Implement ESP-NOW support

This commit is contained in:
Oleg Kalachev
2026-05-18 14:17:13 +03:00
parent bd2b1bd5de
commit 9ac57b246b
5 changed files with 136 additions and 20 deletions
+6 -2
View File
@@ -10,6 +10,7 @@
extern const int MOTOR_REAR_LEFT, MOTOR_REAR_RIGHT, MOTOR_FRONT_RIGHT, MOTOR_FRONT_LEFT; extern const int MOTOR_REAR_LEFT, MOTOR_REAR_RIGHT, MOTOR_FRONT_RIGHT, MOTOR_FRONT_LEFT;
extern const int RAW, ACRO, STAB, AUTO; extern const int RAW, ACRO, STAB, AUTO;
extern const int W_AP, W_STA, W_ESPNOW;
extern float t, dt, loopRate; extern float t, dt, loopRate;
extern uint16_t channels[16]; extern uint16_t channels[16];
extern float controlTime; extern float controlTime;
@@ -45,6 +46,7 @@ const char* motd =
"wifi - show Wi-Fi info\n" "wifi - show Wi-Fi info\n"
"ap <ssid> <password> - setup Wi-Fi access point\n" "ap <ssid> <password> - setup Wi-Fi access point\n"
"sta <ssid> <password> - setup Wi-Fi client mode\n" "sta <ssid> <password> - setup Wi-Fi client mode\n"
"espnow <mac> - setup ESP-NOW peer\n"
"mot - show motor output\n" "mot - show motor output\n"
"log [dump] - print log header [and data]\n" "log [dump] - print log header [and data]\n"
"cr - calibrate RC\n" "cr - calibrate RC\n"
@@ -143,9 +145,11 @@ void doCommand(String str, bool echo = false) {
} else if (command == "wifi") { } else if (command == "wifi") {
printWiFiInfo(); printWiFiInfo();
} else if (command == "ap") { } else if (command == "ap") {
configWiFi(true, arg0.c_str(), arg1.c_str()); configWiFi(W_AP, arg0.c_str(), arg1.c_str());
} else if (command == "sta") { } else if (command == "sta") {
configWiFi(false, arg0.c_str(), arg1.c_str()); configWiFi(W_STA, arg0.c_str(), arg1.c_str());
} else if (command == "espnow") {
configWiFi(W_ESPNOW, arg0.c_str(), arg1.c_str());
} else if (command == "mot") { } else if (command == "mot") {
print("front-right %g front-left %g rear-right %g rear-left %g\n", print("front-right %g front-left %g rear-right %g rear-left %g\n",
motors[MOTOR_FRONT_RIGHT], motors[MOTOR_FRONT_LEFT], motors[MOTOR_REAR_RIGHT], motors[MOTOR_REAR_LEFT]); motors[MOTOR_FRONT_RIGHT], motors[MOTOR_FRONT_LEFT], motors[MOTOR_REAR_RIGHT], motors[MOTOR_REAR_LEFT]);
+4 -1
View File
@@ -10,7 +10,7 @@ extern int channelZero[16];
extern int channelMax[16]; extern int channelMax[16];
extern int rollChannel, pitchChannel, throttleChannel, yawChannel, armedChannel, modeChannel; extern int rollChannel, pitchChannel, throttleChannel, yawChannel, armedChannel, modeChannel;
extern int rcRxPin; extern int rcRxPin;
extern int wifiMode, udpLocalPort, udpRemotePort; extern int wifiMode, wifiLongRange, udpLocalPort, udpRemotePort, espnowChannel;
extern float rcLossTimeout, descendTime; extern float rcLossTimeout, descendTime;
extern int voltagePin; extern int voltagePin;
extern float voltageScale; extern float voltageScale;
@@ -112,6 +112,9 @@ Parameter parameters[] = {
{"WIFI_MODE", &wifiMode}, {"WIFI_MODE", &wifiMode},
{"WIFI_PORT_LOC", &udpLocalPort}, {"WIFI_PORT_LOC", &udpLocalPort},
{"WIFI_PORT_REM", &udpRemotePort}, {"WIFI_PORT_REM", &udpRemotePort},
{"WIFI_LONG_RANGE", &wifiLongRange},
// espnow
{"ESPNOW_CHANNEL", &espnowChannel},
// mavlink // mavlink
{"MAV_SYS_ID", &mavlinkSysId}, {"MAV_SYS_ID", &mavlinkSysId},
{"MAV_RATE_SLOW", &telemetrySlow.rate}, {"MAV_RATE_SLOW", &telemetrySlow.rate},
+51 -17
View File
@@ -1,82 +1,116 @@
// Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com> // Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com>
// Repository: https://github.com/okalachev/flix // Repository: https://github.com/okalachev/flix
// Wi-Fi communication // Wi-Fi and ESP-NOW communication
#include <WiFi.h> #include <WiFi.h>
#include <WiFiAP.h> #include <WiFiAP.h>
#include <WiFiUdp.h> #include <WiFiUdp.h>
#include <MacAddress.h>
#include <ESP32_NOW_Serial.h>
#include "Preferences.h" #include "Preferences.h"
extern Preferences storage; // use the main preferences storage extern Preferences storage; // use the main preferences storage
const int W_DISABLED = 0, W_AP = 1, W_STA = 2; const int W_DISABLED = 0, W_AP = 1, W_STA = 2, W_ESPNOW = 3;
int wifiMode = W_AP; int wifiMode = W_AP;
int wifiLongRange = 0;
int udpLocalPort = 14550; int udpLocalPort = 14550;
int udpRemotePort = 14550; int udpRemotePort = 14550;
int espnowChannel = 6;
IPAddress udpRemoteIP = "255.255.255.255"; IPAddress udpRemoteIP = "255.255.255.255";
WiFiUDP udp; WiFiUDP udp;
ESP_NOW_Serial_Class espnow(NULL, 0, WIFI_IF_AP);
void setupWiFi() { void setupWiFi() {
print("Setup Wi-Fi\n"); print("Setup Wi-Fi\n");
WiFi.enableLongRange(wifiLongRange);
if (wifiMode == W_AP) { if (wifiMode == W_AP) {
WiFi.softAP(storage.getString("WIFI_AP_SSID", "flix").c_str(), storage.getString("WIFI_AP_PASS", "flixwifi").c_str()); WiFi.softAP(storage.getString("WIFI_AP_SSID", "flix").c_str(), storage.getString("WIFI_AP_PASS", "flixwifi").c_str());
udp.begin(udpLocalPort);
} else if (wifiMode == W_STA) { } else if (wifiMode == W_STA) {
WiFi.begin(storage.getString("WIFI_STA_SSID", "").c_str(), storage.getString("WIFI_STA_PASS", "").c_str()); WiFi.begin(storage.getString("WIFI_STA_SSID", "").c_str(), storage.getString("WIFI_STA_PASS", "").c_str());
} else { udp.begin(udpLocalPort);
return; } else if (wifiMode == W_ESPNOW) {
WiFi.mode(WIFI_AP);
WiFi.setChannel(espnowChannel);
espnow.setChannel(espnowChannel);
espnow.addr(MacAddress(storage.getString("ESPNOW_PEER_MAC", "").c_str()));
espnow.begin();
} }
WiFi.setSleep(false); // disable power save WiFi.setSleep(false); // disable power save
udp.begin(udpLocalPort);
} }
void sendWiFi(const uint8_t *buf, int len) { void sendWiFi(const uint8_t *buf, int len) {
if (espnow) {
espnow.write(buf, len);
return;
}
if (WiFi.softAPgetStationNum() == 0 && !WiFi.isConnected()) return; if (WiFi.softAPgetStationNum() == 0 && !WiFi.isConnected()) return;
udp.beginPacket(udpRemoteIP, udpRemotePort); udp.beginPacket(udpRemoteIP, udpRemotePort);
udp.write(buf, len); udp.write(buf, len);
udp.endPacket(); udp.endPacket();
} }
int receiveWiFi(uint8_t *buf, int len) { int receiveWiFi(uint8_t *buf, int len) {
if (espnow) {
return espnow.read(buf, len);
}
if (WiFi.softAPgetStationNum() == 0 && !WiFi.isConnected()) return 0; if (WiFi.softAPgetStationNum() == 0 && !WiFi.isConnected()) return 0;
udp.parsePacket(); udp.parsePacket();
if (udp.remoteIP()) udpRemoteIP = udp.remoteIP(); if (udp.remoteIP()) udpRemoteIP = udp.remoteIP();
return udp.read(buf, len); return udp.read(buf, len);
} }
void printWiFiInfo() { void printWiFiInfo() {
if (WiFi.getMode() == WIFI_MODE_AP) { if (espnow) {
print("Mode: ESP-NOW\n");
print("ESP-NOW version: %d\n", ESP_NOW.getVersion());
print("Max packet size: %d\n", ESP_NOW.getMaxDataLen());
print("MAC: %s\n", WiFi.softAPmacAddress().c_str());
print("Peer MAC: %s\n", MacAddress(espnow.addr()).toString().c_str());
print("Channel: %d\n", espnow.getChannel());
} else if (WiFi.getMode() == WIFI_MODE_AP) {
print("Mode: Access Point (AP)\n"); print("Mode: Access Point (AP)\n");
print("MAC: %s\n", WiFi.softAPmacAddress().c_str()); print("MAC: %s\n", WiFi.softAPmacAddress().c_str());
print("SSID: %s\n", WiFi.softAPSSID().c_str()); print("SSID: %s\n", WiFi.softAPSSID().c_str());
print("Password: ***\n"); print("Password: ***\n");
print("Channel: %d\n", WiFi.channel());
print("Clients: %d\n", WiFi.softAPgetStationNum()); print("Clients: %d\n", WiFi.softAPgetStationNum());
print("IP: %s\n", WiFi.softAPIP().toString().c_str()); print("IP: %s\n", WiFi.softAPIP().toString().c_str());
print("Remote IP: %s\n", udpRemoteIP.toString().c_str());
} else if (WiFi.getMode() == WIFI_MODE_STA) { } else if (WiFi.getMode() == WIFI_MODE_STA) {
print("Mode: Client (STA)\n"); print("Mode: Client (STA)\n");
print("Connected: %d\n", WiFi.isConnected()); print("Connected: %d\n", WiFi.isConnected());
print("MAC: %s\n", WiFi.macAddress().c_str()); print("MAC: %s\n", WiFi.macAddress().c_str());
print("SSID: %s\n", WiFi.SSID().c_str()); print("SSID: %s\n", WiFi.SSID().c_str());
print("Password: ***\n"); print("Password: ***\n");
print("IP: %s\n", WiFi.localIP().toString().c_str()); print("Channel: %d\n", WiFi.channel());
print("RSSI: %d dBm\n", WiFi.RSSI()); print("RSSI: %d dBm\n", WiFi.RSSI());
print("IP: %s\n", WiFi.localIP().toString().c_str());
print("Remote IP: %s\n", udpRemoteIP.toString().c_str());
} else { } else {
print("Mode: Disabled\n"); print("Mode: Disabled\n");
return;
} }
print("Channel: %d\n", WiFi.channel());
print("Remote IP: %s\n", udpRemoteIP.toString().c_str());
print("MAVLink connected: %d\n", mavlinkConnected); print("MAVLink connected: %d\n", mavlinkConnected);
} }
void configWiFi(bool ap, const char *ssid, const char *password) { void configWiFi(int mode, const char *first, const char *second) {
if (ap) { if (mode == W_AP) {
storage.putString("WIFI_AP_SSID", ssid); storage.putString("WIFI_AP_SSID", first);
storage.putString("WIFI_AP_PASS", password); storage.putString("WIFI_AP_PASS", second);
} else { } else if (mode == W_STA) {
storage.putString("WIFI_STA_SSID", ssid); storage.putString("WIFI_STA_SSID", first);
storage.putString("WIFI_STA_PASS", password); storage.putString("WIFI_STA_PASS", second);
} else if (mode == W_ESPNOW) {
storage.putString("ESPNOW_PEER_MAC", first);
} }
print("✓ Reboot to apply new settings\n"); print("✓ Reboot to apply new settings\n");
} }
+3
View File
@@ -0,0 +1,3 @@
# ESPNOW-proxy
Proxy sketch for using ESP-NOW MAVLink connection with Flix drone.
+72
View File
@@ -0,0 +1,72 @@
// Copyright (c) 2026 Oleg Kalachev <okalachev@gmail.com>
// Repository: https://github.com/okalachev/flix
// Proxy for ESP-NOW connection
#include <WiFi.h>
#include <ESP32_NOW_Serial.h>
#include <MacAddress.h>
#include <MAVLink.h>
const int CHANNEL = 6;
ESP_NOW_Serial_Class espnow(NULL, CHANNEL, WIFI_IF_AP);
MacAddress peerMac;
volatile bool peerFound = false;
void onNewPeer(const esp_now_recv_info_t *info, const uint8_t *data, int len, void *arg) {
peerMac = info->src_addr;
peerFound = true;
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.setSleep(false);
WiFi.setChannel(CHANNEL);
// while (!WiFi.AP.started()) {
// delay(100);
// }
ESP_NOW.onNewPeer(onNewPeer, NULL);
ESP_NOW.begin();
while (!peerFound) {
Serial.printf("MAC: %s, waiting for peer...\n", WiFi.softAPmacAddress().c_str());
delay(1000);
}
Serial.printf("Peer found: %s\n", peerMac.toString().c_str());
espnow.addr(peerMac);
espnow.setChannel(CHANNEL);
espnow.begin();
}
void loop() {
uint8_t buf[5000];
// Send from serial to ESP-NOW
while (Serial.available() > 0) {
int b = Serial.read();
if (b < 0) {
break;
}
mavlink_message_t msg;
mavlink_status_t status;
if (mavlink_parse_char(MAVLINK_COMM_0, (uint8_t)b, &msg, &status)) {
int len = mavlink_msg_to_send_buffer(buf, &msg);
// ESP_NOW.write(buf, len);
espnow.write(buf, len);
// espnow.send(buf, len);
// esp_now_send(peerMac, buf, len);
}
}
// Send from ESP-NOW to serial
int len = espnow.read(buf, sizeof(buf));
if (len > 0) {
Serial.write(buf, len);
}
}