A lighthouse turns its beam so that ships can find it. The lidar on my workbench turns its beam so that it can find everything else. Ten times a second, the LD19 sweeps an infrared laser around the room and times each reflection, a method its manual calls direct time-of-flight (LD19 Manual, 2022). Paired with a Raspberry Pi 5 and a PiSugar battery board, it becomes a portable device that knows the shape of any room I set it in.

My partner on the build was my AI assistant, the agent that runs on my Mac in a runtime called Hermes. I brought the parts, four wires, and a goal. The agent brought a terminal on the Pi and a habit of checking its own work. Together we went from a bare board to a working web application in a day. What came after, a month of building, taught me how a person and an agent can experiment well together.

Four Wires and a Borrowed Port

The LD19 has four wires: 5 volts, ground, a data line out, and a PWM (pulse-width modulation) input that controls the motor. I connected them to the Pi’s GPIO header, its row of general-purpose pins, following the vendor’s wiring table. Then I sent the agent a photo and asked it to explore the Pi before changing anything.

The first obstacle was not electrical. Because macOS names screenshots with a narrow no-break space before “PM,” the agent had to find my photo by its bytes. Once found, the photo confirmed the connection that matters most, the lidar’s transmit line on the Pi’s receive pin.

Those pins had no serial port on the Pi yet, only a separate debug port that reads silence, exactly like a dead sensor. The agent backed up the boot configuration, enabled the right port, and caught a trap before it closed. On a Pi 5, serial0, the name the kernel console uses, points at the lidar’s own port. Leaving the console there would have put a 115200-baud login prompt on a 230400-baud data line.

One more question came from the motor wire. A grounded PWM pin runs the motor under its own speed control at 10 Hz (LD19 Manual, 2022). My wire went to a GPIO pin instead. Rather than ask me to move it, the agent added one boot setting that holds the pin low from power-on. Nothing had to be rewired.

Listening to a Device That Never Listens

The LD19 accepts no commands. Once its rotor is stable, it streams measurement packets and never stops, so the software’s whole job is to listen correctly (LudovaTech). I pointed the agent at that community tutorial, which bundles the vendor’s manual, and asked it to learn the device first. It turned what it read into a reusable skill: a packet decoder, a self-test, and a list of pitfalls.

Each packet starts with the bytes 0x54 and 0x2C and ends with a one-byte checksum, a CRC-8 (cyclic redundancy check). Between them sit the rotor speed, start and end angles in hundredths of a degree, twelve distance and intensity readings, and a timestamp. The length hid a trap: the tutorial’s example code reads 45 bytes after it finds the two-byte header, while the manual describes a 47-byte packet. Both are right, because 45 plus the header is 47. A decoder that mixes the two conventions produces angles that look plausible and are wrong.

The agent settled it with evidence instead of a vote. It decoded the worked example packet printed in the manual and checked the fields against the documented values, including the checksum byte, 0x50. Even the example has a slip: it lists the second distance, 0x00DC, as 200 millimeters, and 0x00DC is 220. Decoding beats copying. All thirteen self-test checks passed before the lidar sent a single real byte.

Then came the first live capture. In ten seconds, 4,160 of 4,160 packets were valid, the rotor turned at 9.90 Hz, and readings covered all 360 degrees. That is 4,992 points a second, against the manual’s rating of 4,500.

From Packets to a Picture

Next I asked for a web application: a top-down view of the room with range measurements, single or continuous scans, and an idle timeout that parks the lidar. Parking it was the hard part. The manual documents only one motor signal, speed control at 20 to 50 kHz. An attempt to stop the motor with it failed.

I had read a description of two more signals the firmware is said to answer: 7 kHz for standby and 4 kHz to wake. Neither is in the manual, and the agent’s search found no official source. The agent did not take my word for it. It wrote a throwaway test that read the data stream in the background while sending each signal. After the 7 kHz command, eight more packets arrived, then silence. After the 4 kHz command, the reported rotor speed climbed from zero back to ten turns a second. That climb proved the motor itself had stopped. I brought a claim, and the agent turned it into a measurement.

