플랜트의 차이 발견

지금 나의 시스템은 아래와 같이 플랜트가 제어량 $\delta$ 를 입력 받아서 전달함수를 거쳐 속도와 각속도를 출력하게 되어있다.

플랜트를 매트랩 제어기 이후의 Ros2, Gazebo 전 과정이라고 보고 피드백 구조를 만들었다.

image.png

모터 플러그인을 사용했다보니 어쩔 수 없이 ros2와 gazebo에 들어가는 입력이 토픽 인터페이스에 맞춰서 속도, 각속도 또는 바퀴의 각속도의 형태였다.

  이론 플랜트 gazebo 플랜트
입력 $\delta$ $v, w$
출력 $v, w$ $v, w$

플랜트의 입력이 내 이론 시스템과 달랐고 추가적으로 내부 모터 플러그인이 한 번 더 PI 제어를 자체적으로 수행하고 있었기 때문에 반응성이 이론 예상 값과 더 다르다는 생각이 들었다. 그래서 모터 제어 플러그인 내부와 gazebo와 matlab의 연결고리 역할을 해주는 ros2의 코드를 수정해서 실제 플랜트와 최대한 유사하게 바꿔보았다.

Ros2 / 모터 플러그인 코드 수정

우선 매트랩에서 PID를 거쳐 나온 $\delta$ 값을 ros2에서 디커플링후 배터리전압 $V_{in}$ 을 곱해서 모터 플러그인으로 넘겨주는 코드로 수정했다.

image.png

  • Ros2에서 udp 입력을 $\delta_t, \delta_r$ 로 해석해서 $\delta_l = clamp(\delta_t-\delta_r), \ \delta_r = clamp(\delta_t+\delta_r)$ 로 만든뒤 /left_monotor/command/voltage, /right_motor/command/voltage 로 그대로 publish 했다.
  • 모터 플러그인 내부에 command_mode = voltage를 추가해서 PI 제어를 우회하고, 실제 마찰/점성/관성 계산만 처리되게 했다.

    image.png

  • 최종 시스템의 흐름은 아래와 같다.

  • MATLAB/Simulink
    • v_ref, w_ref → 오차 계산 → PID → 조작량 $\delta_t, \delta_r$ 생성
    • $\delta_t, \delta_r$ 를 UDP(3001)로 double 2개 전송
  • ROS2 브릿지
    • 10ms마다 UDP 수신: ($\delta_t, \delta_r$)
    • 디커플링/믹싱: $\delta_L$ = clamp($\delta_t-\delta_r$), $\delta_R$ = clamp($\delta_t+\delta_r$)
    • publish:
      • /left_motor/command/voltage ← $\delta_L$
      • /right_motor/command/voltage ← $\delta_R$
    • 동시에 /robot/odom를 구독해서 (pos, vel, pqr, euler, body_vel) 총 14개 double을 UDP(3002)로 MATLAB에 송신
  • Gazebo 모터 플러그인
    • /left_motor/command/voltage, /right_motor/command/voltage 토픽에서 $\delta$ 수신(정규화)
    • $\delta$ 를 [-1,1]로 clamp 후 $V = \delta * V_{in}$ 으로 실제 전압 생성
    • 내부 PI는 사용하지 않고, 전기/기계 모델로 전류/각속도 계산 → 토크를 링크에 적용
  • Gazebo 상태 → MATLAB
    • Gazebo p3d/odom → ROS2 브릿지 → UDP(3002) 14개 값 전송 → MATLAB이 받아 v_meas, w_meas 등으로 다음 스텝 제어에 사용

코드 수정 후 결과

이론과 같은 $K_p = 6, \ K_i = 15$ 을 적용시켜서 Gazebo 시뮬레이션을 돌려봤다.

image.png

  • 이론과 시뮬레이션이 비슷한 응답을 보이는 것을 확인할 수 있었다.
  • 오히려 시뮬레이션 환경에서 더 높은 오버슈트와 더 빠른 응답을 확인할 수 있었는데
  • 그 이유를 생각해봤다.
    • 시뮬레이션에는 $\delta$ 를 -1에서 1까지 정규화 해두었기 때문에 최대 값이 1이라 모터 전압에 한계가 있지만,
    • 이론 응답에서는 모터가 무한대의 전압을 제공한다고 가정한 상황이기 때문에 일치하지 않았다.
    • 이론 시스템에도 -1부터 1까지 클램프를 줘서 응답이 변하게 수정해보았다.

