Skip to content

Networking

For this week I am planning on securing the connection between my drone and the controller since I already have ESPNow running on both and have a stable connection. I wanna make the connection secure so no one can suddenly hijack the drone.

Group assignment

We used Irja's ESP and my ESP to communicate to each other using the I2C protocol. Henk also gave us his logic analyzer and told us to visualize the I2C and the SPI protocol. We first hooked up the I2C lanes to each other SDA - SDA, SCL-SCL. We used my old board for this. alt text

After testing and getting no signal for some reason I realized that I desoldered the components and all the bridge resistors to re-use them in another board. So there where no connections running anymore to the mcu. After that we directly hooked it up to the MCU using jumpers. alt text

After that we searched for code to communicate I2C between 2 esp's and found this site with exactly what we were looking for.

https://randomnerdtutorials.com/esp32-i2c-master-slave-arduino/

In there were 2 plug and play program to get communication running between the 2 ESP's.

When we had the correct wiring the code instantly worked as expected. My side. Secondary/child alt text

Irja's side. Main/parent alt text

Next up was SPI. For SPI we first tried to make the ESP act as a secondary SPI device but we couldn't figure out how to do that and online I also couldn't find anything. After a while Irja found a site that did have some code and documentation on how it worked.

https://circuits4you.com/2019/01/03/arduino-spi-communication-example/

When compiling the main side it worked fine but when compiling the secondary side it had errors that was out of my knowledge on how to fix. So I wen't rummaging through the SPI library in arduino but there wasn't much documentation on how it worked. And the official arduino documentation page gave an error 403.

alt text

After that we tried with an SPI screen and there we spent over 2.5 hours attempting to get it to work. Checking the wires multiple times. Trying another screen. Trying different example codes. We had everything correct according to the datasheet and the driver chip that was inside the board.

alt text

We also connected the serial monitor to it and read the data from it. It was sending a lot of commands so that was working but it is very hard to figure out if the commands are correct since they are machine instructions. So we ended the day there and got beers and a bar.

Individual Assignment

I kinda did my individual assignment in the programming week since I was both programming the handheld controller and the flight controller at the same time. During that week I also set up the communication between the 2 devices using ESPNow. ESPNow is a protocol skip a lot of OSI layers thus minimizing the overhead. It doesn't do handshakes so it kind of works like UDP. It's also peer to peer so it doesn't need any network infrastructure making it completely decentralized.

alt text Source: arduino

Encrypted ESPNow

To create secure ESPNow communication I used this tutorial.

The code stays the same except for a few extra variables added. Some things also change with registering peers to

// PMK and LMK keys
static const char* PMK_KEY_STR = "REPLACE_WITH_PMK_KEY";
static const char* LMK_KEY_STR = "REPLACE_WITH_LMK_KEY";


// Register the receiver board as peer
memcpy(peerInfo.peer_addr, receiverAddress, 6);
peerInfo.channel = 0;
//Set the receiver device LMK key
for (uint8_t i = 0; i < 16; i++) {
  peerInfo.lmk[i] = LMK_KEY_STR[i];
}

// Set PMK key
esp_now_set_pmk((uint8_t *)PMK_KEY_STR);

peerInfo.encrypt = true;

The PMK and LMK need to be exactly 16 bytes so to count to amount of bytes I used in my key I used this website. Most of the time you can go for each character is 1 byte. But there are also some online tools available. https://tools.smikkelbakje.nl/text-statistics or https://mothereff.in/byte-counter They should be the same on each board you wanna communicate with. The only flaw about this protocol is that the devices that receive decrypted messages still interpret them as if they where encrypted and they use the data inside them.

alt text

Sender
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-esp-now-encrypted-messages/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <esp_now.h>
#include <WiFi.h>

// REPLACE WITH THE RECEIVER'S MAC Address
uint8_t receiverAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

// PMK and LMK keys
static const char* PMK_KEY_STR = "REPLACE_WITH_PMK_KEY";
static const char* LMK_KEY_STR = "REPLACE_WITH_LMK_KEY";

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
    int counter;
    int x;
    int y;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// Counter variable to keep track of number of sent packets
int counter;

// Variable to save peerInfo
esp_now_peer_info_t peerInfo;

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void setup() {
// Init Serial Monitor
Serial.begin(115200);

// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);

// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
    Serial.println("There was an error initializing ESP-NOW");
    return;
}

// Set PMK key
esp_now_set_pmk((uint8_t *)PMK_KEY_STR);

// Register the receiver board as peer
memcpy(peerInfo.peer_addr, receiverAddress, 6);
peerInfo.channel = 0;
//Set the receiver device LMK key
for (uint8_t i = 0; i < 16; i++) {
    peerInfo.lmk[i] = LMK_KEY_STR[i];
}
// Set encryption to true
peerInfo.encrypt = true;