With the motor solved, the agent paused and asked me to make the architectural calls. I chose Python’s standard library only, a WebSocket to push each scan to the browser as it happens, and a 120-second idle timeout. The standard library has no WebSocket server, so the agent wrote one from the protocol specification in about 140 lines (Fette and Melnikov, 2011). Each rotation appears in the browser as a polar plot with range rings, and a click reads out distance and bearing.

The lidar web application: a dark polar plot of colored scan points outlining a room, with range rings, a measurement marker reading 2.29 m at 78.2 degrees, and scan and motion detection controls on the right.

The web application after a single scan of my workroom. A click on the right-hand wall dropped the marker, which reads 2.29 meters at 78.2 degrees. Select the image for full size.

Testing the running service found two bugs that would have kept the laser spinning indefinitely. The status endpoint counted as activity, so any monitoring poll reset the idle timer. An internal subscriber that fans scans out to browsers also counted as a viewer, so the timer could never expire. Tests now pin both. By the end of the day, the service survived a reboot with no manual setup.

Where Each of Us Was Wrong

By the end of the month the project had 95 commits. Along the way it gained battery telemetry, motion detection, and alerts to my phone. It also gained an MCP server, a Model Context Protocol interface that lets the agent request a scan itself. The moments I remember best are the ones where one of us was wrong.

The PiSugar battery board would not show up on the Pi’s I2C bus, the two-wire bus the Pi uses to talk to small chips. Across two sessions, the agent concluded it was a seating fault: the bus, the pin assignments, and the drivers were healthy, and nothing answered. I looked at the hardware and found the cause. The Pi and the PiSugar have identical USB-C connectors stacked one above the other, and my power cable was in the Pi’s. From software, an unpowered board and a badly seated one look the same. Only someone holding the device could tell them apart.

The agent was also wrong about its own tests, and it caught those errors itself. A test window that was too short made a cold rotor look like a failed wake-up. Packets left in a serial buffer made a good stop look like a failure. Each time, it suspected its own measurement before blaming the hardware.

It also caught what I would have missed. Once the battery board came alive, the agent found its service listening on my whole home network with no authentication, including a command that shuts the Pi down. I chose to restrict it to the Pi itself.

Setting Goals and Testing Claims

In 1960, J. C. R. Licklider proposed a division of labor he called man-computer symbiosis: “men will set the goals, formulate the hypotheses, determine the criteria, and perform the evaluations. Computing machines will do the routinizable work that must be done to prepare the way for insights and decisions in technical and scientific thinking” (Licklider, 1960). On my bench the split was less tidy. The agent formed hypotheses, and some were wrong. I supplied a fact the manual lacked and a diagnosis the software could not see.

Researchers who studied 758 Boston Consulting Group consultants describe a “jagged technological frontier” of AI capability. Tasks that seem “similar in difficulty level” can fall on opposite sides of it (Dell’Acqua et al., 2023). That matched my month. Decoding a binary protocol sat well inside the agent’s frontier. Seeing which of two identical connectors held a cable sat outside it, because that evidence never reached a terminal.

Pairing a person with an AI does not always help. A meta-analysis of 106 experiments found that, on average, the pairs did worse than the best of either alone (Vaccaro, Almaatouq, and Malone, 2024). They lost ground on decisions and gained it on tasks that create content. This build was mostly creation, which is where that study found the gains.

What made the difference was process. Garry Kasparov, the former world chess champion, drew the same lesson from “freestyle” chess. A 2005 online tournament was won by a pair of amateur players using three computers. His summary: “Weak human + machine + better process was superior to a strong computer alone and, more remarkably, superior to a strong human + machine + inferior process” (Kasparov, 2010). Our process had one rule: neither of us got to be right by saying so. My 7 kHz claim had to stop the motor on the agent’s test, and the agent’s seating diagnosis had to survive a look at the cables.

The lidar finds its way by sending light into the room and believing only what comes back. That turned out to be the right rule for the two of us. Each of us sent something out, a hypothesis, a fact, a fix, and let the hardware answer. A lighthouse exists to be seen. The best part of this project was learning, together, how to look.


References