Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

racecar-hm — ROS Workspace for an Autonomous Model Car

This repository contains the ROS workspace for my Bachelor's thesis at the Munich University of Applied Sciences (Hochschule München).

Title: Softwarearchitektur eines autonom fahrenden Modellautos auf Basis von ROS
English: Software Architecture of an Autonomous Driving Model Car Based on ROS

📄 Full thesis (German): Bachelorarbeit.pdf


Why This Work Was Done

The MIT RACECAR project had already been set up at HM and extended by several student projects. By the time I started, the codebase had grown organically into a state that made further development difficult:

  1. Code was scattered across three separate Git repositories — there was no single source of truth. Understanding the full system meant context-switching between repos.
  2. Existing student code was poorly structured — the PS4 controller had hardcoded "magic numbers", erratic steering behavior, and bypassed the entire multiplexer architecture by publishing directly to the motor driver. The line-following node used a monolithic racecar_class with 6 redundant publishers and tangled responsibilities.
  3. No unified control interface — the real car and the simulation used completely different control pipelines. You could not develop and test on the simulation and expect the same behavior on the lab vehicle.
  4. Simulation did not match reality — the simulated car had 7 individual wheel controllers (the real car has 2 motors driving paired wheels), incorrect steering geometry, and a different steering offset. The multiplexer was started but never actually wired into the simulation pipeline.

The result: students could not effectively use the simulation for development, the code was hard to extend, and adding new features meant duplicating or patching existing broken logic.

What Was Achieved

1. Complete Workspace Restructuring and Code Refactoring

Before: Three disconnected repos, a racecar_additions package with tangled dependencies, a racecar_class that bundled unrelated logic, OpenCV headers vendored into the repo instead of linked properly.

After: A single unified racecar-hm workspace. The entire teleoperation stack (PS4 controller, Xbox controller, line detection, line following, mode switch) was extracted from the monolithic racecar_additions and refactored into a clean, modular teleoperation package with its own CMakeLists.txt and package.xml. Each node has a single responsibility and communicates through the proper ROS interfaces.

Key refactoring:

  • PS4 controller (src/teleoperation/src/ps4_controller.cpp): Rewrote from scratch — replaced magic number button indices with named constants, fixed erratic servo behavior, integrated with the ackermann_cmd_mux so commands go through the proper arbitration pipeline instead of directly to the motor driver, removed redundant publishers.
  • Line-following motion node (src/teleoperation/src/line_detection/motion_node.cpp): Created a proper class-based design with a clean header (motion_node.h), eliminated the dependency on the bloated racecar_class, reduced 6 publishers down to 1 that correctly publishes AckermannDriveStamped through the multiplexer.
  • Runtime mode switch (src/teleoperation/src/switch.cpp): Built a new node that lets the driver toggle between manual controller mode and autonomous line-following mode at runtime via the Select/Share button — without this, switching modes required stopping and restarting nodes.

2. ROS Control Hardware Interface (vesc_hw_interface)

Adapted and extended SoftBank Corp.'s open-source vesc_hw_interface (Apache 2.0) to drive the lab car's VESC through the ros_control framework and close the real-vs-simulation gap. The upstream package exposes a single joint via one command_mode; the work here:

  • Registers two interfaces simultaneously — a PositionJointInterface for the steering servo and a VelocityJointInterface for the drive motor — so one node controls both axes of the Ackermann car (vesc_hw_interface.cpp).
  • Adds a servo-mode origin calibration for the steering servo, whose center position cannot be read back, so the interface calibrates it dynamically on startup (vesc_servo_controller.cpp).
  • Replaces the upstream PID law with a PT1-style position controller (the original PID is kept, commented, for reference).
  • Loads joint limits for both joints from the URDF and the parameter server.

The result is a unified control pipeline: the same ros_control interface drives the real car and the Gazebo simulation.

3. Simulation Adapted to Reality

Overhauled the Gazebo simulation to match the lab vehicle's hardware:

  • Reduced from 7 individual wheel controllers down to 3 (one joint state, one velocity, one position controller) — matching the real car's 2-motor, Ackermann-steering layout
  • Wheel parallelization via mimic joint plugin so two motors drive all four wheels, exactly like the real vehicle
  • Corrected steering neutral position offset (0.5304 rad) to match the real servo
  • Removed the servo_commands intermediary node that existed only in simulation
  • Multiplexer now actively wired into the simulation pipeline (previously started but not connected to anything)
  • Fixed PID controller gains in racecar_control.yaml so the simulation behaves like the real car

Architecture Overview

Architecture diagram

Skills Demonstrated

  • ROS / roscpp — nodes, topics, custom messages, launch files, the parameter server, and ros_control
  • C++ — class-based node design and refactoring legacy code into modular, single-responsibility packages
  • ros_control hardware interfaceshardware_interface, controller_manager, joint limits, and a custom position controller
  • Computer vision — OpenCV line detection on a ZED stereo-camera feed via cv_bridge
  • Robotics simulation — Gazebo, URDF/xacro modeling, mimic-joint plugins, and PID controller tuning
  • Hardware integration — VESC motor controller over serial, with automatic servo calibration
  • Software architecture — command multiplexing/arbitration, runtime mode switching, and sim-to-real alignment
  • Working with legacy code — consolidating three repositories and untangling undocumented student code

