A ROS 2 Jazzy + Gazebo Harmonic project. A four-wheeled differential-drive robot with a 3-joint magnetic arm picks up objects scattered around a simulated home and drops them in a collection bin.
Robot definition. Contains:
urdf/— xacro files:base.xacro(chassis, 4 wheels),torso.xacro,arm_active.xacro(shoulder/elbow/wrist joints),arm_cosmetic.xacro,sensors.xacro(camera, GPU lidar, IMU),materials.xacro,inertia_macros.xacro,ros2_control.xacrourdf/robot.urdf.xacro— top-level xacro that includes everything plus Gazebo plugins: diff-drive, joint state publisher, joint position controllers (arm), detachable joint system (magnet pick/drop), triggered publishers (magnet_off fan-out)meshes/— STL meshes for base, wheels, torso, arm linkslaunch/view_robot.launch.py— RViz-only robot viewerconfig/— RViz configs for different stagesrviz/— saved RViz layout
Simulation world. Contains:
worlds/home.sdf— two-room home with walls, furniture, three pickable objects (toy_block_1,can,ball), and a collection binmodels/— SDF + DAE meshes for furniture (chairs, dining table, sofa, coffee table, side table, bookshelf, file cabinet, fridge) and the drop-off boxlaunch/home.launch.py— starts Gazebo (ogre2),robot_state_publisher, spawns robot viaros_gz_sim create, fires initialmagnet_offafter 5 s
Mission logic. Contains:
driftbot_task/task_node.py—TaskNodeclass: odom/IMU/scan/camera subscriptions, world-frame pose (odom position + IMU heading), motion primitives (face_toward,drive_to,drive_straight,turn_by_imu,settle_heading,bug2_drive_to), arm staging,pick()/drop(), mission dispatchdriftbot_task/gz_support.py—GzBridgeSupportnode: relaysjoint_states_gz→joint_states, broadcastsodom→base_footprintTF, relaysscan_raw→scanwithlidar_linkframedriftbot_task/missions/—__init__.py(dispatcher),mission_01.py(straight-line block pick+drop),mission_02.py(Bug2 can+ball pick+drop)config/gz_bridge.yaml— 15 ROS↔Gazebo topic mappingslaunch/mission.launch.py— staggered launch of Gazebo, bridge, nodes, RVizrviz/mission.rviz— RViz layout with grid, robot model, TF, laser scan, camera
- ROS 2 Jazzy
- Gazebo Harmonic
ros_gz_bridge,ros_gz_simrobot_state_publisher,tf2_rosrviz2,image_view- Python 3
No Nav2, no OpenCV, no external planners.
git clone <repo-url> ~/driftbot_assignment/driftbot_ws
cd ~/driftbot_assignment/driftbot_wssource /opt/ros/jazzy/setup.bash
colcon build --symlink-installOpen ~/.bashrc in a text editor and add (or update) the following lines. If you previously had these pointing to a different folder (e.g. drift_assignment instead of driftbot_assignment), replace the old lines entirely — do not keep both.
source ~/driftbot_assignment/driftbot_ws/install/setup.bash
export GZ_SIM_RESOURCE_PATH=$GZ_SIM_RESOURCE_PATH:/home/$USER/driftbot_assignment/driftbot_ws/install/driftbot_description/share
export GZ_SIM_RESOURCE_PATH=$GZ_SIM_RESOURCE_PATH:/home/$USER/driftbot_assignment/driftbot_ws/src/driftbot_gazebo/modelsNote:
GZ_SIM_RESOURCE_PATHtells Gazebo where to find meshes and models. If this is stale or points to the wrong directory, Gazebo will fail to load all STL meshes and the robot will appear invisible in the simulation.
source ~/.bashrcecho $GZ_SIM_RESOURCE_PATHThe output should include paths under ~/driftbot_assignment/. If you still see the old folder name, check ~/.bashrc for duplicate or leftover entries and remove them.
Opens RViz with the robot URDF model for inspection. No simulation.
ros2 launch driftbot_description view_robot.launch.pyStarts Gazebo with the two-room home world, runs robot_state_publisher, and spawns the robot. Does not start any bridge or task nodes.
ros2 launch driftbot_gazebo home.launch.pyOptional args: spawn_x, spawn_y, spawn_yaw, spawn_z, software_gl.
The main launch. Starts everything in sequence:
- 0 s — Gazebo world + robot spawn (includes
home.launch.py) - 8 s — ROS↔Gazebo bridge (clock, odom, cmd_vel, joints, scan, arm, IMU, camera, magnet topics)
- 12 s —
gz_supportnode (joint relay, odom→TF, scan frame fix) +task_node(runs mission) - 15 s — RViz + camera viewer
ros2 launch driftbot_task mission.launch.pyOptional args: spawn_x, spawn_y, spawn_yaw, mission_id.
A single launch runs all phases in sequence:
Mission 1 — Pick block (straight-line)
Drives south to toy_block_1, stops at 60 cm, picks up with magnetic arm, turns 180°, locks heading north, drives to drop-off point, turns -90° to face east, locks heading, drops into collection bin.
Mission 2 — Pick toy_block_2 + toy_block_3 (Bug2)
Uses Bug2 obstacle-avoidance to navigate to toy_block_2, picks it up, Bug2 back to bin, drops. Then repeats for toy_block_3.
Mission 3 — Computer vision object detection pipeline TBD.
Robot spawns at (7.5, 9.0) facing south (yaw = -π/2).
| Object | Position |
|---|---|
| toy_block_1 | (7.5, 5.0) |
| toy_block_2 | (-5.0, 5.0) |
| toy_block_3 | (-2.0, 2.0) |
| can | (1.5, 9.0) |
| ball | (1.5, 2.0) |
| cone | (-8.0, 3.0) |
| collection bin | (8.50, 9.0) |
| drop-off point | (7.5, 9.0) |
- Rover STL meshes and URDF adapted from GGomezMorales/waver
- Arm URDF and meshes adapted from AL5D description
- Furniture models sourced/adapted from Gazebo Fuel, osrf/gazebo_models, and ipa320/cob_simulation