Two Robots That Talk in Tones
A camera robot maps a marker road network, finds a ball and talks a second, blind robot through the pickup by sound.

- Role
- Course project at HTW Berlin (computer engineering): hardware selection, vision and path planning, the acoustic modem, ROS 2 integration, STM32 firmware and testing.
- Robots
- 2, different roles
- Modem
- 16 tones, 500 to 4250 Hz
- Path finding
- Dijkstra
- Middleware
- ROS 2
- Stack
- C++, ROS 2, ros2_control, OpenCV (ArUco), ALSA, FFTW, PulseAudio, STM32 / C, PlantUML
The setup
Two small omnidirectional robots have to do something neither can do alone. The commander has a camera: it explores a road network marked with ArUco markers, spots the ball and plans the route. The worker has no camera but has a gripper: it drives the route it's given, picks up the ball and brings it back. They have no radio link. The only channel between them is sound.
The brief asked for exactly that: localise with an on-board camera, invent a "robot language" of acoustic signals that survives a noisy room, synchronise sending and receiving without any radio, navigate on your own, and keep requirements, design, tests and history in GitLab.
How the pieces fit
- Perception
- USB cameracalibrated
- ArUco detectionOpenCV, 4×4 dictionary, pose estimation
- MicrophoneALSA capture
- Decision
- Discovery state machineexplore, move, exit
- Street network graphnodes, headings, Dijkstra
- Collect taskworker: drive, grab, return
- Communication
- Acoustic modem16 tones, FFT decoding
- Packet protocolstart sequence, ID, ACK, CRC32
- Motion
- ROS 2 omni controllerkinematics, odometry
- ros2_control hardware interfaceUSB serial
- STM32G4 firmwarePWM motor control
Seeing, planning, talking, driving
- 1.
Seeing the road network
The commander detects ArUco markers in the camera image and estimates their pose with the calibrated camera. Each marker stands for a junction and the directions you can take from it. A state machine turns, lines up with the next marker, drives to it and writes down what it found.
- 2.
Building the map
Every junction becomes a node in a graph, with its distance, heading and open directions. Once the ball has been seen, Dijkstra gives the shortest path, which is turned into relative instructions: left, right, straight.
- 3.
Talking in tones
Each 4-bit symbol is a sine tone between 500 and 4250 Hz in 250 Hz steps, followed by a separator tone, played through PulseAudio. The receiver records with ALSA, runs an FFT with FFTW and takes the strongest valid frequency. A symbol only counts once it's been heard several times in a row.
- 4.
Packets
A packet starts with a fixed nibble sequence that includes the receiver's ID, then an acknowledgement, the payload and a CRC32. A misheard command gets thrown away instead of driven.
- 5.
Driving
Velocity commands go to an omnidirectional controller in ROS 2. A custom ros2_control hardware interface sends the wheel commands over USB serial to an STM32G4, which generates the motor PWM.
What broke in testing
Every component has its own test program: camera input, marker detection, the street network, the audio protocol, the microphone filter, the speaker and motor control. The integration tests are written up with logs and videos. Three things came out of them:
- Markers that weren't seen reliably. The white border around the markers was too narrow. Bigger markers with a wider border fixed it.
- Overshooting when lining up. The rotation corrections were too aggressive, so the marker jumped from one side of the image to the other. Calmer turning and a different stopping distance made gate passes repeatable.
- Testing the talking without the driving. Commander and worker ran the full logic with real audio between them but with the motors off. That way path planning and communication could be checked separately from motion.
Trade-offs
Simple frequency-shift keying, with each symbol confirmed several times
- Why
- Easy to generate and easy to decode with an FFT. The repetition filters out short bursts of noise.
- Cost
- Slow: every symbol needs a tone and a pause.
A graph of junctions instead of a metric map
- Why
- The task only needs to know what connects to what, and Dijkstra on a small graph is exact and cheap.
- Cost
- Only works on a network laid out with markers.