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.
ROS 2 Jazzy / Rust Safety Core / EV Charging Robotics
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.
Built as a ROS 2 system with Python rclpy nodes, URDF/Xacro robot description, standard ROS messages, RViz2 world visualization, and live browser telemetry.
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.
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 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.
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_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.
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.
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.
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
ROS 2 nodes, Rust safety logic, RViz visualization, and browser telemetry in one stack.
Reference Architecture

01 / System Architecture
02 / ROS 2 Node Graph
Adapter
docking_supervisor_adapter.py
ROS telemetry in, Rust safety decision out
03 / Docking State Machine
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
05 / Dashboard Data Flow
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