Devin.KR

목표 접근과 흔들림 실험

100분 안팎

학습 목표

C HAL의 가상 바퀴를 Python 목표점 제어기로 구동하며 이득·주기를 바꿉니다.

개념

접수된 목표를 움직임으로 연결합니다

앞 모듈의 액션은 목표 id와 취소 수명을 보존했지만 위치를 외부에서 받아 고정 PWM을 내보냈습니다. 이제 MotionActions가 기존 Actions를 상속해 가상 위치를 읽고 매 tick 새 바퀴 명령을 계산합니다. 기존 클래스와 그 테스트는 통신 fixture로 보존합니다. 목표점 루프를 분리해 추가하면 인터페이스 회귀와 새 운동 검사를 동시에 실행할 수 있습니다. 이번 레슨의 완료는 단순 로그 성공이 아니라 HAL 출력에 따른 이동 증거입니다.

거리와 방향 오차는 역할이 다릅니다

distance는 목표와 현재 위치의 평면 거리이며 angle은 atan2로 구한 목표 방향에서 현재 heading을 뺀 뒤 정규화한 값입니다. distance에 비례한 선속도는 접근할수록 줄어듭니다. angle에 비례한 각속도는 바라보는 방향을 수정합니다. 이 두 루프를 목표 속도 PID의 P·I·D 항과 혼동하지 않습니다. 로컬 목표점 제어는 거리와 방향 P이고 일차 속도 PID 비교는 별도 실험 함수입니다.

뒤의 목표에는 회전부터 합니다

목표가 뒤에 있어도 거리는 양수이므로 거리 P만 쓰면 앞으로 움직여 오히려 멀어집니다. abs(angle)이 turn_gate_rad=0.5보다 크면 v=0으로 하고 회전만 허용합니다. 각속도는 ±1.0rad/s 안으로 자릅니다. 경계가 정확히 0.5면 전진을 허용합니다. 이 정책은 실습용 전진 로봇의 선택이며 후진 접근이나 최단시간 주행을 최적화한 계획기는 아닙니다.

세 종류 속도 상한을 조합합니다

선속도는 전역 max_v=0.30m/s, 목표 요청 max_speed_mps, distance_kp·distance 중 가장 작은 값을 택합니다. 목표의 상한이 0이면 이동하지 않지만 액션은 취소나 다른 종료 조건이 올 때까지 실행 상태를 유지합니다. 설정 dt는 양수이고 1초 이하입니다. 입력 제한을 제거하는 위험한 변경 대신 요청 속도 0.1과 0.3의 결과를 비교합니다. 수치가 제한을 만족하는지부터 시험해야 실험 결과를 해석할 수 있습니다.

몸체 명령을 실제 HAL 값으로 전달합니다

wheel_pwm에서 역기구학으로 바퀴 rad/s를 계산한 다음 이상 모델의 10rad/s당 PWM 1로 변환합니다. v=0.30,w=1.0이면 좌우 PWM은 0.3과 0.9입니다. C set_wheels의 최종 제한 범위 안에 들어갑니다. 실제 위치는 요청한 v가 아니라 C에 저장된 좌우 PWM을 사용해 계산합니다. 이 연결이 없으면 Python 제어 명령은 맞아도 HAL이 결함으로 멈춘 상황을 위치가 계속 이동한 것으로 기록할 수 있습니다.

C의 한 tick을 확인합니다

motion_step은 기존 HAL step을 호출해 dt와 결함 상태를 검사한 뒤 PWM에서 v·w를 복원하고 원호 식으로 x·y·heading을 갱신합니다. 센서 fixture의 index는 매번 0으로 되돌려 반복합니다. 이 조치는 앞 모듈의 짧은 입력을 운동 실험에 재사용하기 위한 것으로 실제 센서 수집 모델이 아닙니다. 기존 센서 회귀는 원래 step 경로를 그대로 검사합니다. 운동과 센서 반복의 책임을 README에 남깁니다.

도착을 판정한 tick은 정지합니다

매 tick 현재 위치의 거리 피드백을 먼저 기록합니다. distance가 0.10m 이하이면 _finish로 PWM 0을 요청하고 출력이 0인지 확인한 뒤 SUCCEEDED를 남깁니다. 따라서 마지막 피드백은 정지 직전의 현재 위치를 뜻하며 tick 중간의 연속 경로를 보여주지는 않습니다. 이번 모델에는 관성이 없어 정지 후 위치가 유지됩니다. 2초 유지 검사는 가상 모델의 보증 범위를 확인하는 것입니다.

취소가 위치 갱신보다 먼저입니다

CANCELING이면 다른 제어 계산보다 먼저 정지하고 CANCELED를 남깁니다. 그 tick에는 위치를 적분하지 않습니다. HAL이 이미 결함이면 ABORTED/HAL_FAULT로 끝납니다. 출력이 0으로 확인되지 않으면 STOP_NOT_CONFIRMED 예외를 유지합니다. 성공 결과를 남기고 나중에 정지하려는 순서는 종료와 구동 상태를 어긋나게 만듭니다. 이번 실습에서는 취소 전후 위치와 PWM을 함께 검사합니다.

실패한 검사를 읽고 고칩니다

