Back to packages

robonix.primitive.agilex.ranger_mini_v3.chassis

AgileX Ranger Mini chassis driver wrapper.

README

ranger_chassis_rbnx

Robonix package wrapping the AgileX Ranger Mini v3 chassis. Owns the primitive/chassis/* namespace.

Capability surface

Contract Mode Transport Source / handler
robonix/primitive/chassis/driver rpc gRPC Driver(CMD_INIT, config_json) — lifecycle
robonix/primitive/chassis/odom topic_out ROS 2 /odom (nav_msgs/Odometry)
robonix/primitive/chassis/twist_in topic_in ROS 2 /cmd_vel (geometry_msgs/Twist)

primitive/chassis/move (rpc-mode) needs its own gRPC handler implementing chassis/srv/ExecuteMoveCommand — TODO. We do NOT implement primitive/chassis/state: that legacy contract bundled map-frame pose into a chassis-owned RPC, which is a layering inversion (chassis primitives are device leaves; localization belongs to the localization service). For "where is the robot in the map?" subscribe to service/map/pose instead.

Driver-init lifecycle

start.sh brings up the atlas bridge — no ROS spawn. The bridge opens a gRPC server (default port 50234), registers the capability and declares only primitive/chassis/driver, then blocks awaiting Driver(CMD_INIT, config_json).

When rbnx boot calls Init, the handler parses config (CAN port, robot model, frames, update rate), spawns ros2 launch ranger_bringup ranger_mini_v2.launch.xml, waits for the first nav_msgs/Odometry on /<odom_topic_name>, and declares chassis/odom + chassis/twist_in on atlas.

If the chassis isn't powered or CAN isn't up, the sentinel times out and Init returns state="error" (NOT deferred — the chassis owns its process; we know it's stuck if we just spawned it and got nothing).

Layout

ranger_chassis_rbnx/
├── package_manifest.yaml
├── ranger_chassis/atlas_bridge.py
├── scripts/
│   ├── build.sh        colcon build vendored sources + rbnx codegen
│   └── start.sh        source ROS, exec atlas_bridge
└── src/
    ├── ranger_ros2/    VENDORED agilexrobotics/ranger_ros2
    └── ugv_sdk/        VENDORED agilexrobotics/ugv_sdk (CAN bus client)

CAN bus naming

The CAN interface name is config-driven — set port_name: in your deploy manifest's config: block to whatever the host calls its CAN device (can0, can_ranger, can_chassis, …). The package never hardcodes a device name, so it works on any host regardless of how its CAN interfaces are named.

When multiple CAN devices share a host you may want to rename the Ranger's interface to something stable via udev / systemd-networkd so the name doesn't shift across boots, then point port_name: at the rename. That's a host-side operation — the package only sees the name you give it via config.

Config (passed via Driver(CMD_INIT, config_json))

{
  "port_name":         "can0",
  "robot_model":       "ranger_mini_v2",
  "odom_frame":        "odom",
  "base_frame":        "base_link",
  "update_rate":       50,
  "odom_topic_name":   "odom",
  "publish_odom_tf":   false,
  "twist_in_topic":    "/cmd_vel",
  "sentinel_timeout_s": 30.0
}

publish_odom_tf defaults to false; the canonical base_link → odom TF should come from soma's robot_state_publisher chain (URDF). Setting this to true here means competing publishers on /tf — only useful if soma isn't deployed.

License

This package: Apache-2.0. Vendored ranger_ros2 / ugv_sdk: see their respective LICENSE files.