Key Challenges & What I Learned

  • Sim-to-real divergence was the core problem. The simulation and the lab car had drifted into two different control pipelines, so nothing developed in simulation could be trusted on the real vehicle. Converging them onto a single ros_control pipeline was the central architectural decision.
  • The steering servo gives no position feedback. Its electrical center is unknown at startup, so the hardware interface runs an automatic origin calibration before closed-loop control begins.
  • Inherited code was opaque. The previous controller used unexplained floating-point literals for every joystick axis and button — working out what each one did was the hardest part of the rewrite, which is why the refactored code leans on named constants and single-responsibility nodes.

My Contributions

Package Key Files What I Did
src/teleoperation/ ps4_controller.cpp, xbox_controller.cpp, switch.cpp, line_detection/*, msg/navigation.msg, launch/*, CMakeLists.txt, package.xml Complete refactor. Rewrote PS4 controller from magic-numbered mess into clean code with proper multiplexer integration. Created the switch node for runtime mode toggling. Refactored line-following from a monolithic class with 6 publishers into a clean node publishing through the mux. Bundled everything into a new teleoperation package with its own build config.
src/vesc/vesc_hw_interface/ vesc_hw_interface.cpp, vesc_servo_controller.cpp, config/*, launch/* Extended SoftBank's Apache-2.0 vesc_hw_interface. Added simultaneous position (steering) + velocity (drive) control, automatic servo-origin calibration, a PT1 position-control law, and all config/launch so the real car shares one ros_control pipeline with the simulation.
Simulation fixes racecar_control.yaml, racecar.xacro, macros.xacro PID tuning, steering offset correction, wheel mimic joint parallelization, controller reduction from 7→3.

Third-Party Packages

This workspace builds upon several open-source projects, each retaining its original license. My original code lives in the teleoperation package. I also extended the third-party vesc_hw_interface (SoftBank Corp., Apache 2.0) and made configuration/URDF changes to racecar_gazebo to align the simulation with the lab car; the remaining MIT/BSD packages are used as-is.

Package Origin License
ackermann_cmd_mux/ MIT RACECAR BSD
racecar/ MIT RACECAR BSD
racecar_gazebo/ MIT RACECAR Gazebo BSD
razor_imu_9dof/ KristofRobot/razor_imu_9dof BSD
vesc/ (driver packages) MIT RACECAR VESC BSD / Apache 2.0
vesc/vesc_hw_interface/ (adapted & extended) SoftBank Corp. — Yuki Onishi Apache 2.0
roboticsgroup_gazebo_plugins/ roboticsgroup Gazebo plugins BSD
zed-ros-wrapper/ Stereolabs ZED ROS wrapper Apache 2.0

roboticsgroup_gazebo_plugins/ and zed-ros-wrapper/ are external dependencies, not included in this repository (see .gitignore); clone them into src/ separately.

Required dependencies (install separately):

  • ros-*-joy
  • ros-*-ackermann-msgs
  • ros-*-ros-controllers
  • wjwwood/serial (GitHub) — for VESC serial communication

Getting Started

Tested on: Ubuntu 18.04 (ROS Melodic) and Ubuntu 20.04 (ROS Noetic)

# Install ROS dependencies
sudo apt install ros-${ROS_DISTRO}-joy
sudo apt install ros-${ROS_DISTRO}-ackermann-msgs
sudo apt install ros-${ROS_DISTRO}-ros-controllers

# Build the workspace
cd racecar-hm
catkin build
source devel/setup.bash

Launch the simulation

roslaunch racecar_gazebo racecar.launch

Drive with a controller (PS4 or Xbox)

# PS4 controller (also starts joy_node)
roslaunch teleoperation ps4_controller.launch

# Xbox controller (use_switch routes commands through the manual/autonomous mux)
roslaunch teleoperation xbox_controller.launch use_switch:=true

Launch line detection and following

roslaunch teleoperation line_detection.launch

Launch everything (simulation + controller + line following)

roslaunch racecar_control all.launch ps4_controller:=true line_following:=true world_name:=racecar_line

License

My original work — the teleoperation package (src/teleoperation/) — is licensed under the MIT License. See LICENSE.

My changes to src/vesc/vesc_hw_interface/ are modifications of SoftBank Corp.'s package and remain under its original Apache 2.0 license, with the modifications noted in that package's README.

All other third-party packages retain their own licenses as noted above.

About

Autonomous 1/10-scale model car on ROS — teleop, line-following, a unified ros_control pipeline, and Gazebo simulation. Bachelor's thesis (Hochschule München).

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages