Un programma per leggere i messaggi HID da un volante Logitech con Esp32S3 Otg Host
Un programma per leggere i messaggi HID da un volante Logitech con Esp32S3 Otg Host
SmartConfig e' un metodo per configurare il WiFi di una Esp32 utilizzando una app su smartphone scaricabile dagli store o personalizzabile tramite sorgenti (EspTouch, Github )
Esistono due versioni. In V1 vengono configurati inviando le credenziali di rete a tutti i dispositivi in ascolto
| V1 |
| V2 |
idf.py erase-flash
// Change from:
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );
// To:
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_V2) );
Ho provato Espnow, un protocollo per inviare brevi messaggi tra Esp32 e simili senza l'appoggio di un accesspoint
ho usato Idf 5.3.1 ed il programma di esempio
idf.py create-project-from-example "espressif/esp-now:get-started"
idf.py menuconfig
Example configuration
CONFIG_ESPNOW_CHANNEL → e.g. 1
CONFIG_ESPNOW_SEND_LEN → e.g. 200
CONFIG_ESPNOW_SEND_COUNT → e.g. 100
CONFIG_ESPNOW_SEND_DELAY → e.g. 1000 (ms)
se non si vuole un progetto di esempio si aggiunge il componente
idf.py add-dependency "espressif/esp-now"
l'esempio si puo' usare in assenza di wifi e si carica lo stesso firmware di esempio su entrambi i dispositivi. A seconda di send_param->magic=esp_random() viene scelto quale tra i due dispositivi e' il sender e quale e' il receiver
se si vuole forzare il ruolo si
#define FORCE_SENDER 1 // 1 = always sender, 0 = always receiver
sender.c (a seconda delle impostazione di peer mac la comunicazione puo' essere broadcast, specificando come Mac Address FF:FF:FF:FF:FF:FF od indirizzata specificatamente ad un dispositivo)
====================================
#include "esp_wifi.h"
#include "esp_now.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "string.h"
static const char *TAG = "ESPNOW_SENDER";
// 👉 Replace this with your receiver’s MAC address (check via `esp_read_mac`)
uint8_t peer_mac[] = {0x24, 0x6F, 0x28, 0xAA, 0xBB, 0xCC};
static void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) {
ESP_LOGI(TAG, "Send to %02X:%02X:%02X:%02X:%02X:%02X status: %s",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5],
status == ESP_NOW_SEND_SUCCESS ? "OK" : "FAIL");
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_wifi_init(&(wifi_init_config_t)WIFI_INIT_CONFIG_DEFAULT()));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_send_cb(send_cb));
esp_now_peer_info_t peer = {0};
memcpy(peer.peer_addr, peer_mac, 6);
peer.channel = 1;
peer.encrypt = false;
ESP_ERROR_CHECK(esp_now_add_peer(&peer));
const char *msg = "Hello ESPNOW";
while (1) {
esp_err_t res = esp_now_send(peer_mac, (uint8_t *)msg, strlen(msg));
if (res == ESP_OK) ESP_LOGI(TAG, "Message sent: %s", msg);
else ESP_LOGE(TAG, "Send error: %s", esp_err_to_name(res));
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
================================
receiver.c
=============================
#include "esp_wifi.h"
#include "esp_now.h"
#include "esp_log.h"
#include "nvs_flash.h"
static const char *TAG = "ESPNOW_RECEIVER";
static void recv_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len) {
ESP_LOGI(TAG, "From %02X:%02X:%02X:%02X:%02X:%02X | Len: %d | Data: %.*s",
info->src_addr[0], info->src_addr[1], info->src_addr[2],
info->src_addr[3], info->src_addr[4], info->src_addr[5],
len, len, data);
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_wifi_init(&(wifi_init_config_t)WIFI_INIT_CONFIG_DEFAULT()));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_recv_cb(recv_cb));
ESP_LOGI(TAG, "Receiver ready");
}
=================================
se si vuole mandare variabili di tipo differente nel pacchetto queste devono essere incluse in una struttura. La lunghezza dei pacchetti e' 250 bytes
=================================
#include "esp_wifi.h"
#include "esp_now.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
static const char *TAG = "ESPNOW_SENDER";
uint8_t peer_mac[] = {0x24, 0x6F, 0x28, 0xAA, 0xBB, 0xCC};
// Define your custom data structure
typedef struct {
uint32_t id;
float temperature;
float humidity;
int status;
char label[16];
} sensor_packet_t;
static void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) {
ESP_LOGI(TAG, "Send to %02X:%02X:%02X:%02X:%02X:%02X status: %s",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5],
status == ESP_NOW_SEND_SUCCESS ? "OK" : "FAIL");
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_wifi_init(&(wifi_init_config_t)WIFI_INIT_CONFIG_DEFAULT()));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_send_cb(send_cb));
esp_now_peer_info_t peer = {0};
memcpy(peer.peer_addr, peer_mac, 6);
peer.channel = 1;
peer.encrypt = false;
ESP_ERROR_CHECK(esp_now_add_peer(&peer));
sensor_packet_t pkt = {0};
pkt.id = 1;
while (1) {
pkt.temperature = 22.5 + (esp_random() % 100) / 10.0;
pkt.humidity = 60.0 + (esp_random() % 100) / 10.0;
pkt.status = esp_random() % 2;
strcpy(pkt.label, "Node_A");
esp_err_t res = esp_now_send(peer_mac, (uint8_t *)&pkt, sizeof(pkt));
if (res == ESP_OK)
ESP_LOGI(TAG, "Sent packet: id=%lu T=%.1f H=%.1f status=%d",
pkt.id, pkt.temperature, pkt.humidity, pkt.status);
else
ESP_LOGE(TAG, "Send error: %s", esp_err_to_name(res));
pkt.id++;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
====================
#include "esp_wifi.h"
#include "esp_now.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
static const char *TAG = "ESPNOW_RECEIVER";
typedef struct {
uint32_t id;
float temperature;
float humidity;
int status;
char label[16];
} sensor_packet_t;
static void recv_cb(const esp_now_recv_info_t *info, const uint8_t *data, int len) {
if (len != sizeof(sensor_packet_t)) {
ESP_LOGW(TAG, "Invalid packet size: %d", len);
return;
}
sensor_packet_t pkt;
memcpy(&pkt, data, sizeof(pkt));
ESP_LOGI(TAG, "From %02X:%02X:%02X:%02X:%02X:%02X | id=%lu | T=%.1f | H=%.1f | status=%d | label=%s",
info->src_addr[0], info->src_addr[1], info->src_addr[2],
info->src_addr[3], info->src_addr[4], info->src_addr[5],
pkt.id, pkt.temperature, pkt.humidity, pkt.status, pkt.label);
}
void app_main(void) {
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_wifi_init(&(wifi_init_config_t)WIFI_INIT_CONFIG_DEFAULT()));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_now_init());
ESP_ERROR_CHECK(esp_now_register_recv_cb(recv_cb));
ESP_LOGI(TAG, "Receiver ready");
}
Nell'SDK IDF ' contenuto un emulatore ESP32 QEmu
Non si possono simulare sensori e protocolli di trasmissione ma per cose semplici come REPL sulla seriale funziona piu' che bene
Non sono riuscito a fare partire l'emulatore con la finestra grafica
Mi sono comprato una scheda per pilotare un NEMA 17 dalla Cina ed e' arrivata senza istruzioni. Per fortuna dopo un po' di ricerca ho trovato lo schema di connessione che peraltro abbastanza semplice
I motori stepper si dividono in closed loop e open loop: nel primo caso nel motore c'e' un encoder ottico che verifica il corretto posizionamento del motore anche in presenza di carichi che limitino il motore non perdendo passi
Il modulo A4988 non arriva montato ...deve essere inserito facendo coincidere il pin VIN (ultimo in basso fila di sinistra del connettore rosso centrale)
![]() |
| https://docs.google.com/document/d/e/2PACX-1vTyiIMFXQ1cY5TMhOh_0EjdznmC3Nw6CplW7Xx8F61ogOaUpHVyuaXsqrWhIiuE8SjpbON_VzB-rk3R/pub |
Nello sketch che segue viene eseguita anche una accelerazione e decelerazione in partenza ed arrivo (valore di ramp), usando il delayMin viene gestita la velocita' (in pratica l'intervallo tra gli impulsi)
/*
* Stepper motor control with A4988 driver
* Includes acceleration/deceleration ramp
* Speed controlled by potentiometer on A0
*/
#define enablePin 6 // Enable (LOW = ON)
#define dirPin 4 // Direction
#define stepPin 5 // Step
#define potPin A0 // Potentiometer input
const int stepsPerRevolution = 200; // 1.8° per step motor
// Motion control variables
int delayMin; // Minimum delay between steps (fastest speed)
int delayMax = 2000; // Maximum delay (slowest speed)
int rampSteps = 50; // Number of steps to accelerate/decelerate
void setup() {
pinMode(enablePin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(potPin, INPUT);
digitalWrite(enablePin, LOW); // Enable driver
digitalWrite(dirPin, HIGH); // Initial direction
}
void loop() {
// Read potentiometer to set minimum delay (speed)
int potValue = analogRead(potPin);
delayMin = map(potValue, 0, 1023, 2000, 200); // slower -> faster
// Rotate forward
digitalWrite(dirPin, HIGH);
moveStepper(stepsPerRevolution, delayMin);
delay(500); // pause
// Rotate backward
digitalWrite(dirPin, LOW);
moveStepper(stepsPerRevolution, delayMin);
delay(500);
}
//--------------------------------------------
// Function to move stepper with accel/decel
//--------------------------------------------
void moveStepper(int steps, int delayMin) {
for (int i = 0; i < steps; i++) {
int currentDelay;
// Acceleration phase
if (i < rampSteps)
currentDelay = map(i, 0, rampSteps, delayMax, delayMin);
// Deceleration phase
else if (i > steps - rampSteps)
currentDelay = map(i, steps - rampSteps, steps, delayMin, delayMax);
// Constant speed
else
currentDelay = delayMin;
// Step pulse
digitalWrite(stepPin, HIGH);
delayMicroseconds(currentDelay);
digitalWrite(stepPin, LOW);
delayMicroseconds(currentDelay);
}
}
Attenzione: dopo aver flashato un programma che usa OTG si perde la seriale USB, il dispositivo deve essere quindi resettato prima di poter essere riprogrammato
Da notare che in StampS3 il tasto e' nascosto sotto l'adesivo
------------------------------------------------------------------
Ho provato ad usare la porta USB in modalita' OTG in ESP32-S3
Con il modulo Esp32-S3-Wroom esistono due porte USB di cui una di programmazione (a sinistra) ed una OTG (a destra)
Provando gli esempi in examples/peripherals/usb/device/hid tutto funziona, la scheda viene riconosciuta come un device. Il problema e' che usando gli esempi examples/peripherals/usb/host/hid il dispositivo viene flashato in modo correto ma non funziona
Dopo averle provate tutto ho trovato che la seconda porta USB non porta corrente ma solo dati ...in pratica in modalita' host il dispositivo nemmeno di accende/ Ho provato una alimentazione esterna sul pin 5V e GND ma niente
Usando pero' dispositivi che hanno una batteria interna (tipo Cardputer basato su Esp32S3) il programma funziona...non riesco a trovare lo schema elettrica del Wroom a questo punto credo che non ci sia proprio connessione elettrica di alimentazione sull'USB Otg ma solo D+ e D-
Anche la Esp32S3 Feather alimentata via LiPo non alimenta in modo efficace la USb (i 3.7 V della Lipo non passano attraverso un booster)
per fornire 5V alla porta USB (e per alimentare nello stesso tempo la scheda) si stacca la LiPo si alimenta dall'esterno sul pin USB +5V e sul pin GND
In altri schede si deve collegare due piazzole come nella scheda sottostante per avere alimentazione su OTG
Devo cerca di lavorare su spettri di riflettanza di plastica e la prima domanda e': quale sono le bande significative? Sono partito dal ...