ROS 2 Jazzy / Rust Safety Core / EV Charging Robotics

KiwiDock

KiwiDock is a ROS 2 Jazzy robotics simulation for an autonomous mobile EV charging robot. The stack drives a robot from depot to dock, aligns an end effector with a Tesla Model 3-style charge port, verifies safety interlocks, and only enables charging when the system is safe.

Robotics stack, safety supervisor, simulation, and dashboardROS 2 JazzyRustrclpyRViz2ReactSSE

Full Robotics Stack

Built as a ROS 2 system with Python rclpy nodes, URDF/Xacro robot description, standard ROS messages, RViz2 world visualization, and live browser telemetry.

Rust Safety Supervisor

Safety-critical docking logic lives in Rust with a typed state machine, unicycle control, sensor freshness checks, battery reserve checks, and ROS-free unit tests.

Human-zone SAFE_HOLD

A moving human actor crosses the docking area. When the zone is occupied, the robot publishes zero velocity, disables charging, enters SAFE_HOLD, and resumes automatically when clear.

Project Notes

The details that mattered.

Project overview

The demo starts the robot at a depot, routes it through a parking-lot scene, approaches a parked Tesla Model 3-style vehicle, aligns the end effector with the charging dock, verifies clearance, and enables charging only after the safety supervisor reaches a safe charging state.

ROS 2 simulation nodes

robot_sim.py applies a unicycle motion model from /cmd_vel and publishes /odom, /tf, and /robot_path. sensor_sim.py publishes LaserScan and BatteryState data with obstacle, stale-sensor, human-zone, and low-battery fault behavior. human_sim.py publishes the moving actor pose, path, presence, and safety-zone state.

World and supervisor bridge

world_visualizer.py renders the parking lot, vehicle, dock target, safety zone, robot path, human actor, faults, and status labels in RViz. docking_supervisor_adapter.py bridges ROS telemetry into the Rust core, then publishes /cmd_vel, /dock_state, /safety_events, /charging_enabled, and /status_markers.

Safety-critical Rust core

The Rust supervisor owns the docking state flow from IDLE through APPROACHING, FINE_ALIGNING, VERIFYING_CLEARANCE, DOCKED, CHARGING, and COMPLETE. Any obstacle, human-zone, stale sensor, low battery, pose tolerance, or yaw tolerance issue moves the system into SAFE_HOLD with charging disabled.

Live dashboard telemetry

dashboard_bridge.py converts ROS telemetry into JSON snapshots and Server-Sent Events for the React 19 dashboard. The browser view shows robot telemetry, battery state, obstacle range, human-zone status, docking state, connector gap, yaw error, and an SVG close-up of the end effector aligning with the charge port.

Build and validation stack

The system targets Ubuntu 24.04 on WSL2, ROS 2 Jazzy, Python rclpy nodes, Cargo for Rust builds and tests, colcon for workspace builds, RViz2 visualization, Vite frontend tooling, HTML/CSS/SVG visualization, and a 60 Hz simulation and telemetry update target.

Diagrams

KiwiDock technical system map.

ROS 2 nodes, Rust safety logic, RViz visualization, and browser telemetry in one stack.

Reference Architecture

KiwiDock full system architecture

KiwiDock system architecture diagram showing ROS 2 Python nodes, Rust safety core, dashboard bridge, React dashboard, key topics, URDF package, launch scripts, and build setup

01 / System Architecture

ROS 2 simulation, Rust safety core, RViz, and React dashboard

ROS 2 Simulation

robot_sim.pysensor_sim.pyhuman_sim.pyworld_visualizer.py

Supervisor Adapter

docking_supervisor_adapter.py/odom, /scan, /battery_state/human/in_safety_zone

Rust Safety Core

Typed docking state machineUnicycle controllerSafety interlocksCargo unit tests

Visualization

RViz2 markersdashboard_bridge.pyServer-Sent EventsReact 19 dashboard

02 / ROS 2 Node Graph

docking_supervisor_adapter.py centered topic graph

/odom/scan/battery_state/human/pose/human/in_safety_zone

Adapter

docking_supervisor_adapter.py

ROS telemetry in, Rust safety decision out

/cmd_vel/dock_state/charging_enabled/safety_events/status_markers

03 / Docking State Machine

Nominal flow with SAFE_HOLD fallback

IDLE->
APPROACHING->
FINE_ALIGNING->
VERIFYING_CLEARANCE->
DOCKED->
CHARGING->
COMPLETE

SAFE_HOLD

Triggered by obstacle, human-zone, stale sensor, low battery, pose tolerance, or yaw tolerance failures. Publishes zero velocity and keeps charging disabled until the hold condition clears.

04 / Runtime Sequence

Human-zone hold and automatic resume

  1. 01Startup pause and telemetry warm-up
  2. 02Robot leaves depot and approaches target vehicle
  3. 03Human actor enters the docking safety zone
  4. 04Supervisor enters SAFE_HOLD, publishes zero velocity, and disables charging
  5. 05Human clears the zone after the crossing sequence
  6. 06Robot resumes approach and fine alignment automatically
  7. 07Clearance, pose, yaw, battery, obstacle, and freshness checks pass
  8. 08Charging is enabled and the dashboard switches to success state

05 / Dashboard Data Flow

ROS topics to Server-Sent Events to React

/odom/battery_state/scan/dock_state/charging_enabled/human/in_safety_zone
ROS 2 topics
->
dashboard_bridge.py
->
React dashboard via SSE

JSON snapshots carry robot telemetry, battery state, obstacle range, human-zone status, docking state, connector gap, yaw error, and charging status at a 60 Hz target.

RViz Parking Lot View

Robot path, Tesla-style vehicle, dock target, safety zone, human actor, status labels.

React Telemetry Dashboard

Battery, range, connector gap, yaw error, dock state, and charging success view.

ROS Graph Snapshot

Supervisor-centered topic graph for simulation, telemetry, commands, and safety events.

Safety State Machine

Nominal docking path with SAFE_HOLD highlighted as the fallback state.

Videos

Project demos and test footage.

KiwiDock autonomous docking and safety-hold walkthrough