Phase 2에서는 원격 속도 명령을 모터에 바로 전달하지 않고, safety_watchdog을 반드시 통과시키는 안전 수동 제어 경로를 만들었다. 이 문서를 공부한 뒤에는 다음 질문에 자신의 말로 답할 수 있어야 한다.
- ROS 2의
Twist명령이 TurtleBot을 어떻게 움직이는가? - Watchdog, 속도 제한, 비상 정지는 각각 어떤 위험을 줄이는가?
- 비상 정지를 해제한 직후 중립 명령을 요구하는 이유는 무엇인가?
- 자동 테스트와 실제 로봇 테스트는 왜 둘 다 필요한가?
키보드·웹·운영자 명령
│ /safety/cmd_vel_in
▼
safety_watchdog
├─ 유효 숫자 검사
├─ 속도 상한 적용
├─ 0.5초 명령 timeout
├─ emergency stop
└─ 해제 후 neutral re-arm
│ /cmd_vel
▼
turtlebot3_node → OpenCR → 모터
핵심 원칙은 외부 조작기가 /cmd_vel을 직접 발행하지 않는 것이다. 모든 정상 제어 입력은 /safety/cmd_vel_in으로 보내고, watchdog만 /cmd_vel의 정상 발행자가 된다.
| 검증 항목 | 결과 |
|---|---|
| WSL 최종 자동 테스트 | 18개 통과, 실패 0개 |
| TB1 실차 배포 시점 자동 테스트 | 13개 통과, 실패 0개 |
| 안전 출력 주기 | 약 19.997 Hz |
| 명령 timeout 설정 | 0.5초 |
| 직선 속도 상한 | 0.05 m/s |
| 회전 속도 상한 | 0.3 rad/s |
| 과속 입력 | 1.0 m/s, 2.0 rad/s |
| 제한된 출력 | 0.05 m/s, 0.3 rad/s |
| 단발 직진 실험 | 약 1.415 cm 이동 후 정지 |
| 단발 회전 실험 | 약 4.99도 회전 후 정지 |
| 텔레옵 종료 후 | 입력 발행자 0개, /cmd_vel은 0 |
TB1 실차 검증 후 최종 PR 리뷰에서 비정상 수치의 중립 판정 회귀 테스트 5개가 추가되어 최종 브랜치는 WSL에서 18개가 통과했다. TB1의 13개 결과는 실차 배포 당시 revision의 실제 기록이며, 숫자를 억지로 같게 쓰지 않는다.
timeout_sec=0.5는 설정값이다. 이번 실험에서는 정지 출력과 이동량을 확인했지만, 정지 지연이 정확히 500 ms인지 별도 계측하지는 않았다. 면접에서도 설정값과 실측값을 구분해서 말해야 한다.
geometry_msgs/msg/Twist는 선속도와 각속도를 표현한다. TurtleBot3 Burger의 평면 이동에서 주로 사용하는 값은 다음 두 개다.
linear.x: 전진·후진 속도, 단위 m/sangular.z: 좌회전·우회전 각속도, 단위 rad/s
나머지 축을 0으로 고정한 이유는 차동 구동 로봇이 옆으로 이동하거나 위아래로 움직일 수 없기 때문이다.
/safety/cmd_vel_in은 아직 검증되지 않은 요청이고 /cmd_vel은 모터에 전달될 최종 명령이다. 이름만 나눈 것이 아니라 책임 경계를 만든 것이다.
운영 규칙은 다음과 같다.
- 조작기는
/safety/cmd_vel_in만 발행한다. - watchdog은 정책을 적용한 뒤
/cmd_vel을 발행한다. turtlebot3_node는/cmd_vel을 구독한다.- 정상 운용에서는 watchdog 이외의
/cmd_vel발행자가 없어야 한다.
다만 ROS 2 자체가 악의적이거나 잘못 설정된 노드의 /cmd_vel 직접 발행을 막는 것은 아니다. 이후에는 접근 제어, 네임스페이스, 배포 규칙과 모니터링으로 보강해야 한다.
속도 명령은 한 번 보내면 영구히 유효한 값이 아니라 짧은 임대권으로 취급한다. 정해진 시간 안에 새 명령이 오지 않으면 watchdog이 0을 출력한다.
이 방식은 조작기 종료, 프로세스 오류, 일시적인 통신 단절처럼 명령 갱신이 끊기는 상황에서 마지막 속도가 계속 유지되는 위험을 줄인다.
watchdog은 입력을 다음 범위로 제한한다.
linear.x: ±0.05 m/sangular.z: ±0.3 rad/s
상한을 넘은 유한한 값은 clamp하고, NaN이나 무한대는 안전한 0으로 바꾼다. 단,
e-stop 재무장에서는 정규화된 0을 사용하지 않고 원시 입력이 유한한지 먼저 검사한다.
그렇지 않으면 NaN이 중립 명령으로 오인될 수 있다. 속도 제한은 조작 실수를 줄이지만
장애물 회피나 충돌 방지를 대신하지는 않는다.
- Topic: 계속 변하는 속도 명령처럼 연속 데이터에 적합하다.
- Service: 비상 정지 활성화·해제처럼 요청과 응답이 필요한 상태 변경에 적합하다.
따라서 속도는 topic으로 받고, e-stop 상태 변경은 std_srvs/srv/SetBool service로 구현했다. Service 성공 응답은 watchdog 내부 상태가 바뀌었다는 뜻이지, 물리 브레이크가 작동했다는 뜻은 아니다.
e-stop이 활성화되면 입력 명령과 관계없이 0을 출력한다. 현재 구현은 소프트웨어 비상 정지이므로 전원 차단형 물리 e-stop과 동일하지 않다.
비상 정지 중에도 조작기가 전진 명령을 계속 보내고 있을 수 있다. 단순히 e-stop 플래그만 해제하면 로봇이 즉시 다시 출발할 수 있다.
이를 막기 위해 해제 후 WAITING_NEUTRAL 상태로 전환한다. 0에 가까운 중립 명령을 새로 받은 뒤에만 다시 움직임을 허용한다.
중요한 구분은 다음과 같다.
- 장애 상태 해제: 이제 정지 원인이 제거되었다.
- 이동 권한 회복: 운영자가 중립을 거쳐 다시 제어하겠다는 의도를 보였다.
두 사건을 분리한 것이 이번 Phase의 핵심 설계 결정이다.
TIMEOUT ──새 명령──> ACTIVE
ACTIVE ──명령 끊김──> TIMEOUT
ACTIVE/TIMEOUT ──e-stop──> ESTOP
ESTOP ──e-stop 해제──> WAITING_NEUTRAL
WAITING_NEUTRAL ──중립 입력──> ACTIVE
모든 비정상 상태의 출력은 0이다. 상태 머신으로 표현하면 조건문만 나열하는 것보다 허용되는 전이를 명확히 검토할 수 있다.
속도 상한, timeout, 출력 주기를 코드에 고정하지 않고 robot/safety_watchdog/config/tb1.yaml에 둔다. 같은 코드로 로봇별 정책을 변경하고, 변경 내용을 Git diff와 코드 리뷰로 추적할 수 있다.
이번 Phase는 세 층으로 검증했다.
- 순수 정책 테스트: clamp, timeout, e-stop, neutral 상태 전이를 빠르게 검증
- ROS 노드 테스트: topic과 service 연결 및 실제 메시지 동작 검증
- TB1 하드웨어 테스트: 바퀴, odometry, 키보드 조작과 정지 확인
자동 테스트만 통과해도 배선·OpenCR·모터 동작은 보장되지 않는다. 반대로 한 번 잘 움직였다는 관찰만으로 경계 조건의 재현성을 보장할 수 없다.
테스트에서는 운용 중인 domain 42와 분리된 domain 142를 사용했다. 같은 네트워크의 실제 노드와 테스트 노드가 서로 발견되어 의도치 않은 모터 명령을 주고받는 일을 막기 위해서다.
최종 텔레옵 검증에서는 다음 세 가지를 함께 확인했다.
/safety/cmd_vel_in의 publisher count가 0- teleop 및 임시
ros2 topic pub프로세스가 없음 /cmd_vel출력이 0
노드 이름만 보거나 터미널이 닫힌 것만으로는 잔여 발행자를 확실히 배제하기 어렵다.
odometry는 바퀴 회전량을 적분한 추정치다. 바퀴를 공중에서 돌리거나 미끄러지면 실제 위치와 달라진다. 이번 실험에서는 누적 절대 좌표가 아니라 명령 전후의 변화량만 사용했다.
| 구성 | 책임 |
|---|---|
policy.py |
제한, timeout, e-stop, neutral re-arm 상태 결정 |
watchdog_node.py |
ROS topic, timer, service와 정책 연결 |
tb1.yaml |
TB1 안전 파라미터 |
test_policy.py |
정책의 경계 조건 자동 검증 |
test_watchdog_node.py |
ROS 노드 인터페이스 검증 |
정책을 ROS 통신 코드에서 분리했기 때문에 시간과 입력을 직접 주입하여 빠르고 결정적인 단위 테스트를 작성할 수 있다.
| 부족한 설명 | 바른 설명 |
|---|---|
/cmd_vel topic이 있으니 안전하다. |
topic 존재뿐 아니라 발행자·구독자 연결, 출력 값, watchdog 우회 발행자 유무를 확인해야 한다. |
| service가 success를 반환했으니 로봇이 물리적으로 멈췄다. | success는 소프트웨어 상태 변경 결과다. 실제 출력 0과 바퀴 정지를 별도로 확인했다. |
| timeout이 정확히 500 ms였다. | 설정은 0.5초이며 이번에는 정지 여부를 확인했다. 정확한 지연은 계측 과제로 남겼다. |
| odom의 1.49 m가 실제 이동 거리다. | 이전 공중 회전이 누적된 값이므로 단발 실험의 전후 차이 약 1.415 cm만 사용했다. |
| publisher 종료 테스트가 Wi-Fi 끊김 테스트와 같다. | 명령 중단 경로는 검증했지만 실제 네트워크 단절과 DDS 탐지 지연은 별도 테스트가 필요하다. |
“원격 조작 명령을 TurtleBot의 /cmd_vel에 직접 연결하지 않고 safety watchdog을 중간에 두었습니다. watchdog은 속도를 0.05 m/s와 0.3 rad/s로 제한하고, 0.5초 동안 명령이 없으면 0을 출력합니다. 비상 정지 해제 뒤에는 유효한 중립 명령을 받아야 재출발하도록 상태 머신을 구성했습니다. 최종 18개 자동 테스트와 TB1 직진·회전·e-stop·키보드 조작으로 검증했습니다.”
“웹이나 키보드 조작기가 죽었을 때 마지막 속도가 계속 남는 위험을 줄이기 위해 입력 topic과 모터 topic을 분리했습니다. 모든 조작 명령은 /safety/cmd_vel_in으로 들어오고 watchdog만 최종 /cmd_vel을 발행합니다. watchdog은 유효 숫자 검사, 속도 clamp, 0.5초 dead-man timeout, software e-stop을 적용합니다. 특히 e-stop을 해제했는데 조작기가 비영점 명령을 계속 보내면 자동 재출발할 수 있어서, 해제 후 WAITING_NEUTRAL 상태를 추가했습니다. 최종 리뷰에서는 NaN이 0으로 정규화되어 중립으로 오인되는 문제도 찾아 원시 입력 검증과 회귀 테스트를 추가했습니다. 최종 18개 자동 테스트와 실제 TB1 과속 제한, 입력 종료 정지, e-stop, 직선·회전 이동을 확인했습니다. 다만 정확한 stop latency와 실제 Wi-Fi 단절, watchdog 프로세스 장애는 후속 검증 항목입니다.”
- 위험: 원격 조작기 장애 때 마지막 속도 유지, 과속 입력, e-stop 해제 후 자동 재출발
- 구조: 안전 입력과 모터 출력을 분리하고 watchdog을 단일 정상 게이트로 배치
- 정책: 유효성 검사, clamp, timeout, e-stop, neutral re-arm
- 구현: 정책과 ROS 노드를 분리하고 YAML로 로봇별 설정
- 검증: 최종 단위·노드 테스트 18개, graph endpoint, 실제 바퀴·odom·키보드 검증
- 결과: 과속 제한, 명령 종료 후 0, e-stop 중 0, 중립 전 재출발 차단
- 한계: 물리 e-stop 아님, 우회 publisher 방지 미완료, stop latency·실제 네트워크 장애 미계측
- 다음 개선: source arbitration, heartbeat, lifecycle/systemd, 상태 telemetry와 장애 주입 테스트
안전 정책을 모든 조작 방식에 일관되게 적용하기 위해서입니다. 입력 경로가 키보드에서 웹으로 바뀌어도 최종 모터 명령 전에 제한, timeout, e-stop을 한 곳에서 적용할 수 있습니다.
watchdog 발행은 중단되지만 하위 OpenCR의 timeout 동작은 이번 Phase에서 직접 검증하지 않았습니다. 운영 환경에서는 프로세스 supervisor, heartbeat, 하위 제어기의 독립 timeout과 물리 e-stop을 함께 사용해야 합니다.
해제 시점에도 기존 조작기가 비영점 명령을 계속 발행할 수 있기 때문입니다. 장애 해제와 이동 권한 회복을 분리해 의도하지 않은 자동 재출발을 막았습니다.
유한한 입력에 대해서는 방향을 유지하며 안전 상한 안에서 예측 가능한 조작을 제공하기 위해서입니다. NaN과 무한대처럼 의미 없는 값은 0으로 처리합니다. 정책에 따라 전체 거부를 선택할 수도 있습니다.
시스템 시각 변경의 영향을 받지 않는 monotonic clock이 적합합니다. wall clock은 NTP 보정이나 수동 변경으로 점프할 수 있습니다.
자동 테스트는 경계 조건의 반복성과 회귀 방지에 강하지만 USB, OpenCR, 모터, 바닥 마찰은 확인하지 못합니다. 그래서 실제 로봇에서 명령부터 물리 이동과 정지까지 확인했습니다.
바퀴 encoder 기반 추정치이므로 실제 위치의 절대 기준으로 보지 않았습니다. 누적값 대신 같은 조건에서 명령 전후 delta와 실제 관찰을 함께 사용했습니다.
속도는 높은 빈도로 갱신되는 최신값 중심의 스트림입니다. Action은 장시간 목표의 진행률과 취소가 필요할 때 적합합니다.
명시적인 상태 변경 요청과 성공·실패 응답이 필요했기 때문입니다. 다만 service 응답과 실제 정지는 구분하여 출력과 하드웨어를 추가 검증했습니다.
현재는 우선순위 중재가 없다. 다음 단계에서는 twist_mux 같은 arbitration 계층을 두고 e-stop, 운영자, 자율주행의 우선순위와 lock 정책을 정의해야 합니다.
관찰용 subscriber가 모든 샘플을 처리하지 못했거나 QoS·스케줄링 조건에서 일부를 놓쳤다는 뜻입니다. 안전 판단은 단일 echo가 아니라 endpoint, 연속 출력, 상태와 하드웨어 결과를 함께 봐야 합니다.
실제 로봇 domain 42와 discovery를 분리해 테스트 메시지가 모터 경로에 섞이는 것을 막기 위해서입니다. 과도하게 큰 domain ID는 DDS 기본 포트 계산 범위를 벗어날 수 있어 142를 선택했습니다.
linear.x와angular.z의 단위는 무엇인가?- watchdog timeout은 어떤 위험을 줄이는가?
- e-stop 해제 직후 비영점 명령을 허용하면 어떤 문제가 생기는가?
- Topic과 Service를 이번 구현에서 각각 어디에 사용했는가?
/cmd_vel의 정상 publisher와 subscriber는 누구인가?- odometry 절대값을 실제 이동 거리로 사용하지 않은 이유는 무엇인가?
- 자동 테스트와 하드웨어 테스트가 각각 찾기 좋은 문제는 무엇인가?
- 이번 Phase에서 아직 검증하지 않은 안전 항목 두 가지를 말하라.
linear.x는 m/s,angular.z는 rad/s다.- 명령 갱신이 끊겼을 때 마지막 비영점 속도가 계속 유지되는 위험을 줄인다.
- 조작기가 명령을 계속 보내는 중이면 해제와 동시에 의도치 않게 재출발할 수 있다.
- 연속 속도 명령은 Topic, e-stop 상태 변경은 Service를 사용했다.
- 정상 publisher는
safety_watchdog, subscriber는turtlebot3_node다. - 공중 회전과 미끄러짐도 누적되는 encoder 기반 추정치이기 때문이다.
- 자동 테스트는 상태 전이와 경계값 회귀, 하드웨어 테스트는 배선·OpenCR·모터·물리 움직임 문제에 강하다.
- 예: 정확한 stop latency, 실제 Wi-Fi 단절, watchdog 강제 종료, OpenCR 독립 timeout, 물리 e-stop.
- 안전 명령 경로를 그림 없이 설명할 수 있다.
- timeout, clamp, e-stop의 역할 차이를 설명할 수 있다.
-
WAITING_NEUTRAL이 해결하는 위험을 예로 들 수 있다. - 최종 WSL 테스트 18개와 TB1 배포 시점 테스트 13개를 구분해 말할 수 있다.
- odometry의 한계와 이번 delta 측정 방식을 설명할 수 있다.
- 구현한 것과 아직 구현하지 않은 것을 과장 없이 말할 수 있다.
- DDS discovery와 QoS의 reliability/history/depth
- ROS 2 executor, callback scheduling, timer jitter
twist_mux기반 다중 명령원 우선순위- lifecycle node와 systemd 재시작 정책
- 하드웨어 e-stop 및 독립 안전 제어기
- 네트워크 장애 주입과 stop latency 계측
- 보안 enclave와 topic 접근 제어