// Add receiver as peer        
if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
}

// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of transmitted packet
esp_now_register_send_cb(OnDataSent);
}
void loop() {
static unsigned long lastEventTime = millis();
static const unsigned long EVENT_INTERVAL_MS = 5000;
if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {
    lastEventTime = millis();

    // Set values to send
    myData.counter = counter++;
    myData.x = random(0,50);
    myData.y = random(0,50);

    // Send message via ESP-NOW
    esp_err_t result = esp_now_send(receiverAddress, (uint8_t *) &myData, sizeof(myData));
    if (result == ESP_OK) {
    Serial.println("Sent with success");
    }
    else {
    Serial.println("Error sending the data");
    }  
}
}
Receiver
    /*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-esp-now-encrypted-messages/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <esp_now.h>
#include <WiFi.h>

// REPLACE WITH YOUR MASTER MAC Address
uint8_t masterMacAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

// PMK and LMK keys
static const char* PMK_KEY_STR = "REPLACE_WITH_PMK_KEY";
static const char* LMK_KEY_STR = "REPLACE_WITH_LMK_KEY";

// Structure example to send data
// Must match the sender structure
typedef struct struct_message {
int counter; // must be unique for each sender board
int x;
int y;
} struct_message;

// Create a struct_message called myData
struct_message myData;

// Function to print MAC address on Serial Monitor
void printMAC(const uint8_t * mac_addr){
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
        mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.println(macStr);
}

// Callback function executed when data is received
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) {

Serial.print("Packet received from: ");
printMAC(mac_addr);

memcpy(&myData, incomingData, sizeof(myData));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Packet number: ");
Serial.println(myData.counter);
Serial.print("X: ");
Serial.println(myData.x);
Serial.print("Y: ");
Serial.println(myData.y);
}
void setup() {
// Init Serial Monitor
Serial.begin(115200);

// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);

// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
    Serial.println("There was an error initializing ESP-NOW");
    return;
}

// Set the PMK key
esp_now_set_pmk((uint8_t *)PMK_KEY_STR);

// Register the master as peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, masterMacAddress, 6);
peerInfo.channel = 0;
// Setting the master device LMK key
for (uint8_t i = 0; i < 16; i++) {
    peerInfo.lmk[i] = LMK_KEY_STR[i];
}
// Set encryption to true
peerInfo.encrypt = true;

// Add master as peer       
if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
}

// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}
void loop() {

}

The reason this can be done without low overhead is because some ESP models have hardware encryption accelerators build in for AES-128. and that's also the encryption what is used in this ESPNow protocol when enabled.

Charging my new batteries

This week I got my Li-Po batteries delivered.

alt text These batteries are amazing when you need lots of power quickly. But that also makes a bit more dangerous because they can discharge extremely quick. I already have a bit of experience with single cell li-po batteries. But not with multiple cell ones. To charge these you need a special charger that charges every battery cell separately otherwise a cell may go above 4.2 volts and get permanently damaged. We had one 5S Li-Po in the fablab but I didn't trust it because it had a nominal voltage of 11 volts. These cells also need to be checked every so often if the voltage doesn't drop too low.

alt text 5s cell with a nominal voltage of 11 volts. According to this guide a cell shouldn't go below 3.2 volts and any higher than 4.2 will significantly increase the risk of the battery bursting into flames.

3.2 * 5 cells = 15,6 volts the battery should be at a minimum of 15,6 volts to avoid damage to the cells. This battery was way under that (11 volts). So I ordered my own batteries because I didn't wanna work with a fire hazard.

Whenever I charged them I made sure to always be within eye sight of the batteries in case something happened. This is also described in the safety manuals.

alt text alt text

We also had a balanced Li-Po charger in the fablab. It is the IMAX B6 LiPro balance charger.

alt text

My LiPo batteries used XT-60 connectors and these weren't in the box. So I made my own connector.

alt text

The LiPo charger has a input range of 11-18 volts so I supplied that using my own power supply since there wasn't a charger in the box. alt text

When I first started charging I selected the LiPo charge function but that was wrong because it stopped as one cell reached 4.20 volts instead of all cells reaching 4.2. Then I started clicking through the menu's and found the balance function and that did charge them correctly. I also needed to configure how fast it charged. A good rule of thumb is 1C to 0,5C so 1x the capacity in MaH or half the capacity in 0,5 MaH

alt text

Whenever you are charging and press the right status button you can see the individual cell voltages.

alt text Here you see the battery I first charged normally without the balancing feature. Here you can see there are some big differences in the cells.

Sources

  • https://randomnerdtutorials.com/esp32-esp-now-encrypted-messages/
  • https://fpvfc.org/beginners-guide-to-lipo-batteries