Télécommande intelligente 2
| Langue : | Français |
|---|
Projet réalisé par fma38.
Projet abouti
Présentation
Réalisation d'une nouvelle télécommande intelligente pour piloter un hexapode ou BB-8. Ce projet fait suite à ma première télécommande intelligente.
Cette fois, j'utilise des petits joysticks 3 axes à monter sur panneau. La partie électronique se fait via une carte WiPy 3.0 (à base d'ESP32), et intègre un écran OLED 1,5".
Le choix de la Wipy 3.0 s'est fait car c'est une des rares cartes à exposer toutes les pins des ADC. Car il faut savoir que lorsque le wifi est actif, l'ADC2 n'est plus utilisable ! Or, initialement, je comptais faire lire les joysticks et potentiomètres directement par l'ESP32, et sur les autres cartes, il n'y avait pas assez d'entrées. Depuis, j'ai développé un petit module monté à l'arrière des joysticks, qui permet de lire 4 ADC et 4 I/O, le tout via le bus I²C. Du coup, une carte ESP32 plus classique conviendrait. Ceci-dit, la Wipy 3.0 dispose d'un connecteur pour une antenne externe, que j'utilise, et qui permet d'étendre grandement la portée du wifi.
Cahier des charges
- 2 joysticks analogiques 3 axes + bouton + PCB I²C
- 2 potentiomètre linéaires
- 4 boutons inverseurs
- 6 boutons poussoirs (3 momentanés, 3 bistables)
- écran OLED 128x128 (SPI)
- roue codeuse + click central + 4 directions + led RGB (I²C)
- MPU6050 (I²C)
- communication UDP (bidirectionnelle) via wifi
- alimentation par Li-ion 18650 (chargeur intégré)
Réalisation
Le boîtier est bien sûr réalisé en impression 3D ; il est composé de 3 pièces seulement, mais nécessite une surface d'impression de 300x200mm.
Câblage
Tableau de correspondance des fils des joysticks 3 voies :
axe Z : blanc / noir (curseur) / rouge bouton : bleu / bleu
Câblage retenu sur la carte WiPy 3.0 :
5 / GPIO36 / AD1_0 / P13 : 6 / GPIO37 / AD1_1 / P14 : 7 / GPIO38 / AD1_2 / P15 : 8 / GPIO39 / AD1_3 / P16 : 10 / GPIO35 / AD1_7 / P17 : 11 / GPIO34 / AD1_6 / P18 : 12 / GPIO32 / AD1_4 / P19 : 13 / GPIO33 / AD1_5 / P20 : battery monitoring 15 / GPIO26 / / P21 : 14 / GPIO25 / / P22 : 17 / GPIO14 / / P23 : 39 / GPIO22 / / P11 : i2cNavKey interruption 20 / GPIO13 / / P10 : SCL 18 / GPIO12 / / P9 : SDA 22 / GPIO2 / / P8 : 38 / GPIO19 / / P7 : 16 / GPIO27 / / P6 : 34 / GPIO5 / / P5 : 21 / GPIO15 / / P4 : 24 / GPIO4 / / P3 : 23 / GPIO0 / / P2 : Bootloader switch 41 / GPIO1 / / P1 : TX0 (prog) 40 / GPIO3 / / P0 : RX0 (prog)
Logiciel
Exemple de code :
Cliquer sur le bouton à droite pour faire apparaître/disparaître le code...
#include "WiFi.h"
#include "AsyncUDP.h"
#include "ArduinoJson.h"
const char *ssid = "";
const char *password = "";
AsyncUDP udp;
StaticJsonDocument<300> jsonData;
const uint8_t X = A0;
const uint8_t Y = A1;
const uint8_t Z = A2;
const uint8_t A = A3;
const uint8_t U = A7;
const uint8_t V = A6;
const uint8_t W = A4;
const uint8_t B = A5;
const uint8_t IO0 = 26;
const uint8_t IO1 = 25;
void setup()
{
Serial.begin(115200);
pinMode(IO0, INPUT_PULLUP);
pinMode(IO1, INPUT_PULLUP);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed");
while (1) {
delay(1000);
}
}
if (udp.connect(IPAddress(192,168,0,2), 1234)) {
Serial.println("UDP connected");
udp.onPacket([](AsyncUDPPacket packet) {
Serial.print("UDP Packet Type: ");
Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
Serial.print(", From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.print(packet.remotePort());
Serial.print(", To: ");
Serial.print(packet.localIP());
Serial.print(":");
Serial.print(packet.localPort());
Serial.print(", Length: ");
Serial.print(packet.length());
Serial.print(", Data: ");
Serial.write(packet.data(), packet.length());
Serial.println();
// Reply to the client
//packet.printf("Got %u bytes of data", packet.length());
});
// Send unicast
udp.print("Hello Server!");
}
}
void loop()
{
String s;
jsonData["timeStamp"] = millis();
jsonData["analog"]["X"] = map(analogRead(X), 0, 4095, 0, 255);
jsonData["analog"]["Y"] = map(analogRead(Y), 0, 4095, 0, 255);
jsonData["analog"]["Z"] = map(analogRead(Z), 0, 4095, 0, 255);
jsonData["analog"]["A"] = map(analogRead(A), 0, 4095, 0, 255);
jsonData["analog"]["U"] = map(analogRead(U), 0, 4095, 0, 255);
jsonData["analog"]["V"] = map(analogRead(V), 0, 4095, 0, 255);
jsonData["analog"]["W"] = map(analogRead(W), 0, 4095, 0, 255);
jsonData["analog"]["B"] = map(analogRead(B), 0, 4095, 0, 255);
jsonData["digital"]["D0"] = digitalRead(IO0);
jsonData["digital"]["D1"] = digitalRead(IO1);
serializeJson(jsonData, s);
serializeJsonPretty(jsonData, Serial);
Serial.println();
udp.print(s.c_str());
delay(100);
}Annexes
Programmation de la WiPy 3.0
Cette carte nécessite une tension d'alimentation de 3,5V minimum, mais les I/O doivent être en 3,3V. Du coup, un câble FTDI 5V risque de griller les I/O, et un câble 3,3V ne pourra pas alimenter la carte. La solution est d'utiliser ce genre de module FTDI. En effet, on peut sélectionner la tension des I/O à 3,3V, et disposer quand même d'une alimentation 5V ; l'astuce consiste à ne pas utiliser la pin Vcc sur le connecteur arrière, qui sera donc à 3,3V, mais la pin marquée 5V, sur le connecteur latéral.
La WiPy 3.0, contrairement à la plupart de ses équivalentes, n'a pas de port USB intégré. La programmation se fait via TX0/RX0, une fois en mode bootloader. Pour ça, il faut démarrer l'ESP32 avec la pin GPIO0 à la masse. Une fois le programme téléchargé, il faut alors redémarrer l'ESP32 en laissant la pin GPIO0 en l'air. Si on utilise esptool.py pour programmer la carte, ce qui est le cas lorsqu'on dévelope via l'IDE Arduino, on peut automatiser la bascule sur le bootloader en câblant la pin DTR sur GPIO0 et RTS sur RST (EN de l'ESP32), comme indiqué sur cette page. Merci à Oliv' pour l'info.