image.png

image.png

  • 이론 시스템에도 클램프를 건 이후 이론 시스템의 오버슈트가 상승했고, 라이징 타임이 길어졌다.
  • 하지만 여전히 시뮬레이션 응답이 더 빠르게 나타났다.
  • 시뮬레이터 설정 확인 중에 최대 전류 제한이 없다는 것을 발견하였다.
    • $\delta = 1$ 일때, 48/4.18 = 11.5A 까지 전류가 올라가서 초기 토크가 약 $9.2 N \cdot m$로 약 1.44배 더 높게 나올 수 있어 risetime이 빨라질 수 있겠다는 생각이 들었다.

image.png

image.png

  • 성공했다!
  • 0.5 m/s 속도를 주었을 때, 시뮬레이션과 이론의 응답을 동기화 시켰다.
  • 이전에 초기 시뮬레이션에서 응답이 더 빨랐던 것은 전류가 실제 스펙보다 더 높게 흘렀기 때문이었다.
  • 우연일 수 있기 때문에 두세 번 비교 해보았다.

image.png

image.png

  • 임의로 0.7의 입력을 주었을 때도 동일하게 응답하는 것을 확인했다.
  • 이제 목표하는 시스템 요구 사항을 만족하기 위해서 오버슈트를 10% 이하로, $T_s = 1s$ 이하로 튜닝하는 작업이 필요하다.

image.png

  • 0.7의 stepinput

image.png

  • 0.4의 stepinput

  • 앞서 했던 튜닝 방법을 사용하여 $K_p = 3, \ K_i = 1$ 로 선정하였다.
  • 오버슈트가 사라지고 1차 시스템과 비슷한 응답이 나올 수 있었다.

      <0.7 stepinput data>
      === Gazebo Velocity Step Response ===
      RiseTime: 0.4592 s
      SettlingTime: 4.9527 s
      SettlingMin: 0.6341
      SettlingMax: 0.7263
      Overshoot: 4.7906%
      Undershoot: 4.4353%
      Peak: 0.7263
      PeakTime: 2.9900 s
        
      === Ideal Velocity Step Response ===
      RiseTime: 0.4030 s
      SettlingTime: 0.7038 s
      SettlingMin: 0.6297
      SettlingMax: 0.6997
      Overshoot: 0.0005%
      Undershoot: -0.0000%
      Peak: 0.6997
      PeakTime: 4.9765 s
    

결론

프로젝트 성과

이 프로젝트에서는 아마존 페가수스 모바일 로봇을 대상으로 수학적 모델링 → PID 제어 설계 → Gazebo 시뮬레이션 검증까지 완전한 제어 시스템 개발 사이클을 경험할 수 있었다.

주요성과

  • 물리 기반 모델링 :
    • 차체/바퀴의 병진/회전 운동방정식과 DC 모터 전달함수를 유도하고, 시스템 파라미터가 응답에 영향을 미치는 영향을 정량적으로 분석했다.
  • 제어기 설계 및 검증 :
    • Matlab Root locus 방법으로 PI 제어기 파라미터 설계
    • Simulink 시뮬레이션 결과와 Gazebo 물리 엔진 결과를 정량적으로 일치 (오차 5% 이내%)
  • 시뮬레이션 환경 구축 :
    • SDF 포맷으로 로봇 모델 제작
    • Ros2 - Gazebo - Matlab UDP 통신 파이프라인 구축
    • 실시간 제어 루프 구현 (100hz)

