LEGO is a fun and relatively easy way to put together a robot. I competed in
Robocup Junior last year and used LEGO parts to build the robot because we
ran out of time to put together something more professional, and it worked out
fine. However, the motors and sensors we were using are about as old as I am,
and they're showing signs of age. This year I planned to use the new generation
of LEGO hardware, which uses a new connector type. The hardware is really
precise and reliable, which is great. They are also pretty easy to build with.
In addition, the Raspberry Pi Foundation put together a Pi hat that lets you
plug in these parts and talk to them. It supports a Python and C# interface,
but I can't stand Python for robotics and I also despise using C# on Linux,
so I foolishly decided to try to make a library to control it through good old
C.
When I started working on this project, I hit the real hurdle immediately. The
hat works through serial communication through the normal rx/tx pins (no SPI
or I2C or anything), which meant I'd be using read and write syscalls to do
everything. The problem is that it's challenging to debug this stuff. Turns out
that the BuildHAT runs on the new-ish RP2040 chip, which has no onboard
non-volatile storage. To account for firmware updates (I assume), the
developers made a bootloader that sits on a ROM on the board through which you
upload a firmware image and signature every time the board power cycles. The
bootloading process is entirely undocumented. There's a 'help' command you can
send it (if you're using minicom or something to talk through serial to the
board), which seems like it tells you what you have to do, but it didn't work,
so I went to look at the open-source Python library to see what I was doing
wrong. Turns out that there are multiple magic numbers and a whole checksum
generation routine that are required but fully undocumented. Luckily they were
easy to copy. It's confusing to me why the RPi Foundation would provide a whole
serial interface documentation PDF but totally neglect the relevant information
that allow someone who is not using Python or C# (which nobody reading the
serial documentation is using, clearly) to actually use the serial mode. You'd
have to first run a boilerplate Python program or something to get the firmware
uploaded in order to use the serial mode, but then there's no point in using
serial. Anyways.
I'm not a particularly experienced C programmer, especially not with string
input handling, because all my C code is usually pretty static as it runs
microcontroller stuff. There was a lot of string stuff involved in sending
all these runtime-determined commands to the board, and then handling
confusingly unpredictable returns. There's a method to obtain the 'expected
response length', but there seemingly isn't a guarantee that the response will
actually fit in a buffer of that size, which is totally obnoxious and defeats
the point. The current state of my library is that my slightly abstracted read/
write functions are totally broken and not usable. However, with that being
said, I believe it is more C-like to make the read/write syscalls yourself on
the file descriptor that is created by the firmware loading routine. The
firmware loading is really the only thing that is infeasable to implement
every time, everything else is just read/write calls. I'd like to have polished
this a lot more, but unfortunately I lost track of time this season and we
didn't make it to competition this year, so I didn't really feel motivated
to finish this. Hopefully the firmware loader lowers the barrier to entry
enough to let somebody else give C programming a shot for robotics.