I entered the Sparkfun Autonomous Vehicle Competition for the first time last year. It didn’t go as well as I had hoped, so I’m hoping to start earlier and make some changes this year. This is going to be a short recap of the progress I’ve made so far.
Last year, I started late and spent too much time working on less important things at the expense of critical functions. This year, I’m going to prioritize things by importance and ease of implementation and get the earlier things tested and working well before trying other things. Here’s a rough list of things that need to be done in order of priority:
- Control the car from the onboard computer (done!)
- Complete sensor data processing (in progress)
- Complete basic navigation to waypoints
- Add a physical start button
- Nice to have
- Include basic collision detection and recovery
- Use a Kalman filter for position estimation
- Add a remote kill switch
- Implement obstacle avoidance
- Consider the shortcut, non-GPS option, and ramp and hoop
- Estimate speed from accelerating from a standstill
- Look at faster motors and other upgrades
- Get remote monitoring working
Last year, all of my code was in Python. Python is nice because it is easy to test, easy to prototype new ideas, easy to edit on the Pi so that you can make changes in the field, and has fantastic library support (Want to output PWM from the Raspberry Pi’s GPIO pins with hard real-time requirements without using much CPU? There’s a library for that). It’s biggest drawback is that it’s slow. I’ve heard estimates of it being around 40 times slower that optimized C code.
Now before you write Python as an option off, I would strongly urge you to benchmark your code and consider the tradeoffs. Last year, I was running my code on a Raspberry Pi model B running an ARMv6 processor at 700 MHz. The GPS I was using only provided updates at 1 Hz, while the compass provided updates at 5 Hz. My vehicle had a top speed of about 2 meters per second, and my code directly used the GPS readings without any filtering. With my code processing this information and controlling the car at 5 Hz, I was comfortably sitting under 20% CPU utilization. Python was perfectly adequate.
This year, I have a much faster car, a GPS module that updates more frequently, and I’m hoping to do some extra position processing and image processing for obstacle avoidance. I started modifying my original code but found after running some benchmarks that the CPU usage was uncomfortably high, so I started looking for a new language.
My initial thought was to try Rust, a new programming language whose development is being sponsored by Mozilla. Rust compiles to machine code, so it should be about as fast as modern C++. It also has a complex type system that prevents memory leaks, null pointer errors, use-after-free errors, and data races.
Rust is an evolving language. They only recently released an alpha version, and they recommend that you always use the nightly builds. Unfortunately, there is no official ARMv6 support yet. I did find a guide for compiling a cross-compiler targeting the Pi, but I was worried that that would prevent me from easily modifying the code in the field. After some digging, I found a few months old build that ran on the Pi. This worked fine, but trying to get help when I ran into issues was problematic because most people were only familiar with the nightly version. Also, I found that the trigonometric functions did not work.
At this point, I wasn’t sure what to do. I started rewriting my code in C++ but became frustrated with, well, everything about C++. Build systems, Makefiles, Sconstruct files, header files, circular dependencies, manual memory management, race conditions, linking, preprocessor directives, unsafe macros, null pointer errors… During my brief time with Rust, I’d forgotten about all of the annoyances of C++. Fortunately, another user started making unofficial builds of Rust for the Pi and I was able to use them. And, the trigonometric functions worked!
Rust hasn’t been all rainbows and sunshine though. Being a pre-1.0 language, it’s still undergoing a lot of syntax changes, and I’ve had to rewrite parts of my code several times. This should stop in a month or two though. Partly as a result of this constant change, it’s also lacking an extensive library. Fortunately, I’ve found that it’s very easy to call external C functions. Finally, the biggest problem I’ve had is the learning curve. With other languages, it’s easy to pick up bits and pieces of the syntax and learn as you go, but I’ve found that you really need a good handle on the type system before you can do much of anything. Be prepared to read through the Rust book before setting off.
I guess that’s it for now. Over the next few weeks I hope to get the GPS sensors working and the car doing some basic waypoint navigation. Once that’s done, I’ll add a physical start button. This should leave me in decent shape for the competition if nothing else goes as planned.