Welcome back to our ArduRover series! In Part 1 and Part 2, we have built a 6WD Arduino rover. In this final part, we will focus on writing a program for robot control. We already covered a bit of coding in the second part, but that was just to get the motors running. This time, however, we want to get all the sensor data, maybe even transfer some pictures from the serial camera, and most importantly, we want some actual remote control using an Android phone!
In the previous part of this series, among other things, I covered wiring of the logic circuits – all the sensors and modules. Back then, I only tested the motors, because the VNH5019 drivers were the only subsystem I haven’t worked with before. Naturally, the code that I used only controlled them and since they were working just fine, I thought it was safe to add all the other functions, such as code to control the sensors, the camera, and the servos. Imagine my surprise when all the motors stopped working immediately after adding those.
When issues like that happen, we have to take a step back and look back when everything was working correctly. I changed coding, and this was very easy just by uploading a different Arduino sketch, to see if the problem was in the hardware or in the software. Sure enough, the motors were running again with the older sketch. By carefully adding and removing parts of the new code, I discovered that the Servo library was somehow responsible for the error. After calling servo.attach() function, the motors would stop working. This seemed very odd, until I realized what was going on with the signals. When using the Servo library, it seemed like there was no output on the motor controls at all.
VNH5019 allows you to control the motor speed by using pulse width modulation (PWM). Servos also use PWM to set a small motor into a single position and to keep it there. As it turns out, on Arduino Mega, PWM control has a few poorly documented features. Originally, my servo PWM inputs were connected to Arduino Mega pins 8 and 9 and the motor PWMs to pins 44 and 46. According to the official Arduino documentation, all these pins support PWM. However, what it fails to mention is that when you use the Servo library on pins 2 to 13 you lose PWM functionality on pins 44 to 46. This is because Servo library uses one of the ATmega2560 timers that also controls the PWM on pins 44 to 46, and naturally the timer can only handle one thing at a time.
With that in mind, I updated the wiring schematic. As you can see in the following picture, PWM for motors has been moved to pins 5 and 6. With this change, both the servos and the motors worked at the same time.
Figure 1. Fixed logic side schematic
Arduino sketch structure
When writing a program to control a system this complex, it’s a good idea to write down everything that needs to be taken into consideration. In case of ArduRover, this includes the following:
Motor control – this is probably the most important part since we obviously need to control where the robot is going.
Sensor control – we want to get some data from all the sensors attached to the robot.
Camera control – this includes taking and sending pictures, as well as turning the camera using the servo mount.
Data logging – we have a SD card on board and we can use that to log data from sensor and from GPS.
One potential issue is sending back image data. As we established in the JPEG Decoding on Arduino Tutorial, sending image data takes quite some time. If the robot suddenly decides to transmit the entire image at once, it would become unresponsive for quite a while. So, at each run through the main loop, we have to decide whether to transmit some part of the image, or respond to commands that arrive during the execution of the last loop.
Using the above requirements as a guideline, I came up with this diagram of program logic.
Figure 2. Arduino sketch logic diagram
During each iteration of the main loop function, Arduino will first update all current sensor data and log them to the SD card. This includes all the ROHM sensors, the GPS, and currents passing through each of the motor drivers. Then, it checks whether a new packet is received by the LoRa module. If it is, the command inside that packet will be executed and a response to it will be transmitted, again, using the LoRa module. If there is no new command received, the program will check if a picture needs to be transmitted. If it is, it will transmit one packet of image data. If there’s no on-going picture transmission, then this step is skipped. Finally, the program loops back to the beginning and the process is repeated.
It is important to realize that using this logic, processing new commands has higher priority than JPEG transmissions. This way, we can neatly avoid the issue I mentioned above the robot becoming unresponsive. The maximum delay between responses to commands is however long it takes to transmit one packet of image data.
Now that we have a general idea of the program logic, we need to take look at another crucial step: what will the commands look like?
Jan is currently studying Electrical Engineering at Brno University of Technology. He has many years of experience building projects using Arduino and other microcontrollers. His special interest lies in mechanical design of robotic systems.