주요 공학적 배움 돌아보기

  • 문제 : 처음 설계한 PID 게인 $K_p=6,\ K_i=15$ 를 Gazebo에 적용했을 때 예상보다 응답이 느렸다.
  • 원인 분석 :
    • 모터 플러그인 내부에 자체적인 PI 제어기가 포함되어 있어서 2중 제어가 적용되고 있었다.
    • 플랜트에 들어가는 입력이 속도로 변환된 입력값이었다.
  • 해결 :
    • command_mode = voltage를 추가해서 커스텀 모드에서는 PI 제어를 우회
    • 이론 플랜트와 Gazebo 플랜트의 입력을 맞추기 위해 PID 출력 값인 $\delta_t, \delta_r$ 을 Gazebo에 그대로 Publish
  • 배운점 :
    • 마찰이나 다른 설정값이 문제라서 응답이 느린 줄 알고 가장 많은 시간을 낭비했다.
    • 제어를 용이하게 해주는 플러그인이지만, 사용할 때 내부적으로 구동 되는 원리를 먼저 파악하고 사용해야함을 느꼈다.
  • 병진 속도 응답에 회전 입력이 전혀 영향을 주지 않았다.
  • 원인 분석 :
    • $V_R + V_L = V_{in}(\delta_t + \delta_r) + V_{in}(\delta_t - \delta_r) = 2V_{in}\delta_t$
    • 회전 성분이 합에서 자동으로 소거
  • 물리적 의미 :
    • 양쪽을 다르게 밀더라도, 로봇은 돌지만 전진력의 총합은 변하지 않는다.
    • 이 직교성 덕분에 병진과 회전의 독립적인 PID 제어가 가능했다.
  • P3D 플러그인에 가우시안 노이즈를 줬더니 정지상태인데도 속도가 튀었다.
  • 원인 분석 :
    • $v = \frac{x_k - x_{k-1}}{\Delta t} = \frac{(x + n_k) - (x + n_{k-1})}{\Delta t} = \frac{n_k - n_{k-1}}{\Delta t}$
    • 위치 노이즈 n이 작아도, 분모 $\Delta t$ 가 작은 값이면 노이즈가 증폭 된다.
  • 해결 :
    • 위치 미분 대신 휠 오도메트리로 속도를 직접 측정
    • 칼만 필터 적용
  • 배운점 :
    • 센서 융합의 중요성
    • GPS 같은 위치 센서는 속도 추정에 부적합하고, IMU나 엔코더로 직접 측정 센서를 써야한다는 것을 배웠다.
  • 이론을 통해 PID 설계한 게인이 시뮬레이션에는 정확하게 맞지 않는다.
  • 원인 분석 :
    • 이론에는 마찰이나 점성이 반영되지 않았기 때문에 응답이 달랐다.
    • 통신 지연은 확인하지 못했지만 가능성이 있을 것 같다.
  • 배운점 :
    • Trial & Error 방법이 가장 쉽고 정확한 길이라는 걸 느꼈다. 실제 응답을 관찰하면서 미세 조정하는 감각이 조금 생긴 것 같다.
  • 문제 : 이론 응답이 시뮬레이션 응답에 비해 반응성이 빨랐다.
  • 원인 분석 :
    • 이론 시스템에는 무한대의 전압이 가능하게 설정되어 있었다.
  • 해결 :
    • 이론 시스템에도 오차를 클램핑 해서 실제 로봇 환경과 동일하게 맞춰주었다.
  • 배운점 :
    • 이론 시스템을 너무 이상적으로 만들어두면 지금 이론 시스템이 맞게 설계 되어있는지, 시뮬레이션 환경이 제대로 구성되어 있는 것인지 비교 할 수 없다는 것을 깨달았다.

아쉬운 점

  • 한 가지 아쉬운 점이라면, 센서의 노이즈 설정을 빼고도 Gazebo에서 넘어오는 정보가 자글자글하게 튀는 형태를 가지고 있었는데 원인을 찾을 수 없었다.
  • 마찰 때문인지, 아니면 물리 엔진 자체의 수치해석상의 한계인지 알 수 없었다.
  • 어쩌면 센서 데이터는 항상 저런식으로 자글자글하게 들어오는 것인데 내가 경험이 부족해서 당연하게 못 느끼는 걸 수도 있겠다는 생각을 했다.

향후 발전 방향

  • 센서 융합 : 현재는 물리 엔진이 제공하는 속도 정보만 피드백에 사용했지만, IMU 센서와 휠오도메트리를 추가하여 칼만 필터를 적용해 위치 추정의 정확도를 높여보고 싶다.
  • 실제 구현 : 시뮬레이션에서 검증된 알고리즘을 임베디드 보드에 탑재해서 실 주행에서는 또 어떤 결과가 나오는지 테스트 하고 싶다.

프로젝트를 마치며

“이론은 맞는데 왜 안 되지? → 아 시뮬레이터에 숨은 로직이 있었구나” 처럼 이론과 실제 적용 사이의 간과할 수 있는 내용들을 찾아가면서 배우는 것이 수업에서 A+ 를 받는 것보다 값지다는 것을 배웠다.

이런 깨달음의 순간들이 모여서 엔지니어의 직관이 된다고 생각했다.

이 기본 경험을 바탕으로 앞으로 더 복잡하고 정교한 로봇 시스템을 제어하는 엔지니어가 될 수 있었으면 좋겠다.

Updated: