Hello, everyone. I would like to present a project that I have been working on for some time. This project has a main goal which is to be able to transfer an APJ firmware via OTA with the help of the ESP8266 and do a real remote upload. In the Ardupilot field this is normally done via USB cable using programs like Mission Planner or the python script :
“uploader.py”
These solutions work very well nowadays but unfortunately have limitations when it comes to convenience and speed. For my example, working with many drones, I need in case of new firmware versions to make a mass upload in the shortest time possible and here is where the OTA comes to help; with a solution like the OTA programming i can make a mass upload in a short time thanks to the help of the wifi network created by esp8266.
THE PROJECT :
Let’s move on to what I was able to do during this time .
First of all I had to overcome several problems to start just trying an OTA idea . In my hardware the esp8266 (wroom 2) is able to communicate with the FC via TX and RX through the UART 2 port, this connection obviously makes it capable of UDP communication with Mission Planner, Mavproxy …
The first thing I did was to modify the hwdef-bl.dat so that the BOOTLOADER was able to communicate through the UART2 port and with a baudrate of 921600(Normally the bootloader works at 115200 but this created problems for communication with the esp8266 that works instead at 921600, so I decided to adapt the bootlader to the baudrate of the esp).The last change concerns the SERIAL_ORDER or the order of the serial ports that the bootloader decides at boot, I put the USART2 as the first port .
Below are the changes to hwdef-bl.dat:
#CHANGE BAUDRATE
define BOOTLOADER_BAUDRATE 921600
# order of UARTs (and USB) for bootloading
SERIAL_ORDER USART2 OTG1
# USART2
PD5 USART2_TX USART2
PD6 USART2_RX USART2
The second SET of changes I had to do was mainly inside the original mavesp8266 firmware using the latest pull at this link:
My firmware modifications mainly include the activation of the raw mode of esp8266 (and the creation of various functions to control the status of the raw mode) at the arrival of a certain mavlink packet, in particular the message REBOOT_SHUTDOWN with param1=3
https://mavlink.io/en/messages/common.html#MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN
Here are the changes made to the esp8266 firmware:
void #function for enter in raw mode
MavESP8266Component::_enterRawMode(mavlink_command_long_t *cmd, uint8_t compID)
{
if (_in_raw_mode) {
return;
}
if (cmd) {
getWorld()->getLogger()->log("Raw mode enabled (cmd %d %d)\n", cmd->command, compID);
} else {
getWorld()->getLogger()->log("Raw mode enabled\n");
}
_in_raw_mode = true;
_in_raw_mode_time = 0;
}
////////////////////////////////
bool
MavESP8266Component::inRawMode() { #while the esp8266 is in raw mode
// switch out of raw mode when not needed anymore
if (_in_raw_mode_time > 0 && millis() > _in_raw_mode_time + 5000) {
_exitRawMode();
}
return _in_raw_mode;
}
///////////////////////////////
void
MavESP8266Component::_exitRawMode()
{
if (!_in_raw_mode) {
_in_raw_mode_time = 0;
return;
}
_in_raw_mode = false;
_in_raw_mode_time = 0;
raw=false;
getWorld()->getLogger()->log("Raw mode disabled\n");
// Restore original baud rate
Serial.end();
Serial.begin(getWorld()->getParameters()->getUartBaudRate());
}
////////////////////////////////////
// recognize FC reboot to bootloader command and switch to raw mode for bootloader protocol to work
if(cmd->param1 == 3)
{ //change param1>0 to param1==3
_enterRawMode(cmd, compID);
return false;
}
Having modified the esp firmware in this way I’m able to activate the raw mode when the reboot_shutdown package arrives. Obviously the raw mode is needed to allow low level communication between the esp8266 and the FC during the bootloader phase.
First tests:
Created a spartan connection between esp8266 and bootloader I started to make the first tests that included sending a set of bytes useful to show the response of the FC and understand if there was a stable connection between the two. I worked completely on ubuntu environment and my idea was the following :
- Using a socat connection to create a virtual serial port with a direct udp connection to the network created by the esp8266
socat pty,rawer,link=/tmp/udp-serial-bridge udp4-datagram:192.168.4.1:14555,bind=:14550
- Activate a simple tcdumper to display the traffic via serial port
sudo tcpdump -i enp0s3 -X host 192.168.4.1 and udp
- Test a first handshake between mavesp8266 and FC by sending GET_SYNC+EOC bytes : 0X21 0X30
echo "21 20" | xxd -r -p | socat - udp:192.168.4.1:14555
The test started by connecting to the Access point created by the esp8266 and then creating the virtual port/udp . Then I had to send a mavlink command to send the FC into bootloader - and send the esp into raw mode , remember the changes made to the esp firmware - in this situation I started the tcpdumper and then sent the set of bytes 0x21 and 0x20 . With this set of packets the FC should respond with 0x12 0x20 indicating the success of communication.
The result was very satisfactory in fact on the tcdumper I saw both the outgoing and incoming bytes, confirming that the virtual connection between esp8266 and FC had been successful!
How to transfer apj and upload file via OTA and some errors :
After making sure that the connection was correct I asked myself how and what to use to load the apj firmware and do all the procedure that is normally done:
erasing , programming , verifing
So I decided to use px_uploader.py, a slightly modified python script useful to upload apj firmware via usb.
Being a script designed to work via usb I had to modify it with a kind of “retry” regarding the sending of packets, since in a wifi connection the loss of information is more frequent (if required I will post the changes to this script). At the end of all I tried to use the script starting it with this line :
python3 px_uploader.py --baud-bootloader 921600 --port /tmp/udp-serial-bridge firmware.apj
After a few failed attempts I managed to make the first OTA! The time to complete the operation took about 1 minute and a half, but it worked perfectly.
Being a real hack, however, still has some errors that I report below :
"CRC (Cyclic redundancy check) FAILED" -> is an error probably due to a writing problem during the programming phase I believe that it is due to the verification phase that realizes that the writing previously made during programming does not match the one of the verification
"BOOTLOADER OPERATION FAILED" ->is an error due to failed communication between the bootloader and the script.
THIS PROBLEM DOESN'T HAVE A MESSAGE BUT FREQUENTLY THE PROGRAMING BLOCKS A T 83 %
CONCLUSION AND REQUEST FOR HELP OR ADVICE
A big thank you goes @ntamas for helping me with most of the projects and issues on here
This method works even if it has its problems and limitations today, one of these is obviously the limitation of being able to make the ota for one drone at a time, which totally blocks the final purpose of my project.
I ask help therefore to you for of the councils on like realizing a system, that it is also to command line that it is in a position in fact to managing a flow of information UDP with more routines and with a system similar to that one of the today uploader.py script using trio (Using an asynchronous solution with multiple coroutines) from python script maybe. I ask also to the maximum connoisseurs as @tridge to say their opinion and to give advices about this project. Thanks for reading the post ! Davide