ROS 2 통합
PLEM 로봇은 표준 ROS 2 인터페이스(토픽·서비스·액션)로 제어하고 관측하실 수 있습니다. 이 페이지는 외부 ROS 2 환경을 PLEM 기기에 연결하는 절차와 인터페이스 카탈로그, 클라이언트가 지켜야 할 규약을 다룹니다.
전제
| 기기 Ubuntu | ROS 2 배포판 |
|---|---|
| 22.04 (jammy) | Humble |
| 24.04 (noble) | Jazzy |
로봇 기기의 OS 에 대응하는 같은 ROS 2 배포판의 클라이언트가 지원 구성입니다.
모든 클라이언트는 로봇과 같은 ROS_DOMAIN_ID 와 같은 RMW 를 써야 합니다. 도메인은 기기의 plem Settings 가 소유하되 셸 ROS_DOMAIN_ID 가 있으면 그것이 우선합니다. RMW 는 스택이 강제하지 않으므로, 짐작하지 마시고 아래 plem env 로 로봇 프로세스의 실제 값을 확인하세요.
로봇 기기 안에서 접속하기 (SSH 포함)
가장 간단한 통합 지점은 로봇 기기 자체입니다. 대화형 셸은 PLEM 환경(/opt/plem — rclpy + plem_msgs)이 자동으로 잡혀 있고, 비대화형 SSH 나 CI 는 bash -lc '...' 또는 source /opt/plem/setup.bash 가 필요합니다.
기기의 DDS 는 기본적으로 루프백(lo) 전용입니다. 같은 기기 안의 대용량 전송(카메라 프레임)을 안정화하기 위한 설정입니다(QA 실측: 카메라 RGB 10.9 → 30.0 Hz). 같은 기기라도 로봇 스택과 다른 DDS 환경으로 뜬 셸은 토픽이 안 보일 수 있으므로, 아래 중 하나로 로봇 프로세스의 DDS 환경을 그대로 가져오세요.
# 1회성 조회·호출 — 실행 중 로봇 프로세스의 DDS 환경을 복사해 ros2 를 실행
plem ros2 topic list
plem ros2 action list
# 현재 셸에 영구 적용 (eval 없이 실행하면 무효)
eval "$(plem env)"
다른 호스트에서 접속하기
lo 전용 기본값 때문에 다른 PC 의 ROS 2 클라이언트는 이 기기의 토픽을 에러 없이 못 봅니다. 빈 목록이 나올 뿐 에러가 없으므로, 원격 접속 실패의 1차 확인 대상입니다. 이 프로파일(~/.ros/cyclonedds.xml, 설치와 업데이트가 배치하며 기존 파일은 보존)은 <Domain Id="any"> 로 적용되므로 도메인 번호를 바꾸셔도 lo 전용은 그대로입니다.
크로스-호스트 접속이 필요하면 로봇과 클라이언트 양쪽이 공용 NIC 를 쓰는 CycloneDDS 프로파일을 사용하세요.
- 기기의
~/.ros/cyclonedds.xml에서<NetworkInterface name="lo" ...>의name을 실제 NIC 이름(예:eth0)으로 바꾼 프로파일을 준비하세요. 클라이언트 쪽도 같은 방식으로 맞추세요. - 파일을 직접 교체하는 대신 프로세스 단위로 지정하실 수도 있습니다:
CYCLONEDDS_URI=file:///path/to/profile.xml. 셸에 영구export하는 것은 권장하지 않습니다. 이후 same-host 도구의 기본 프로파일까지 덮습니다. - 프로파일의
<SocketReceiveBufferSize min="10MB"/>때문에 클라이언트 커널 수신 버퍼가 작으면 노드 생성이 실패할 수 있습니다.sysctl -w net.core.rmem_max=10485760(영구 적용은/etc/sysctl.d/) 로 맞추세요.
lo 전용 해제는 same-host 성능 이점과 네트워크 노출을 맞바꾸는 결정입니다. 필요한 기간과 네트워크에서만 적용하시기를 권장합니다.
plem_msgs 설치
PLEM 커스텀 인터페이스를 쓰시려면 클라이언트 환경에 plem_msgs 패키지가 필요합니다. 로봇 기기에는 이미 설치돼 있습니다. 별도 PC 에는 WIM 패키지 저장소(기기 온보딩 시 등록하는 것과 동일)를 등록하신 뒤 설치하세요.
sudo apt install plem-msgs # /opt/plem 에 설치 — source /opt/plem/setup.bash 로 오버레이
패키지 이름은 plem-msgs 입니다 (ros-humble-plem-msgs 형태가 아닙니다). 표준 인터페이스만으로는 관절 상태 조회와 그리퍼 사용까지 가능합니다. 다만 팔 구동은 모드 진입(아래 규약)이 필요하고 그 인터페이스가 plem_msgs 이므로, 모션 통합에는 설치가 사실상 필수입니다.
인터페이스 카탈로그
로봇 1대당 자기 네임스페이스 /{robot_id}/ 아래로 노출됩니다. robot_id 는 plem 에서 선택하신 로봇 프로필 이름입니다. PLEM 커스텀 인터페이스는 /{robot_id}/plem/ 아래, ros2_control 표준 인터페이스는 /{robot_id}/ 직하에 있습니다.
제어
이름 (/{robot_id}/ 생략) | 타입 | 용도 |
|---|---|---|
plem/set_mode | plem_msgs/action/SetMode | 로봇 모드 전환 (모션 전 필수 — 아래 규약) |
plem/control_command | plem_msgs/srv/SetControlCommand | 복구 프리미티브 — reset_error · protective_stop(브레이크 체결 = BRAKED 전환) · release_brake · free_drive. 뒤의 셋은 하위 모드·브레이크만 전환합니다(컨트롤러 전환·점유 검사 없음) — 정지·안전 참조 |
plem/plan_trajectory | plem_msgs/action/PlanTrajectory | 궤적 계획 — 기본(DETERMINISTIC)은 예측 가능한 산업 모션. 충돌 회피는 motion_intent=COLLISION_AWARE 로 요청하며 지원 모델에서 자기 충돌과 정적 장면까지 회피합니다. 실제 환경(놓인 물체) 회피에는 지각 스택이 더 필요합니다. ROS 2 Humble(JetPack 6) 트레인 한정: Jazzy(JetPack 7) 기기에는 cuMotion 이 아직 프로비저닝되지 않았습니다 — 지원 모델에서 스택을 이 옵션과 함께 기동하면 cuMotion 플러그인을 찾지 못해 기동이 실패합니다(사전 경고 없음) |
joint_trajectory_controller/follow_joint_trajectory | control_msgs/action/FollowJointTrajectory | 궤적 실행 (표준) — 완료·안전 규약은 아래 참조 |
gripper_action_server/gripper_command | control_msgs/action/GripperCommand | 그리퍼 (전 벤더 공통 이름 — 표준) |
상태·관측
이름 (/{robot_id}/ 생략) | 타입 | 비고 |
|---|---|---|
joint_states | sensor_msgs/msg/JointState | 100 Hz |
joint_states_throttled | sensor_msgs/msg/JointState | 30 Hz 스로틀 — 기기에 topic_tools 가 설치된 경우에만 뜹니다(없으면 joint_states 를 직접 구독) |
joint_trajectory_controller/state | control_msgs/msg/JointTrajectoryControllerState | 궤적 추적 상태 (desired/actual/error) — 실행 중 모니터링 |
status_broadcaster/robot_mode | plem_msgs/msg/RobotMode | 로봇 모드 (50 Hz) |
status_broadcaster/safety_mode | plem_msgs/msg/SafetyMode | 안전 상태 (50 Hz) |
gripper_status | plem_msgs/msg/GripperStatus | 그리퍼 상태 |
rt_events | plem_msgs/msg/RtEvent | RT 이산 이벤트 (fault·상태 전이 — 정지 원인 판독) |
rt_diagnostics | plem_msgs/msg/RtDiagnostics | 제어 사이클 진단, ~1 Hz 창 집계 |
rt_raw | plem_msgs/msg/RtRawBatch | 사이클 전수 원시 데이터 (BestEffort 배치) — 분석용 |
모드 상수
RobotMode: BRAKED=0 STOPPING=1 TRAJECTORY=2 FREEDRIVE=3 ERROR=-1
SafetyMode: NORMAL=0 PROTECTIVE_STOP=1
구독 클라이언트는 다섯 값 모두를 처리해야 합니다.
클라이언트 규약
표준 ROS 2 관례 위에서 PLEM 이 요구하는 규약입니다.
모드 먼저
궤적 실행은 로봇이 TRAJECTORY 모드일 때만 수락됩니다. 그 외 모드에서 보낸 FollowJointTrajectory goal 은 거부됩니다(accepted == False, 조용한 무시가 아니라 명시적 거부).
궤적 컨트롤러는 비활성 상태로 로드되고 모드 진입이 활성화하므로, ros2 action list 에 실행 액션이 보인다고 goal 이 수락되는 것은 아닙니다. TRAJECTORY 진입은 plem/set_mode(TRAJECTORY) 로 하세요. plem/control_command 의 release_brake 는 같은 모드 전환을 일으키지만 궤적 컨트롤러를 활성화하지 않아 실행 준비가 끝나지 않습니다.
권장 시퀀스는 plem/set_mode(TRAJECTORY) → plem/plan_trajectory → 결과의 trajectory 를 follow_joint_trajectory 로 실행입니다.
직접 작성한 궤적은 충돌 검사를 거치지 않는다
plem/plan_trajectory 를 거치지 않고 직접 작성해 follow_joint_trajectory 로 보낸 궤적은 어떤 충돌·경로 검사도 거치지 않습니다. 사람이 작업영역 밖에 있고 비상정지에 도달 가능한 상태에서, 검증된 동작에만 사용하세요.
실행 성공은 목표 도달이 아니다
FollowJointTrajectory 의 SUCCEEDED 는 목표 도달을 보장하지 않습니다. 도달 tolerance 가 설정돼 있지 않아 time_from_start 경과 시점에 성공으로 보고합니다. 종료 후 joint_states 로 최종 위치를 독립 검증하세요. 서보 한계를 넘는 궤적(과도하게 짧은 time_from_start)은 보내지 마세요.
마지막 포인트의 velocity 가 0 이 아니어도 goal 은 수락됩니다(allow_nonzero_velocity_at_trajectory_end: true). 안전을 위해 마지막 포인트의 velocity 는 0 으로 두는 것을 권장합니다.
정지·복구
제어된 정지는 실행 goal 의 cancel, 즉시 정지는 plem/control_command 의 protective_stop(브레이크 체결) 또는 plem/set_mode(BRAKED) 입니다. P-STOP 과 ERROR 상태는 자동 복구되지 않습니다. safety_mode 와 robot_mode 를 감시하시고, 복구는 reset_error(P-STOP/ERROR 전용) 후 모드 재진입으로 하세요.
joint 순서
joint_states 의 name 배열 순서는 보장되지 않습니다 (실측 예: joint0,1,2,5,3,4). 인덱스 순서를 하드코딩하지 마시고 항상 name 으로 매핑하세요. 명령(joints_rad, JointTrajectory.joint_names)도 같은 원칙입니다.
단위
각도는 radian, 거리는 meter, 회전 표현은 쿼터니언입니다 (SI 일관). 모션 목표 필드명이 단위를 드러냅니다: MotionTarget.joints_rad. degree 값은 rad = deg × π / 180 으로 변환해 보내세요.
스키마 확인
필드 구조는 문서로 옮겨 적지 않습니다. 인터페이스 정의의 단일 진실은 plem_msgs 패키지이며, 환경에서 직접 조회하세요.
ros2 interface show plem_msgs/action/SetMode
ros2 interface show plem_msgs/action/PlanTrajectory # Goal = MotionTarget target + WorkspaceBox workspace
ros2 interface show plem_msgs/msg/MotionTarget # 모션 목표 필드 전체 (move_type·speed_scale 등)
ros2 interface show plem_msgs/srv/SetControlCommand
인터페이스 가용 시점
로봇 스택 기동 시 로봇별 1초 간격으로 ros2_control 과 그리퍼 드라이버가 병렬로 뜨고, PLEM 상태·명령 인터페이스(plem/set_mode·plem/control_command·status_broadcaster·rt_*)는 하드웨어 활성화 때 함께 생성됩니다. plem/plan_trajectory 는 계획 스택(MoveIt)이 수 초 늦게 기동하므로 마지막에 뜹니다. 클라이언트는 wait_for_server 로 대기하세요.
plem/set_mode 전환이 거부되면 두 경우를 구분하세요.
goal 이 아예 수락되지 않으면(accepted == false) 결과 메시지가 없습니다. 이미 그 모드이거나, 안전 상태가 그 전환을 막거나, 다른 모드 goal 이 처리 중인 경우입니다(모드 goal 은 직렬로 보내세요).
수락된 뒤 실패하면 결과의 message 에 사유가 담깁니다. EtherCAT 링크 비정상(로봇 전원·케이블), 다른 제어 주체(teleop)의 점유, 컨트롤러 전환 실패 등이 같은 증상으로 나타나며, robot_mode·safety_mode·rt_events 가 원인을 가릅니다.