Computer-Driven Grid Sweep with 3pi+ and MQTT

Hello Pololu community,
Over the past year, I have been working on a project using Pololu robots in Dr. Honary’s lab at the University of San Diego, under the broader theme of multi-agent search and rescue. I was a freshman at the time with no coding experience, so many of my issues were self-inflicted. However, these are great, resilient devices to learn on and I have made great progress past what is written here that I hope to share soon. Below, I give a summary of what I did previously. This forum has been very useful to me the past year so I thought I would present this for others to use.

The goal of the overall project is to design a cost-effective, multi-agent platform for testing search algorithms. For this phase, I used Pololu 3pi+ 2040 OLED robots with the aim of getting them to run a computer-directed coordinated sweep across a taped grid. Each robot has an ESP32 on board that relays commands and status over Wi-Fi using MQTT, and a simple hub script runs the sweep. The outcome is multiple Pololus perform a computer-directed sweep ( not perfectly) via MQTT on a grid and report when they hit “clues” or an “object.”

Hardware is straightforward. The base is the Pololu 3pi+ 2040 OLED. Comms are handled by an ESP32 per robot talking UART0 at 230400 baud on GP28/29. The hub is a Jetson Nano (or any PC) running a Mosquitto broker and a Python control script. The grid is a white table with black electrical-tape lines, white tape/paper at intersections to simulate clues, and rolls of tape placed so the bump sensors can register an “object.”

The comms structure is simple and reliable. Robot ↔ ESP32 is UART at 230400. On MQTT, each robot has an ID/command and ID/status, and the hub can also broadcast on general/command. The hub publishes movement commands like “1”, “L”, “R”, or “stop”. The ESP32 receives them over MQTT and relays them to the Pololu over UART. After executing, the Pololu reports back strings like x/y, line:x/y, bingo:x/y, or invalid:x/y, and the ESP32 publishes that upstream for logging and coordination.

On first command the robot self-calibrates. It spins in place and calls line_sensors.calibrate() ~50 times, then calibrates the bump sensors. That sets thresholds for both line and bump detection so the rest of the run is consistent.

Movement distance is defined by line intersection. Number commands (‘1’–‘10’) mean “pass this many intersections.” The robot runs a ride_the_line() routine that does proportional + derivative correction using the weighted IR sensor values to follow the tape. For intersections, it watches the outer sensors (0 and 4). If they cross threshold, it slows to verify, increments intersections_passed, and once it hits the target, it stops, updates (x, y), and reports.

The Pololu is a great platform because it offers 2 simple methods of detection. If the middle sensor (index 2) reads very low after calibration (under ~200), that’s a “clue”: the robot halts, updates location, and reports line:x/y. If either bump sensor trips, that’s an “object”: it reports bingo:x/y and stops immediately.

Turns are handled with point turns. “L” or “R” triggers about a 0.4 s point turn with asymmetric motor speeds. Before turning, it checks there’s actually a valid left or right line to enter. After the turn it updates its heading (N, E, S, W) and reports. If there isn’t a valid line to turn onto, it reports invalid:x/y.

If a stop command comes in during motion, it sets a stop_pending flag and halts at the next intersection, then reports current (x, y) so the hub stays in sync.

A few challenges were worth noting. Initially, the idea was the use HC-05s, but powering the modules off the Pololu’s 3.3 V rail was flaky, so I moved to ESP32s and MQTT over Wi-Fi and that stabilized everything. We also initially wanted free-roaming robots, but the drift was too unpredictable to run multiple in a group without constant correction. Early intersection logic double-counted; adding an ignore_intersection_timer fixed the repeats. Using white patches for clues and bump hits for objects mapped nicely to the search-and-rescue analogy.

Robots follow hub-assigned paths and stop when they pass the commanded number of intersections, detect a clue, hit an object, or receive a stop broadcast. They report grid coordinates back, and the hub logs everything. Multiple robots can run under the same hub script and cover the grid in a coordinated sweep.

Improvements I didn’t get to would be correcting the starting location of each robot and adding incident detection, however it worked well enough for the simple goal/demo I wanted.

The next goal is to replace the hard-coded sweep with a search policy to enable autonomous search and clue adaptive behavior.

Hardware:

Pololu 3pi+ 2040 Robot with headers soldered in

ESP-32 WROOM-32U

Computer (I used a jetson nano)

Wifi setup

GitHub link to code: GitHub - jlott22/PoloGridRunners: A centralized MQTT-based control system for coordinating multiple Pololu 3pi+ robots to execute a hard-coded search pattern on a grid and relay footprints and objects location using line-following, intersection counting, and IR sensor readings.

Sorry for the short film, the limit was 5MB.

3 Likes