드라이브 버스 API
내 서보 드라이브 붙이기 로 띄운 드라이브 버스의 레퍼런스입니다. plem drive check 출력, plem drive run 의 동작, ROS 인터페이스, Python plem.drive, 벤치 세부를 다룹니다. 파일의 키는 드라이브 모델 파일 에 있습니다.
이 페이지의 <ns> 는 plem drive run 의 네임스페이스 /<bus.name> 입니다(파일의 bus: { name: … }). plem drive <동사> 는 plem-drive <동사> 와 같은 도구입니다. 드라이브 패키지만 설치한 기기에서는 plem-drive 로 씁니다.
plem drive check 출력
거부 문장의 형식(키 경로, axes[i] 와 로더의 INFO 대응 줄)은 드라이브 모델 파일 §2 에 있습니다. INFO 대응 줄은 plem drive check 에서는 stderr 로, plem drive run 에서는 기동 로그로 나옵니다.
통과하면 JSON 문서 하나를 찍습니다("format": "plem-drive-check/1").
| 필드 | 뜻 |
|---|---|
bus_name | 파일의 bus.name. 버스는 /<bus_name> 으로 뜹니다. 이 키가 없는 파일은 무엇을 적을지와 함께 거부합니다 |
| digest 두 개 | 파일의 설정과 전이표 digest. bus.name 은 들어가지 않으므로 버스 이름을 바꿔도 승인이 유지됩니다 |
implementation_revision | 이 소프트웨어의 판 |
approval_claimed, approval_effective | 파일이 주장하는 승인 상태와 실제로 성립하는 승인 상태 |
required_bench_items | 이 파일의 축 모드에 필요한 벤치 항목 |
approve_blocker | 벤치가 승인을 기록하지 못할 이유. 없으면 null |
| 축·슬레이브 주소 | 벤치에 쓰는 값 |
reasons | 주장한 승인이 성립하지 않는 이유 |
not_judged | check 가 판정하지 않고 기동 때 판정하는 것 |
warnings | 경고. 거부가 아니고 종료 코드도 바꾸지 않습니다 |
warnings 에 나오는 것:
- 위치·속도 축이 정지 방식을 정하는 객체(0x605A, 0x605C, 0x6084, 0x6085)를
startup_sdo로 쓰지 않음. - DC 슬레이브의
sync0_shift_ns가 0.
axes[i] 에는 plem drive run 이 쓰는 값이 들어 있습니다.
| 필드 | 뜻 |
|---|---|
mode | 축의 운전 모드 |
position_min_rad, position_max_rad | 위치 한계. 끝 멈춤 없는 축은 null |
velocity_limit_rad_s | 속도 한계 |
velocity_cap_rad_s | 플래너가 명령해도 되는 속도. csp 축은 속도 한계에서 주기당 한 위치 카운트(끝 멈춤 없는 축은 두 카운트)를 뺀 값이라, 반올림된 목표도 한 주기 이동량 검사 안에 듭니다. 다른 축은 속도 한계 그대로 |
acceleration_limit_rad_s2 | 정지 감속. cst 축은 null |
torque_min_nm, torque_max_nm | cst 축의 limits.torque_nm. 다른 축은 null |
plem drive run 이 하는 일
plem drive run <파일> [--master N] [--rt-cpu N] [--monitor] [--plot] [--unapproved] [--verbose]
- 이름과 승인 확인. 파일을
check로 봅니다. 버스는/<bus.name>네임스페이스에서 뜹니다. 같은 이름의plem drive run이 이 기기의 내 계정에서 이미 떠 있으면(그 네임스페이스의 컨트롤러 매니저나robot_state_publisher) 그 pid 와 함께 거부합니다. 다른 계정이나 같은 ROS 도메인의 다른 기기에서 뜬 버스는 보지 못합니다. 승인을 주장하지만 더는 성립하지 않는 파일(벤치 뒤 값을 고친 파일 등)도 미승인으로 읽습니다. 미승인 파일이면 터미널에서 벤치를 이어 돌립니다.--unapproved를 주면 묻지 않고 벤치 기동으로 띄웁니다. 이때 「BENCH MODE」 경고가 나오고, 그 런의 근거는 벤치 근거일 뿐입니다. - 실시간 환경 경고. 커널이 PREEMPT_RT 가 아니거나, 격리 CPU 가 없거나, Jetson 의 nvpps PTP-TSC 잠금이 켜져 있으면 고칠 방법과 함께 경고만 합니다. nvpps 잠금은 호스트 클록을 끌고 다녀 드라이브의 DC 편차가 따라옵니다.
- 로봇 설명과 파라미터. 로봇 설명은 축마다 관절 하나를 파일의 축 순서로 둡니다. 관절 이름은 파일의 축 이름이고, 위치 한계는 파일 값, 끝 멈춤 없는 축은
continuous, 속도 한계는velocity_cap_rad_s입니다. 컨트롤러 매니저의 갱신 주기는 버스 주기와 같습니다. - CPU. 버스 루프는 기본으로 마지막 격리 CPU 에 붙고,
--rt-cpu N이면 CPU N 에 붙습니다. 이 프로세스가 돌 수 있는 CPU 여야 하고, 아니면 하드웨어 플러그인이 기동 때 격리 CPU 목록(/sys/devices/system/cpu/isolated)을 알리며 거부합니다. 격리됐는지는 검사하지 않습니다. 매니저의 갱신 스레드는 갈 곳이 있으면 격리 CPU 와--rt-cpu의 CPU 밖에서 돕니다. 버스 루프의 우선순위는 기본값 그대로이고 옵션은 없습니다. - 기동.
robot_state_publisher와 컨트롤러 spawner 를 띄운 뒤 자신이 컨트롤러 매니저가 됩니다(exec). 그래서 Ctrl-C 가 곧바로 닿습니다. 버스는 손을 놓기 전에 모든 축을 세웁니다. 토크 축이 없는 버스는 요청 정지(감속해 세운 뒤 브레이크), 있으면 곧바로 서는 정지입니다. 체결을 확인하지 못하면 ERROR 로그가 남습니다.
터미널 출력. 띄우기 전에 버스 이름, 축 수와 모드, 주기, 마스터, 승인 상태를 몇 줄로 찍습니다. 그 뒤 터미널에는 경고와 오류, 버스 노드 자신의 줄(OP 대기, 벤치 근거), 스포너의 줄(컨트롤러 로드·활성화)만 나옵니다. ROS 노드의 로그 레벨(--log-level warn)과 plem 의 PLEM_LOG_LEVEL 로 거르며, 사용자가 이미 정한 PLEM_LOG_LEVEL 은 그대로 둡니다. 벤치가 띄우는 run 은 늘 --verbose 입니다(그 출력은 진단용 벤치 로그 파일로 갑니다). PlotJuggler 의 출력은 실행 폴더의 plotjuggler.log 로 가고, 그 경로를 시작 요약에 적습니다. --verbose 를 주면 모든 노드의 로그를 예전처럼 그대로 보여 줍니다.
--monitor 는 버스 타이밍(rt_raw)을 같은 터미널에 1초에 한 줄로 찍고 Ctrl-C 때 합계를 냅니다(--monitor 출력).
--plot 은 이 버스의 rt_raw_relay 와 PlotJuggler 를 함께 띄웁니다. PlotJuggler 는 A6B 예제의 레이아웃 examples/a6b_pair/plotjuggler.xml 에서 토픽의 /a6b_pair/ 를 /<bus.name>/ 로 바꾼 임시 사본을 엽니다. 두 자식 모두 run 이 끝나면 함께 끝납니다. PlotJuggler 나 그 ROS 2 스트리머(plotjuggler_ros)가 설치돼 있지 않거나 레이아웃을 읽지 못하면 아무것도 띄우기 전에 거부합니다. PlotJuggler 가 없을 때는 sudo apt install ros-$ROS_DISTRO-plotjuggler-ros 를 안내합니다. 레이아웃은 축 0 과 축 1 을 그리고, 동기 탭은 두 축이 거울처럼 맞물린 한 쌍이라고 가정합니다. 다른 버스에서는 그 그래프가 비어 있거나 뜻이 없습니다.
컨트롤러와 명령
| 축 | 컨트롤러 | 인터페이스 |
|---|---|---|
csp | joint_trajectory_controller (open loop, 궤적은 늘 정지로 끝남) | <ns>/joint_trajectory_controller/follow_joint_trajectory (control_msgs/action/FollowJointTrajectory). Python Bus.move_to, MoveIt 등 표준 클라이언트가 그대로 붙습니다 |
csv, cst | stream_controller | <ns>/stream_controller/commands (std_msgs/Float64MultiArray, best effort). 스트림 축마다 값 하나, 컨트롤러의 joints 파라미터 순서, 단위는 그 축의 것(rad/s, Nm) |
스트림 컨트롤러의 동작:
- 끊긴 스트림을 놓습니다. 마지막 메시지 50 ms 뒤 쓰기를 멈추고, 그러면 버스 자신의 50 ms 명령 감시가 보호정지를 겁니다. 마지막 메시지 뒤 약 100 ms 입니다.
- 첫 메시지 전에는 속도 축에 0 rad/s 를 명령하고 토크 축에는 아무것도 쓰지 않습니다. 그래서 토크 축이 있는 버스는 해제 전에 스트림을 먼저 흘립니다.
- 한 주기는 모든 축에 명령이 있을 때만 버스에 씁니다. 위치 축과 스트림 축이 섞인 버스에서 스트림이 끊기면 위치 축의 명령도 함께 멈춥니다.
늦게 읽힌 샘플. 컨트롤러 매니저는 버스 루프 옆에서 제 클록으로 돌아, 루프가 샘플을 늦게 읽을 수 있습니다. 계획 속도와 함께 쓴 csp 명령(궤적 컨트롤러의 속도 명령)은 그 속도 × 샘플 나이만큼 앞으로 밀어 적용합니다. 그래서 늦은 샘플이 한 주기 이동량 검사에 걸리지 않습니다.
단, 이 전진은 루프가 실제로 깨어난 시각을 따르고 검사는 정한 주기를 씁니다. 두 프레임 사이 목표는 대략 속도 × 깨어남 간격만큼 움직입니다. 빠르게 도는 축에서 루프가 늦게 깨어나 그 간격이 주기 × velocity_rad_s / 속도를 넘으면, 한 주기 이동량 검사가 보호정지를 겁니다(LIMIT_STOP 사유 5). 예를 들어 속도 한계의 90 % 로 도는 축은 간격이 약 1.1 주기면 걸립니다. 그 프레임은 이동 전체를 싣고 드라이브는 그것을 한 주기 안에 받으므로, 멈추는 쪽이 안전합니다.
버스 루프가 격리 CPU 에서 FIFO 우선순위로 돌면 드뭅니다. 늦은 깨어남은 period_dev(loop_jitter_us, 간격 − 주기)에 보입니다. 1 ms 주기, 90 % 면 약 111 µs 에서 걸립니다. 앞 주기의 오버런(deadline_miss)이 그 원인 중 하나입니다.
명령 검사
위치·속도 명령은 값을 자르지 않습니다. 다음이면 보호정지가 걸립니다.
- 위치 명령이 위치 한계 밖이거나, 한 제어 주기에 갈 수 있는 거리(
velocity_rad_s× 주기)보다 멀리 뜀. - 속도 명령의 크기가
velocity_rad_s를 넘음.
둘 다 드라이브 카운트로 바꾼 값으로 판정하므로 한계 바로 근처의 값은 반올림으로 갈릴 수 있습니다. run 이 로봇 설명에 쓰는 속도 상한 velocity_cap_rad_s 는 그 반올림을 뺀 값이라, 그 아래로 계획한 궤적은 이 검사 안에 듭니다.
해제 직후 첫 위치 명령은 그 순간의 실측 위치와 비교합니다. 토크 축이 없는 버스는 해제 때부터 지킨 위치와 비교합니다. 실측에서 한 주기 이동량보다 멀면 곧바로 보호정지이고, 그 안이면 그대로 적용되어 축이 움직입니다.
ROS 인터페이스
| 인터페이스 | 타입 | 뜻 |
|---|---|---|
<ns>/joint_states | sensor_msgs/JointState | joint_state_broadcaster 가 약 100 Hz(제어 주기가 더 느리면 그 주기)로 내는 실측 위치, 속도, 토크. 로봇과 같은 주기이고, 매 제어 주기 값은 rt_raw 에 있습니다. 이름은 파일의 축 이름 |
<ns>/plem_drive/status | plem_drive_msgs/DriveStatus | 보호정지, operation_enabled(전 축 Operation enabled), 브레이크, status_word(0x6041). 상태 확인용이고 시각 측정용이 아닙니다 |
<ns>/plem_drive/rt_events | plem_drive_msgs/RtEvent | 사건 기록. 사건의 시각은 monotonic_ns 입니다(header.stamp 는 발행 시각) |
<ns>/rt_raw | plem_drive_msgs/RtRawBatch | 매 제어 주기 기록. 40 주기씩 묶어 best_effort, 로봇과 같은 형식. 주기마다 이 버스의 축 수만큼(axis_count, 8축까지) 싣습니다. 실측과 함께 applied_command(그 주기 프레임에 실제로 실린 목표, 축 모드 단위, 클램프·반올림 반영, 표현되지 않는 위치 워드는 NaN)를 싣습니다. dc_sync_monitor_ns 는 주기마다의 DC 동기 편차(ns)입니다. bus.sync_mode: sm 이면 늘 0 이고, 4294967295 는 그 주기에 값을 얻지 못했다는 표시입니다 |
<ns>/plem_drive/info | plem_drive_msgs/DriveInfo | 기동 때 한 번 내고 유지합니다(latched). 스캔한 PDO 매핑의 digest(파일의 슬레이브 순서, 매핑을 선언한 슬레이브는 빈 문자열)와 축별 modes_of_operation(0x6060 값, int8: 10 cst, 8 csp, 9 csv, 파일의 축 순서) |
<ns>/plem/control_command | plem_drive_msgs/srv/SetControlCommand | 아래 표 |
SetControlCommand 의 요청:
| 필드 | 뜻 |
|---|---|
release_brake | 해제 |
protective_stop | 정지. 토크 축이 없는 버스는 감속해 세운 뒤 브레이크, 있으면 곧바로 disable |
reset_error | 드라이브 fault reset 과 보호정지 해제 요청. 비동기이고 결과는 status 로 봅니다 |
protective_stop 을 release_brake 나 free_drive 와 한 요청에 보내면 정지만 실행하고 나머지(reset_error 포함)는 버린 뒤 실패로 응답합니다.
해제 응답과 거부 문장
받아들인 release_brake, protective_stop 의 응답 메시지는 requested 로 시작하고, 무엇을 지켜볼지(status.operation_enabled, status.brake_engaged)를 함께 적습니다. 스크립트는 메시지 문자열이 아니라 success 로 판정합니다.
받아들여진 해제도 한 주기 뒤 준비 게이트에서 거부될 수 있습니다. 이때 응답은 success: true 인데 브레이크는 물린 채입니다. 해제는 status 로 확인하고, 원인은 rt_events 에서 봅니다. 벤치는 시간 초과 메시지에 원인을 붙여 줍니다.
해제 거부 문장은 할 일을 reset_error, status, approval.status, plem drive run(벤치, --unapproved) 같은 이름으로 알려 줍니다. 문장에 함께 나오는 내부 이름은 이렇게 읽습니다.
| 문장의 이름 | 해당하는 것 |
|---|---|
DriveHost::reset | reset_error 요청 |
DriveHost::write | 스트림 축(<ns>/stream_controller/commands)의 토크 명령 |
stopping (「a stop is still running …」) | ROS status 에 없는 내부 값. status 에서 모든 축의 brake_engaged 비트가 서고 brake_ops_pending 이 0 이 된 뒤 다시 해제합니다 |
rt_events
이벤트 번호는 RtEvent 의 상수(Python RtEvent.SLAVE_NOT_OPERATIONAL, C++ RtEvent::SLAVE_NOT_OPERATIONAL 등)로 비교합니다.
event_type | 이름 | 칸 | 할 일 |
|---|---|---|---|
| 98 (0x62) | SLAVE_NOT_OPERATIONAL | joint_id = 축, error_code = 슬레이브의 AL 상태(0 오프라인 또는 조회 실패, 1 INIT, 2 PREOP, 4 SAFEOP, 8 OP 이나 재구성 대기), value = 링 위치 | plem drive run 은 모든 슬레이브가 OP 에 든 뒤에야 버스를 띄우므로, 대개 그 뒤 슬레이브가 OP 를 벗어난 것입니다(8 은 재구성 대기). 커널 로그(sudo dmesg | grep -i ethercat)에서 AL status code 나 거부된 startup SDO(startup_sdo, 또는 dc.write_cycle_time 의 0x1C32:02)를 찾습니다 |
| 95 (0x5F) | MODE_OF_OPERATION_MISMATCH | joint_id = 축, error_code = statusword, value = 0x6061 표시값 | 축에 아직 프레임이 없거나, statusword 를 해석할 수 없거나, 표시값이 선언한 mode 와 다릅니다. mode 와 mode_display 를 확인합니다. 운전 중 모드를 벗어난 축(보호정지)도 같은 이벤트로 남습니다 |
| 78 (0x4E) | LIMIT_STOP | joint_id = 축, error_code = 사유(아래), value = 그 값(사유의 단위) | 한계 때문에 걸린 보호정지. 축마다 한 건 남습니다 |
| 79 (0x4F) | HALT_TIMEOUT | value = 요청 뒤 초 | 요청 정지가 시간 안에 확인되지 않아 Quick stop 을 명령했습니다. 다시 해제하려면 reset 이 필요합니다 |
| 84 (0x54) | TORQUE_COMMAND_STALE | value = 명령의 나이(초) | 명령 스트림이 끊겨 보호정지했습니다 |
LIMIT_STOP 의 사유: 1 위치, 2 속도, 3 위치 표현 불가, 4 위치 명령 범위, 5 위치 명령 한 주기 이동량, 6 속도 명령, 7 명령 표현 불가.
Python plem.drive
from plem.drive import Bus, SCurve
Bus 는 버스의 표준 ROS 표면(로봇 설명, joint_states, status, 제어 서비스, controller_manager/switch_controller, 궤적 액션, 스트림 토픽)만 씁니다. 자기 스레드에서 ROS 를 돌리므로, 호출은 부른 쪽만 막습니다.
상태
| 이름 | 뜻 |
|---|---|
Bus(name, *, timeout=10.0) | 파일의 bus.name 이 name 인 plem drive run 에 붙습니다. 앞의 / 는 있어도 됩니다. 로봇 설명, joint_states, status 가 올 때까지 기다리고, timeout 초 안에 오지 않으면 버스 이름을 밝히고 plem drive run 이 떠 있는지 묻는 DriveError |
bus.axes | 축 이름(튜플, 파일 순서) |
bus.positions, bus.velocities | 축 이름 → rad, rad/s (dict) |
bus["축"] | 축 하나. .position, .velocity, .move_to(x). 없는 이름은 KeyError |
bus.status | 버스의 최신 plem_drive_msgs/DriveStatus: operation_enabled, 비트 마스크 brake_engaged 와 protective_stop, status_word |
bus.default_profile | move_to 의 기본 프로파일. Trapezoid() |
timeout 은 아래 메서드의 기다림에도 쓰입니다. 오류는 DriveError(버스가 거부하거나 실패함, 메시지는 버스의 사유), ValueError(보내기 전 검사에 걸림), KeyError(없는 축 이름)입니다.
reset()
- 하는 일:
reset_error를 보내 드라이브 fault 와 보호정지를 풉니다. - 기다리는 것: 버스가 둘 다 보고하지 않을 때까지.
- 오류: 남은 것이 있으면
DriveError. 보호정지의 출처(INTERNAL 은 아직 넘은 한계, EXTERNAL 은 버스, 명령 스트림, 또는 enable·모드를 벗어난 드라이브)와 fault 축을 적습니다. 원인 자체는rt_events에 있습니다. - 스트림 축이 있는 버스는 스트림을 먼저 다시 보낸 뒤 reset 합니다. 끊긴 스트림은 남는 원인입니다.
release()
- 하는 일: 위치 축이 있는 버스면 궤적 컨트롤러를 다시 활성화해, 앞선 목표가 아니라 지금 축 위치를 지키게 합니다. 그다음 해제를 요청합니다.
- 기다리는 것: 모든 축이 Operation enabled 이고 모든 브레이크가 풀릴 때까지.
- 해제 뒤: 축은 움직일 때까지 자리를 지킵니다. 토크 축이 없는 버스의 속도 축은 해제 뒤 첫 스트림 명령까지 0 rad/s 를 지킵니다. 토크 축이 있는 버스는 살아 있는 스트림에서만 해제되고, 스트림의 명령이 해제와 함께 바로 적용됩니다.
- 오류:
- 파일의
fault_reset.policy가none이면, fault 상태(CiA 402 Fault, 많은 드라이브가 버스가 멈출 때 알람을 래치합니다)인 축이 있을 때 요청 전이든 뒤든 그 축과 statusword 를 적은DriveError를 바로 냅니다.reset()을 먼저 부르세요. - 클라이언트는 fault 를 스스로 리셋하지 않습니다.
bounded_auto_reset이면 버스가 리셋하고release()는 그것을 기다립니다. - 버스 루프가 해제를 거부하면(슬레이브가 OP 가 아님, 축이 선언한 모드가 아님) 그 축과 사유(AL 상태, 또는 0x6061 표시값과 statusword)를 적은
DriveError를 바로 냅니다. 사유는rt_events의SLAVE_NOT_OPERATIONAL·MODE_OF_OPERATION_MISMATCH에서 읽습니다. - 궤적 컨트롤러를 다시 시작하지 못하면
DriveError.
- 파일의
끊긴 스트림. 이 클라이언트가 한 번 스트림을 보냈다면 release() 와 reset() 동안에도 stream() 을 스레드에서 계속 부르세요. csv 축을 세워 두려면 0 rad/s 를 보냅니다. 요청 뒤에도 버스가 EXTERNAL 정지를 보고하는데 이 클라이언트의 스트림이 끊겨 있으면(마지막 stream() 뒤 0.1 s 초과), 두 메서드는 제한 시간을 기다리지 않고 그렇다고 적은 DriveError 를 바로 냅니다.
move_to(goals, *, velocity_scale=1.0, acceleration_scale=1.0, profile=None)
- 하는 일:
goals({축: rad})로 모든 위치 축의 이동 하나를 계획해 보냅니다. 이름을 주지 않은 위치 축은 제자리입니다. 배율은 (0, 1] 입니다. - 기다리는 것: 도착. 모든 축이 목표 1 mrad 안에 들면 돌아옵니다.
- 움직이기 전 오류:
ValueError: 이름이csp축이 아님. 계획한 점이 파일의 위치 한계, 속도(velocity_cap_rad_s), 가속(점과 점 사이 모두)을 넘음.KeyError: 없는 이름.DriveError: 축이 해제되지 않음.
- 이동 중 오류(
DriveError, 버스의 사유와 함께):- 컨트롤러가 이동을 거부하거나 실패함.
stop()이 취소함.- 축이 목표에 닿기 전에 버스가 스스로 멈춤(보호정지, 해제 풀림).
- 버스가 1초 동안 상태를 보내지 않음.
plem drive run이 떠 있는지 확인합니다. 버스가 살아 있으면 이동은 계속되니stop()으로 세우세요. - 제한 시간까지 축이 목표 1 mrad 안에 들지 않음. 거친 엔코더는 그만큼 붙지 못할 수 있습니다.
stream(commands)
- 하는 일: 스트림 축 모두에 한 주기의 명령을 보냅니다.
csv는 rad/s,cst는 Nm 입니다. 이름으로 주면 스트림 컨트롤러의 순서는 클라이언트가 맞춥니다. - 기다리는 것: 없습니다. 대신 보내 주는 스레드도 없으니 매 주기 부르세요.
- 보내기 전 오류(아무것도 보내지 않음):
ValueError: 값이 파일 한계 밖(csv는limits.velocity_rad_s,cst는limits.torque_nm의 min, max. 유한하지 않은 값 포함). 위치 축 이름이 있음. 빠진 스트림 축이 있음. 버스에 스트림 축이 없음.KeyError: 없는 이름.DriveError: 로봇 설명에 토크 한계가 없는cst축(예전plem drive run이 쓴 설명).plem drive run을 다시 띄웁니다.
- 검사는 값마다 유한한지와 파일 한계뿐입니다.
csv축의 가속은 검사하지 않습니다. - 부르기를 멈추면(루프가 멎거나 예외로 죽으면) 마지막 호출 뒤 약 100 ms(스트림 놓음 50 ms + 명령 감시 50 ms, 그리고 한 제어 주기와 전달 시간)에 버스가 보호정지합니다.
- 해제 전에 불러도 됩니다. 토크 축이 있는 버스는 그래야 해제됩니다.
stop()
- 하는 일:
protective_stop을 먼저 부르고(계획의 속도에서 감속), 진행 중인 이동을 취소합니다. - 기다리는 것: 모든 브레이크가 물릴 때까지.
- FollowJointTrajectory goal 을 직접 취소하는 것(MoveIt, CLI)은 정지가 아닙니다. 궤적 컨트롤러가 그 순간의 실측 위치를 바로 붙듭니다.
close() 와 with
with 블록을 정상으로 나가거나 close() 를 부르면 클라이언트만 닫힙니다. 해제된 축은 해제된 채 자리를 지킵니다. 블록이 예외로 끝나면(Ctrl-C 포함) 먼저 stop() 으로 축을 세운 뒤 닫습니다. 그 정지가 실패해도 원래 예외가 그대로 올라갑니다.
프로파일
| 이름 | 뜻 |
|---|---|
Trapezoid() | 기본값(bus.default_profile) |
SCurve(jerk=None) | 저크 제한. 기본 저크는 각 축이 0.1 s 에 가속 한계에 닿는 값 |
여러 축의 이동은 관절 공간의 직선 하나라 함께 출발하고 함께 섭니다. 보내는 점은 구간 경계뿐이고, 그 사이는 궤적 컨트롤러의 스플라인이 각 구간을 그대로 따릅니다. 직접 만들려면 Profile 을 상속해 plan(start, goal, limits, scale) -> trajectory_msgs/JointTrajectory 를 구현합니다. 궤적은 t = 0 에 start 에서 시작해 goal 에서 정지로 끝나야 하고, 그 점들도 같은 한계 검사를 받습니다.
이동은 run 과 plem.drive 가 계획하고, 정지는 limits.acceleration_rad_s2 로 감속합니다.
--monitor 출력
1초마다 그 1초에 들어온 값을 한 줄로 찍고, 칸 이름 줄은 20줄마다 다시 찍습니다. 버스 상태가 바뀌면 그 순간 시:분:초 -> 새 상태 한 줄을 따로 찍습니다. 터미널에서는 문제가 있는 줄(overrun, WKC 오류, 유실)을 노란색, fault 와 보호 정지를 빨간색으로 칠합니다(NO_COLOR 를 두면 칠하지 않습니다). 칸 이름에 단위가 붙어 있습니다(/s 는 그 1초에 센 수).
| 칸 | 뜻 |
|---|---|
time | 그 줄을 찍은 시각 |
exec-mean[us], exec-max[us] | 한 주기의 처리 시간(loop_exec_us)의 평균과 최대 |
jit-p99[us], jit-max[us] | 깨어남 사이 간격이 정한 주기에서 벗어난 크기(loop_jitter_us 의 절댓값)의 p99 와 최대. 일정 대비 늦음이 아닙니다 |
overrun/s | 처리가 주기보다 오래 걸린 주기 수(deadline_miss) |
wkc-err/s | working counter 가 틀린 주기 수. 슬레이브가 아직 OP 가 아닌 기동 중에는 매 주기 셉니다 |
lost/s | 샘플 번호가 건너뛴 수. 발행 쪽 넘침과 DDS 유실을 가리지 않습니다. 버스를 다시 띄워 번호가 0 으로 돌아간 것은 유실이 아니라 새 세션입니다 |
dc-max[ns] | dc_sync_monitor_ns 의 최대. 0 은 DC 꺼짐인지 실제 0 인지 구별되지 않고, 값이 없는 주기는 건너뜁니다 |
state | 마지막 status 를 말로: every statusword 0 (drives not reporting yet), held, brakes on(모든 브레이크 체결 확인), brakes moving, released. 빨간색으로 `protective stop INTERNAL |
백분위는 1000 µs 까지 0.1 µs 칸으로 셉니다. 값은 그 칸의 위 경계이고 정확한 최대를 넘지 않습니다. 1000 µs 를 넘는 값은 정확한 최대를 보여 줍니다.
벤치 세부
벤치는 미승인 파일에 plem drive run 이 제안하고, plem-drive 패키지에 들어 있습니다. 필수 항목과 합격 기준은 드라이브 모델 파일 §6.1 에 있습니다.
시작 전에 거부하는 경우. 버스와 드라이브를 건드리기 전에 거부합니다.
- 로봇 스택이나 다른 드라이브 버스가 그 마스터를 쓰고 있거나, 마스터가 Idle 이 아님.
- 파일이 이미 승인돼 있음(
already approved — nothing to bench).
승인 기록이 더는 성립하지 않는 파일(벤치 뒤 값을 고친 파일)은 그 이유를 보여 준 뒤 벤치해 기록을 바꿉니다. plem drive check 의 경고는 먼저 보여 주되 멈추지 않습니다.
확인 프롬프트. 묻는 것은 이 하나입니다. 해제 횟수는 세 번이고, 위치·속도 축과 스트림 축이 함께 있는 버스는 네 번입니다. 움직임과 안전 조건을 함께 싣습니다. 거절하면 아무것도 건드리지 않습니다.
벤치 중.
plem drive run --unapproved와 같은 사슬을 자식으로 띄웁니다. 같은--master를 씁니다.- 해제는 래치라 위치 축은 제자리를, 속도 축은 0 rad/s 를 지킵니다. 속도·토크 축이 있는 버스는 스트림 축에 0 을 흘립니다.
- 풀린 채 서 있는 축이 0.005 rad 넘게 움직이면 곧바로 중단하고 브레이크를 물립니다.
- 벤치 전에 이미 걸려 있던 드라이브 fault(앞 실행이 남긴 알람 등, 원인은 보지 않습니다)는 모든 축이 상태를 보고한 뒤
reset_error를 한 번 보내 풀고 WARN 으로 남깁니다. 승인 기록에도 남습니다. 그래도 Fault 면 벤치가 멈추니, 드라이브 알람을 풀고 다시 돌리세요. - 위치·속도 축이 있는 버스는 한 번 움직입니다(
stop-decel). 각 축을 여유 있는 쪽으로 최대 0.5 rad, 속도 상한의 0.3 배 이하로 움직이고, 순항 중에protective_stop을 불러 감속을 잽니다.
드라이브 대조와 경고. 경고는 승인을 막지 않고 승인 기록(conditions.notes)에 남습니다.
- 버스를 띄우기 전에 드라이브에서 지원 모드(0x6502)를 읽습니다. 파일의 모드를 지원하지 않으면 브레이크를 풀기 전에 멈춥니다.
- 드라이브 쪽 극성(0x607E)과 파일의
flip이 함께 켜져 있으면 경고합니다. - 드라이브의 스케일 객체(0x6092, 0x6091, 0x608F)가 모터 1회전을 파일의
encoder_resolution과 다른 정수 카운트로 보고하면 경고합니다. 파일의startup_sdo가 쓰는 객체는 그 값으로 판정합니다. 읽기 실패는 대조하지 않을 뿐 멈추지 않습니다. - 위치·속도 축은 파일이 선언하지 않은 정지 값을 드라이브가 지금 가진 값 그대로,
startup_sdo에 붙일 수 있는 줄로 보여 줍니다. - 끝난 뒤 벤치 전후로 엔코더 위치가 1회전 이상 바뀌었는지 알립니다.
stop-decel이 움직인 축은 감속기를 거치면 여러 회전일 수 있어 판정하지 않으므로,csp,csv축이 있는 버스는cst축만 봅니다. - 벤치 동안 내부 한계(statusword bit 11)가 났는지 알립니다. 추종 오차(bit 13)는 PLEM 이 쓰지 않고 정상 운전 중에도 켜질 수 있어 알리지 않습니다.
결과.
- 전부 통과하면 승인 기록을 모델 파일 안에 씁니다. 파일의
approval블록을 제자리에서 바꾸거나(없으면 끝에 붙임) 나머지 바이트는 그대로 둡니다. 같은 디렉터리의 임시 파일에 쓴 뒤 rename 으로 한 번에 바꿉니다(권한 유지). 벤치 증거가 그 기록 안에 들어 있습니다. - 벤치 도중 파일을 고쳤으면(digest 가 달라짐) 기록을 거부합니다.
- 그 밖의 결과는 파일을 건드리지 않고
my_drive.bench.log만 남깁니다. - 승인을 판정하는 것은 C++ 도구(
plem_drive의 판정 함수)이고, 벤치는 잰 값을 옮길 뿐입니다. my_drive.bench.log는 확인한 실행마다 새로 씁니다. 확인 전 거부나 거절은 한 줄만 출력하고 아무것도 쓰지 않습니다. 앞 실행의 로그가 필요하면 다시 돌리기 전에 옮겨 두세요.- 모델 파일은 실행하는 사용자 소유여야 하고 그 파일과 디렉터리에 쓸 수 있어야 합니다.
승인의 범위. 기동 때 대조하는 것은 기록에 적은 칸뿐입니다. revision number 나 버전 칸이 null 이면 그 칸은 대조하지 않으므로, 그 값이 바뀌어도(버전이면 다른 펌웨어) 승인이 유지됩니다. 시리얼이 0 이거나 기록되지 않았으면 묶을 개체가 없어, 기록에 남은 칸 안에서 같은 제조사·제품 번호(scanned 슬레이브는 스캔한 매핑까지)의 드라이브 전부에서 열립니다.