starter는 단위 변환과 회전 우선 조건 두 곳이 비어 있습니다. test_inverse_units가 실패하면 몸체 m/s를 PWM으로 바로 반환했는지 확인합니다. test_heading_gate가 실패하면 뒤쪽 목표에도 전진을 허용했는지 봅니다. goal 상태가 EXECUTING으로 남으면 목표를 향한 회전 부호와 도달 반경을 점검합니다. 컴파일 오류는 C 파일명과 gcc 출력의 첫 위치를 읽고, HAL_LIBRARY 오류는 check.sh를 거치지 않고 Python을 직접 실행했는지 확인합니다.

실험표의 관측 범위를 선언합니다

motion_demo.py는 목표 (1,0)에 도착한 시간과 x·PWM을 출력하고 별도의 PID 응답 네 조합 및 적분 제한 전후를 출력합니다. 목표점 흔들림을 추가 분석하려면 motion_config.json의 distance_kp와 dt를 한 번에 하나씩 바꾸고 거리·방향 이력을 남깁니다. PID 표의 큰 주기 진동은 일차 속도 모델에서의 결과입니다. 이를 목표점 위치 진동으로 바꿔 서술하지 않으며 두 실험의 단위와 성공 기준을 각각 적습니다.

회귀 검사는 이전 검사에 직접 연결합니다

check.sh는 check-m05.sh를 호출하고, 그 스크립트는 기존 check_previous.sh와 test_actions를 직접 실행합니다. 이전 검사가 새 check.sh를 다시 부르지 않으므로 재귀가 없습니다. 이후 새 C 라이브러리를 임시 폴더에 만들고 전체 Python 검사를 실행합니다. 임시 폴더는 종료 시 정리되며 서버나 데몬을 띄우지 않습니다. 명령 한 줄만으로 이전 산출물 준비와 새 검사가 완료되어 다운로드한 폴더 외부 파일에 의존하지 않습니다.

미션 제출물을 리뷰합니다

미션 starter는 m05 solution 전체를 이어받은 별도 robotics-m06-motion-control 폴더입니다. 두 TODO를 고친 뒤 전체 검사 로그, 목표 도달과 2초 유지 근거, 2개 이득·2개 주기의 오차·부호 전환·정착 비교, 적분 제한 전후 수치를 제출합니다. 장애물이 없는 시험이므로 충돌 회피를 주장하지 않습니다. 실물에는 모터 응답·추정 오차·통신 지연을 추가 검증해야 하고 경로 계획은 다음 모듈에서 이 제어기를 재사용합니다.

따라하기

회전 우선 판단을 확인합니다

목표가 뒤에 있는 경우 먼저 회전하도록 전진 명령을 0으로 둡니다.

import math
x,y,theta=0.0,0.0,0.0
gx,gy=-1.0,0.0
angle=math.atan2(gy-y,gx-x)-theta
angle=math.atan2(math.sin(angle),math.cos(angle))
v=0.0 if abs(angle)>0.5 else 0.3
w=max(-1.0,min(1.0,2.0*angle))
print(f"v={v:.3f} w={w:.3f}")

실행 결과

v=0.000 w=1.000

바퀴 입력 제한을 검산합니다

최대 몸체 명령을 가상 PWM으로 변환합니다.

v,w,r,L=0.30,1.0,0.05,0.30
left=(v-w*L/2)/r/10
right=(v+w*L/2)/r/10
print(f"pwm={left:.3f} {right:.3f}")

실행 결과

pwm=0.300 0.900

C HAL과 전체 검사를 실행합니다

robotics-m06-goal-control starter.zip을 풀고 이 폴더에서 다음 명령을 실행합니다. TODO 두 곳을 고친 뒤 C 44개, 기존 Python 61개와 액션 20개, 전체 Python 95개가 통과하는지 확인합니다. 마지막 목표 로그에서 SUCCEEDED·3.50초·x=0.904558·PWM 0을 확인합니다. 전체 로그에는 회귀 결과와 실험표가 함께 나오므로 여기에는 복사하지 않습니다.

bash check.sh

확인 문제

실습

motion.py의 wheel_pwm과 회전 우선 TODO를 완성합니다. bash check.sh는 C 빌드부터 이전 회귀와 운동 검사를 한 번에 실행합니다. 직선·제자리 회전·원호·요청 속도 상한·각도 정규화·도달 후 2초 유지·취소·HAL 결함을 검증합니다. 마지막 목표 로그와 PID 비교표를 읽고 두 실험을 구별해 설명합니다. 별도 미션 robotics-m06-motion-control starter는 앞 모듈 solution 전체를 포함하며 같은 명령으로 검사합니다. README의 error·flips·settled·saturation 정의를 사용해 이득 2개×주기 2개 및 적분 제한 전후를 제출합니다.

시작 코드·테스트 내려받기

실행 명령

bash check.sh

기대 결과

C 44개·기존 Python 61개·액션 20개·전체 Python 95개 통과; goal SUCCEEDED time=3.50 x=0.904558 pwm=(0.0, 0.0)

모범 답안모범 답안 내려받기

더 읽기

면접 질문

  • 목표점에 가까워져도 로봇이 흔들리는 상황을 설명해 주시면 됩니다.