Software apps and online services
As I try to keep my projects affordable, doable and reasonably solid, I like to start with a complete kit and expand on that. My focus is much more on coding then on building.
The cheapest and easiest to source robot car kits generally are Arduino based. Which makes sense as Arduino is an excellent "robot brain".
What Arduino (the simple types) does not have, however, is a lot of computing power and wireless connectivity. Therefore I often expand my cheap little robot car with a Particle Photon. I link the two by sticking a breadboard on the robot with the Photon connecting the two via simple serial (RS-232 TTY level). It took some research but yes: it is harmless to talk to a Photon with 5V, the RX port is 5V tolerant. Likewise the Arduino is quite happy to accept 3V3 as "HIGH" on it's RX.
This also allows for some asynchronous computing tasks, like reading sensors while processing the next movement instructions at the same time.
It also allows interacting with a desktop or laptop via WiFi which immediately opens up a world of extra possibilities.
Attached you will find the code for the Arduino and Photon parts. In the Photon code you will find some references to an INA219 (power measurement) and a BNO055 (9DoF). The connections for these are trivial as they are both I2C devices, just connect Vcc to the Photon 3V3, GND to GND, SCA to SCA and SCL to SCL. See application notes for the INA219 for the connections to the raw power source (in my case two 18650 LIPO batteries) and the circuit under test.
I can recommend adding a INA219 to your project, it reveals a LOT about the power being used by your robot car under various conditions (running, turning, scanning, idling).
My robot kit came with a echo sounder to measure distances, mounted on a servo so you will see some code for that as well. Likewise it has three line followers mounted underneath.
The serial protocol is of my own design. It's super simple but copes quite well with transmission errors and works well with the Serial.parseInt() function. For each parameter I define a case-sensitive letter. This is usually immediately followed by a value. Finally a white-space character (space, tab, EOLN) separates the next transmitted parameter.
In case of a transmission error things tend to recover quite quickly as the stream of commands/parameters is continuous.
The entire project runs on a 20 Hertz "heartbeat" (50 milliseconds). This proves to be rapid enough to be responsive while leaving enough time to poll sensors and such.
The protocol used between a desktop or laptop running the actual code I'm experimenting with is UDP. This is similar to for instance VoIP (Voice over IP) for the same reasons: its fast, low overhead and if we missed a packet we do not want it re-transmitted like TCP would do. The recovery and buffering mechanisms of TCP/IP are a major hinder in this case, never use TCP/IP for volatile data like sensor readings or (motor) commands. Just keep a continuous stream of datagrams going and deal with missing data by simple repetition.