Télécommande intelligente 2

De Wiki LOGre
Aller à : navigation, rechercher
Langue : Français

Projet réalisé par fma38.

En cours

Présentation

Réalisation d'une nouvelle télécommande intelligente pour piloter un hexapode. 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, et dispose d'un écran OLED 1,5".

Cahier des charges

  • 2 joysticks analogiques 3 axes + bouton + PCB (I²C)
  • 2 potentiomètre linéaires
  • 4 inverseurs
  • 6 boutons poussoirs (3 momentanés, 3 bistables)
  • écran OLED 128x128 (I²C)
  • 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 300x300mm.

RC 1.png RC 2.png RC 3.png

RC-4.jpg

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 :

Wipy3-pinout.png

 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)

Soft

Exemple de 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.