(Short clip of driving outdoors)


Overview

As before, this project is about making a "drone-like" model car which gives the operator a video feed, some telemetry, and which communicates with a single digital radio. At the heart of it is a Raspberry Pi 3. It deals with messaging through the Wifi interface, controlling servos, and communicating with the motor controller, to name the most important tasks.

Hardware configuration

Illustrated in the following diagram.


Red represents power supply, black lines data flow, and yellowish major components. The box labeled Custom "Shield" is a circuit board which sits on the 40 pin header of the Pi and bears the indicated components. Besides the obvious, there is a status LED which blinks differently depending on the state of the operating system - shut down, rc car processes running, or processes not running. The "shutdown" button triggers shutdown of the OS, as the name implies. With IMU I refer to a AltIMU-10 v4 board from Pololu. I added it for the possibility to present the heading, or some sort of attitude indicator to the user.

Software

The next diagram shows the processes running on the Pi.

There is a central Python script, here named Control Process, which handles messaging and servo control. You read that right, Python. However, the speed with which it could be developed made it worthwhile to write rather than going straight for a C++ implementation. Fortunately it runs fast enough.

RX and TX refer to the processes pertaining to  the wifibroadcast software. They use stdin/stdout to exchange data. However, I find it convenient to launch them independently of the other processes. Other processes should just be able to connect to them when both parts are available. I enabled this by connecting RX/TX to socat which opens sockets other processes can connect to.

Raspivid, on the other hand, streams directly through stdout/stdin to TX since this part of the system is very simple and stable - at least from my user perspective. So no need to control these two independently.

All the processes are managed by systemd - much like in the basic wifibroadcast project. There is a service file for each of them. A custom .target file helps to bring everything up automatically in a well defined order.

(Code is on GitHub, if you dare to look)


Details on essential and/or changed components follow.

Drive train

The main goal after completing the last iteration of the vehicle was the incorporation of a new drive system. There are several reasons for this, namely: 

The controller got a project site of its own. I refer there for details.

Power distribution

The car is powered by a single 12 V battery. The motor controller has a small linear regulator to supply its micro controller. In contrast to before, the board on top of the Raspberry Pi now carries a regulator for the Pi and one for the servos. I employ identical cheap switch mode buck converter boards with 3 A output bought from Ebay. My design has two of them because a 2 A supply is recommended for the Pi and the servos can draw significant current, too. In particular the more powerful steering servo. Moreover, voltage fluctuations induced by servo operation should not have a negative impact on the Pi. The Pi has a dedicated USB port for power. However, in my case it was simpler to power it through the 5 V pin on the 40 pin header.

Messaging protocol

Previously I described by ASCII based messaging protocol with which commands and other data are exchanged between control station and car. While simple and mostly human readable, I ultimately did not like it. Mostly because it becomes unsafe and clumsy to use when things get more sophisticated. To explain, there was no schema, no types, no API. Just raw numbers.

But this can be helped. First let's consider (de)serialization, i.e. turning a data structure into a byte stream to go over the wire. There are good technologies out there. I picked Protobuf. The Protobuf compiler takes a formal message definition and auto-generates code to access the data, parse it from a string, and encode it. In addition to the safety this makes it easy to add more functionality. For instance adding messages for setting parameters.

But that is not all. Unlike say, TCP, the serial link with the motor controller nor Wifibroadcast know the concept of a message. Just raw bytes. Therefore, when transmitting over such channels, the beginning and the end of each message must be clearly identified in one way or another. One might send a header with magic numbers and the message length. I found an interesting alternative named "Consistent Overhead Byte Stuffing" (COBS). Basically, it rewrites the byte stream in a clever way, such that messages are delimited by zeros.

Another important aspect is checking for transmission errors. Wifibroadcast does not do this. In case of video we deliberately delegate the problem of dealing with errors to the video decoder. With control messages the situation is different. Therefore, I simply compute a CRC8 checksum and append it to the serialized message. The receiver also computes the checksum and discards the message if the numbers mismatch.

Telemetry

The motor controller reports

The Pi itself monitors

All of this data is sent periodically as Protobuf messages to the control station. In addition to the telemetry, the following is also displayed to the user

Control

Overall it is quite simple. The Pi receives messages with desired speed, steering deflection, and camera yaw. The speed value is forwarded to the motor controller. The servos are controlled directly from the Pi, i.e. their signal wires are connected to the 40 pin header. I am using the pigpio library to configure the PWM signal at the pins. This library even implements special convenience functions for servo control.

Conclusion

In this projects I implemented a number of improvements and extensions over the previous iterations of this model car. At the very least I arrived at another working solution which can be deployed outdoors. And I am rather quite happy with that.

But so far I did not have a chance to try it on more challenging terrain, like steep climbs, rocks, and so on. Hence I am uncertain about its performance there. Which I hope to change when I find a suitable spot.

Indeed, I am fortunate that the initially fabricated hardware already does well. However, there are some issues. Most disturbing at present maybe the deliberate lack of consideration for casing during the design of the circuit board. The connectors, cables and buttons are in places that makes it impossible to devise a satisfactory protective cover. I find the one I made for now rather comical.

In spite of that, the next step in this line of project will most likely be a remote control. I still use my laptop - put on the roof of my car so I can operate the game controller with both hands. A more portable solution is desired.