Status
The joint ordering, joint names, and joint_id → leg/joint mapping on this page are CONFIRMED and canonical (ratified 2026-09-04). Every consumer uses exactly this table — there is no alternative numbering.
Geometric constants marked pending (link lengths, limits, masses) are current best estimates pending final vendor data. The joint mapping itself is final.
Joint ordering rules confirmed
Twelve joints, IDs 1–12. The ID is a deterministic index derived from a fixed two-level rule:
- Legs are numbered first:
FL → FR → RL → RR(front row before rear row; within a row, left before right). - Within each leg, joints are numbered body-to-foot:
hip → knee → ankle.
Derivation:
joint_id = 1 + 3 × leg_index + joint_index
leg_index: fl = 0, fr = 1, rl = 2, rr = 3
joint_index: hip = 0, knee = 1, ankle = 2
Checks: fl_hip = 1 · fr_ankle = 1 + 3 + 2 = 6 ·
rl_knee = 1 + 6 + 1 = 8 · rr_ankle = 1 + 9 + 2 = 12. ✓
Master joint map confirmed
| joint_id | Joint name | Leg | Joint | Motion |
|---|---|---|---|---|
| 1 | fl_hip | front-left | hip | thigh swing, sagittal plane |
| 2 | fl_knee | front-left | knee | thigh → shank bend |
| 3 | fl_ankle | front-left | ankle | shank → foot pitch |
| 4 | fr_hip | front-right | hip | thigh swing, sagittal plane |
| 5 | fr_knee | front-right | knee | thigh → shank bend |
| 6 | fr_ankle | front-right | ankle | shank → foot pitch |
| 7 | rl_hip | rear-left | hip | thigh swing, sagittal plane |
| 8 | rl_knee | rear-left | knee | thigh → shank bend |
| 9 | rl_ankle | rear-left | ankle | shank → foot pitch |
| 10 | rr_hip | rear-right | hip | thigh swing, sagittal plane |
| 11 | rr_knee | rear-right | knee | thigh → shank bend |
| 12 | rr_ankle | rear-right | ankle | shank → foot pitch |
Name grammar confirmed
Joint names are always {leg}_{joint}:
leg∈ {fl,fr,rl,rr}joint∈ {hip,knee,ankle}
All 12 names are derivable from the ordering rules above; the joint name and the
joint_id always agree per the master map. Any code, message, or log that carries a
joint_id (1–12) is decoded with that table, and any that carries a name is spelled
exactly as shown (lowercase, underscore).
Body frame canonical
| Axis | Direction |
|---|---|
| +x | forward (nose) |
| +y | right (left side is −y) |
| +z | up |
base_linkorigin: robot center, at the hip joint height (z = 0 plane).- All 12 joints rotate about the body Y axis
(0, 1, 0)— lateral, planar legs; no roll or yaw at any joint. - Zero pose: all angles 0 → legs straight down, feet at rest positions.
- Units: documentation and datasheets in mm; URDF/ROS in m.
Hip origins & foot rest positions verified
Hip joint origin in base_link (m) — directly above the foot rest position:
| Leg | Hip x | Hip y | Foot z (rest) |
|---|---|---|---|
| FL | 0.130 | −0.105 | −0.185 m (−185 mm) |
| FR | 0.130 | +0.105 | −0.185 m |
| RL | 0.240 | −0.105 | −0.185 m |
| RR | 0.240 | +0.105 | −0.185 m |
Foot rest positions, body frame (mm): FL (130, −105, −185) · FR (130, +105, −185) · RL (240, −105, −185) · RR (240, +105, −185).
Per-joint kinematics
| Parameter | Value | Status |
|---|---|---|
| L1 (hip → knee, thigh) | 0.100 m | pending — provisional split of the 185 mm rest reach |
| L2 (knee → ankle, shank) | 0.085 m | pending — L1 + L2 = 0.185 m matches documented foot drop |
| Ankle → foot | fixed joint, not actuated | confirmed — chain is hip → knee → ankle → foot |
| Joint axes | (0, 1, 0) all legs | canonical (body frame above) |
Limits / effort / velocity per joint type (same for all four legs):
| Joint | Limit (rad) | Limit (°) | Max effort | Max velocity |
|---|---|---|---|---|
| hip | ±1.20 | ±68.8° | 10 N·m | 10 rad/s |
| knee | ±1.57 | ±89.9° | 10 N·m | 10 rad/s |
| ankle | ±0.60 | ±34.4° | 5 N·m | 10 rad/s |
All limit values are provisional estimates pending final vendor data (rated motor torque
is 5 N·m per the GIM6010-8 datasheet in Robot).
Telemetry wire mapping canonical
Commands (JointTarget) and samples (JointSample) both address joints by
the joint_id from the master map above. There is no second numbering.
| Field | Type | Meaning |
|---|---|---|
id / joint_id | uint | 1–12, decoded per the master map (fl_hip … rr_ankle) |
pos / pos_rad | float | target/actual angle, rad, zero pose per body frame |
vel / vel_rads | float | target/actual angular velocity, rad/s |
kp, kd | float | PD gains |
max_tq | float | per-joint torque clamp, N·m |
tq_nnm, cur_a, temp_c, flags, fault_code | — | sample-side telemetry (50 Hz) |
URDF structure canonical
Files: limit.urdf (expanded), limit.urdf.xacro (parameterized source),
generate.py (regenerator: python3 generate.py).
- 17 links:
base_link+ 4 × {{leg}_hip,{leg}_thigh,{leg}_shank,{leg}_foot} - 16 joints, four per leg:
| URDF joint | Type | Parent → Child |
|---|---|---|
{leg}_hip | revolute | base_link → {leg}_hip |
{leg}_knee | revolute | {leg}_hip → {leg}_thigh |
{leg}_ankle | revolute | {leg}_thigh → {leg}_shank |
{leg}_foot | fixed | {leg}_shank → {leg}_foot |
Note: each revolute joint shares its name with its child link (e.g. joint fl_hip drives
link fl_hip). The ankle actuator is joint {leg}_ankle; the foot itself
is a passive link carried by fixed joint {leg}_foot.
/joint_states names (ROS): fl_hip, fl_knee, fl_ankle, fr_hip, fr_knee, fr_ankle,
rl_hip, rl_knee, rl_ankle, rr_hip, rr_knee, rr_ankle.
Gait pairing (trot)
Trot drives the two diagonal leg pairs in alternation:
- Pair A: FL + RR — joint IDs {1, 2, 3, 10, 11, 12}
- Pair B: FR + RL — joint IDs {4, 5, 6, 7, 8, 9}
Single source of truth
This page is the canonical specification, mirrored 1:1 in the URDF repository README
(limit_urdf/README.md). Downstream artifacts must stay in lockstep:
| Artifact | Uses this spec for |
|---|---|
generate.py / limit.urdf / limit.urdf.xacro | link & joint names, order, geometry |
limit_msgs (JointTarget / JointSample) | joint_id 1–12 semantics |
sim_node.cpp | synthetic joint numbering |
Dashboard (dash.js) | joint_id → leg/axis rendering |
limit_docs/ site | public documentation |
Change process: propose the change here first (with date + rationale), then update all downstream artifacts in the same commit. A mapping change breaks every consumer simultaneously — never edit one artifact alone.
Usage
# regenerate URDF after any parameter edit
python3 generate.py
# ROS 2
ros2 launch robot_state_publisher robot_state_publisher.launch.xml \
robot_description:="$(command cat limit.urdf)"
# joint_state_publisher_gui feeds /joint_states (fl_hip, fl_knee, …)
rviz: RobotModel first; swap box/cylinder visuals for per-link meshes when per-link GLTF exports
exist (the current AssemblyAnimated.gltf is one skinned mesh and cannot be split per URDF
link).
Verified facts & sources
- 12 actuated joints, IDs 1–12, 50 Hz —
limit_msgs/msg/JointSample.msg,sim_node.cpp - 4 legs × 3 joints, chain hip → knee → ankle → foot — Robot
- Foot rest positions — Robot (Kinematics)
- 12 × GIM6010-8 joints, PD control (kp, kd, pos, vel, max_tq) — Robot (Drivetrain),
JointTarget.msg - Gait: trot, alternating diagonal pairs
- Joint ordering & mapping — confirmed 2026-09-04 (this page)