본문으로 건너뛰기

드라이브 버스 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_judgedcheck 가 판정하지 않고 기동 때 판정하는 것
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_nmcst 축의 limits.torque_nm. 다른 축은 null

plem drive run 이 하는 일​

plem drive run <파일> [--master N] [--rt-cpu N] [--monitor] [--plot] [--unapproved] [--verbose]
  1. 이름과 승인 확인. 파일을 check 로 봅니다. 버스는 /<bus.name> 네임스페이스에서 뜹니다. 같은 이름의 plem drive run 이 이 기기의 내 계정에서 이미 떠 있으면(그 네임스페이스의 컨트롤러 매니저나 robot_state_publisher) 그 pid 와 함께 거부합니다. 다른 계정이나 같은 ROS 도메인의 다른 기기에서 뜬 버스는 보지 못합니다. 승인을 주장하지만 더는 성립하지 않는 파일(벤치 뒤 값을 고친 파일 등)도 미승인으로 읽습니다. 미승인 파일이면 터미널에서 벤치를 이어 돌립니다. --unapproved 를 주면 묻지 않고 벤치 기동으로 띄웁니다. 이때 「BENCH MODE」 경고가 나오고, 그 런의 근거는 벤치 근거일 뿐입니다.
  2. 실시간 환경 경고. 커널이 PREEMPT_RT 가 아니거나, 격리 CPU 가 없거나, Jetson 의 nvpps PTP-TSC 잠금이 켜져 있으면 고칠 방법과 함께 경고만 합니다. nvpps 잠금은 호스트 클록을 끌고 다녀 드라이브의 DC 편차가 따라옵니다.
  3. 로봇 설명과 파라미터. 로봇 설명은 축마다 관절 하나를 파일의 축 순서로 둡니다. 관절 이름은 파일의 축 이름이고, 위치 한계는 파일 값, 끝 멈춤 없는 축은 continuous, 속도 한계는 velocity_cap_rad_s 입니다. 컨트롤러 매니저의 갱신 주기는 버스 주기와 같습니다.
  4. CPU. 버스 루프는 기본으로 마지막 격리 CPU 에 붙고, --rt-cpu N 이면 CPU N 에 붙습니다. 이 프로세스가 돌 수 있는 CPU 여야 하고, 아니면 하드웨어 플러그인이 기동 때 격리 CPU 목록(/sys/devices/system/cpu/isolated)을 알리며 거부합니다. 격리됐는지는 검사하지 않습니다. 매니저의 갱신 스레드는 갈 곳이 있으면 격리 CPU 와 --rt-cpu 의 CPU 밖에서 돕니다. 버스 루프의 우선순위는 기본값 그대로이고 옵션은 없습니다.
  5. 기동. 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 을 그리고, 동기 탭은 두 축이 거울처럼 맞물린 한 쌍이라고 가정합니다. 다른 버스에서는 그 그래프가 비어 있거나 뜻이 없습니다.

컨트롤러와 명령​

축컨트롤러인터페이스
cspjoint_trajectory_controller (open loop, 궤적은 늘 정지로 끝남)<ns>/joint_trajectory_controller/follow_joint_trajectory (control_msgs/action/FollowJointTrajectory). Python Bus.move_to, MoveIt 등 표준 클라이언트가 그대로 붙습니다
csv, cststream_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_statessensor_msgs/JointStatejoint_state_broadcaster 가 약 100 Hz(제어 주기가 더 느리면 그 주기)로 내는 실측 위치, 속도, 토크. 로봇과 같은 주기이고, 매 제어 주기 값은 rt_raw 에 있습니다. 이름은 파일의 축 이름
<ns>/plem_drive/statusplem_drive_msgs/DriveStatus보호정지, operation_enabled(전 축 Operation enabled), 브레이크, status_word(0x6041). 상태 확인용이고 시각 측정용이 아닙니다
<ns>/plem_drive/rt_eventsplem_drive_msgs/RtEvent사건 기록. 사건의 시각은 monotonic_ns 입니다(header.stamp 는 발행 시각)
<ns>/rt_rawplem_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/infoplem_drive_msgs/DriveInfo기동 때 한 번 내고 유지합니다(latched). 스캔한 PDO 매핑의 digest(파일의 슬레이브 순서, 매핑을 선언한 슬레이브는 빈 문자열)와 축별 modes_of_operation(0x6060 값, int8: 10 cst, 8 csp, 9 csv, 파일의 축 순서)
<ns>/plem/control_commandplem_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::resetreset_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_OPERATIONALjoint_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_MISMATCHjoint_id = 축, error_code = statusword, value = 0x6061 표시값축에 아직 프레임이 없거나, statusword 를 해석할 수 없거나, 표시값이 선언한 mode 와 다릅니다. mode 와 mode_display 를 확인합니다. 운전 중 모드를 벗어난 축(보호정지)도 같은 이벤트로 남습니다
78 (0x4E)LIMIT_STOPjoint_id = 축, error_code = 사유(아래), value = 그 값(사유의 단위)한계 때문에 걸린 보호정지. 축마다 한 건 남습니다
79 (0x4F)HALT_TIMEOUTvalue = 요청 뒤 초요청 정지가 시간 안에 확인되지 않아 Quick stop 을 명령했습니다. 다시 해제하려면 reset 이 필요합니다
84 (0x54)TORQUE_COMMAND_STALEvalue = 명령의 나이(초)명령 스트림이 끊겨 보호정지했습니다

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_profilemove_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/sworking 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 슬레이브는 스캔한 매핑까지)의 드라이브 전부에서 열립니다.