Projekte - ferngesteuerter Rasenmäher mit ESPNow...

Hier mal wieder ein kleines Spielprojekt - ich habe auf in einer bekannten Web-Plattform ein kleines "Kettenfahrwerk mit Gleichstrom-Motoren"  entdeckt - da bin ich "schwach geworden"... Und irgendwie hatte ich auch mal wieder Lust, etwas "Überschaubares"  und vor Allem etwas mit 3D-Druck zu bauen...

 
Übersicht:
 
Einführung...
Hardware - eingekauft...
Tank Chassis...
Motor-Treiber / H-Brücke...
DC-DC-Wandler...
Joystick's...
Hardware - aktuelle Lösung / Anpassungen...
Tank Chassis...
Motor-Treiber / DC-DC-Wandler...
Steuerungskonsole...
Joystick's...
Elektronik...
Fahrzeug - Motor-Treiber...
Fahrzeug - Mähwerk...
Konsole - Joystick's...
Konsole - Druckschalter...
Konsole - Drehzahlsteuerung Mähwerk...
Software...
Konsole...
Fahrzeug...
Vorschau...
Mai 2025 - Update - Ketten...
Mai 2025 - Update - OTA - Softwareaktualisierung...

 

Einführung...

Seit ich im Web erste Beiträge über die ESP-Now-Funktionalitäten der ESP32 gelesen hatte, habe ich mich gefragt ob man diese Form des Datenaustausches zwischen den Kleinstcomputern auch sinnvoll und "gebrauchsfähig" für eine "zeitechte" Fernsteuerung eines Gerätes nutzen kann.

Bisher hatte ich meine ESP-Module zwar über WLAN und eine vom jeweiligen Rechner selbst generierte "Webseite" mit entsprechenden Verzögerungen ferngesteuert, jetzt jedoch müssten Anweisung und Ausführung ja doch relativ "zeitnah" erfolgen.

Und da ich immer einen motivierenden Hintergrund - "Sinn ? " - für meine Basteleien brauche, kam ich auf die Idee einen kleinen "Rasenmäher" zu bauen. Mit diesem kann ich dann unter den Solarpaneelen im Garten mähen, die stehen auf dem Rasen und mit den normalen Geräten komme ich da schlecht dran bzw. drunter. Und ich kann dann "mit einem Bier" daneben sitzen und dem Gerät zuschauen...

hier im " fast arbeitsfähigen Zustand"....

Also einen "mehr oder weniger" sinnvollen Zweck hatte ich somit gefunden...und eventuell kann ich es später ja noch automatisieren - ich denke da an meine Versuche zum GPS bzw. zu den Abstands-Sensoren...

Ausserdem entstehen bei einem kompletten Projekt auch immer technische Fragen und erfordern Lösungen, was ja den eigentlichen Spass bei der Sache macht = "der Weg ist das Ziel !!" 

 

Ist mir zu kompliziert..... =>.... zurück zur Startseite

Hardware - eingekauft...

Obwohl ich normalerweise versuche, alle Konstruktionen und elektronischen Regelungen selbst zu entwerfen und zu bauen, habe ich dieses Mal mehrere Produkte auf den bekannten WebPlattformen "zugekauft".

Leider darf ich aus Urheberrechtsgründen nicht einfach die - schon vorbereiteten Bilder der Händler von der Web-Plattform nutzen - und muss mir daher auf andere Weise helfen  ( und blöderweise sind die zugekauften Bauteile bereits verbaut.... ).

Besorgt habe ich mir....

 

Einen alten, aber noch tüchtigen Akku von einem 20 Volt-Rasentrimmer hatte ich noch rumliegen, daher habe ich den Motor gleich für 24 Volt gekauft.  Lt. WebRecherchen sollte ein Trimmer-Motor ca. 7000-8000 U/min haben - runterregeln kann ich es später immer noch.

...... hier noch Photo von Motor und Akku....

Durch Zufall habe ich im Web so kleine "Plastik-Trimmer-Messer" gefunden (Durchmesser Schneidbereich dann ca. 14cm), dies ist für mich günstiger als ein klassischer "Drahtkopf" - rein von der notwendigen 3D-Konstruktion.

diese Plastikmesser gibt es zu 60 Stk. für ca. 7 € im Web...

 

Tank Chassis...

Als Basis habe ich mir ein "vorgefertigtes" Set bestellt - ca. 19x16cm im Grundriss und ca. 6cm hoch. Gefertigt aus Blech inkl. 2 DC-Motoren 12 Volt, Ketten und Laufrollen - da es direkt aus FernOst kommt, dauert die Lieferung etwas.

Leider hat der Konstrukteur nicht so ganz aufgepasst, wenn man die Laufräder entsprechend Anleitung und vorgefertigten Löchern montiert - stehen die Ketten in Fahrtrichtung längs versetzt... An der "richtigen" Stelle" für ein symetrisches Bild im Grundriss ist zwar auch eine Bohrung, allerdings mit zu grossem Durchmesser. 

O.K. auch ich muss meine Prototypen i.d. Regel mehrfach drucken, um Fehler auszumerzen - allerdings werden meine Fehler nicht produziert und verkauft...

Aber in meiner "Grabbelkiste" habe ich aber noch einige alte gedruckte Buchsen gefunden, welche ich hier als Ausgleichsstücke verwenden konnte - jetzt passt es.

Da jedoch die beiden Motoren im Grundriss versetzt sind, wird immer eine Kette gezogen und die andere Kette geschoben - bei dem unvermeidlichen Kettendurchhang müssen sich die Ketten dann erst ausgleichen - sprich das Chassis fährt immer erst etwas "quer"...

Darum sind bei Kettenfahrzeugen üblicherweise die beiden Motoren immer an der gleichen Stelle im Chassis...

 

Motor-Treiber / H-Brücke...

Dieses Board stellt die elektronische Antriebsregelung für 2 DC-Gleichstrom-Motoren ODER 1 Steppermotor ( dort werden ja 2 interne Stromkreise gesteuert siehe mein Beitrag zu Steppermotoren ) zur Verfügung.

Es hat neben dem Versorgungseingang noch 2 Ausgänge zu den Motoren und bietet zusätzlich einen Ausgang 5 Volt z.B. als Versorgung des steuerenden Rechners - hier mein ESP32.. Dieser Ausgang ist allerdings nur bei einer Versorgungsspannung für das Board bis 12 Volt nutzbar, bei grösseren Spannungen muss er mittels Jumper deaktiviert werden.

Die Ansteuerung erfolgt - je Kanal - durch 3 Pin's  ( 2x Drehrichtungsdefinition und 1x Enable = An/Aus-Definition ).  Der Enable-Pin kann durch einen Jumper auf dem Board direkt aktiviert werden (Vollgas) - oder aber vom ansteuernden Rechner dann mit einem PWM-Signal belegt werden (PWM - Pulsweitenmodulation = steuerbare Frequenz ). In diesem Falle lässt sich die Drehgeschwindigkeit steuern.

Also erst mal kein "Hexenwerk" - normalerweise würde ich mir das mit einem MosFet auch selbst bauen..

 

DC-DC-Wandler...

Da ich mein System aus einem 20 Volt-Akku speisen will, muss ich für die Versorgung der vorgenannten H-Brücke und somit der Fahrmotoren ja 12 Volt bereitstellen, dies erfolgt unkompliziert mit diesem Wandlerboard.

Da ich keine Angaben zum Stromverbrauch der beiden Fahrmotoren hatte - und der ESP nimmt allen schon ca. 2 A -  habe ich mit hier für die Variante mit 0-30 Volt und max. 12 A entschieden (das ist aber preislich kaum ein Unterschied).

Die Justierung ist ebenfalls recht einfach (wenn man nicht grad die Pole vertauscht und somit das Board "grillt"). Stromquelle anschliessen und auf dem Ausgang ein Multimeter. Dann an dem kleinen blauen Regler drehen ( gegen Uhrzeigersinn => mehr Ausgangsspannung ) bis die gewünschte Spannung eingestellt ist ( fleissig drehen...).

Das Board sollte dann auch unter Last diese Spannung halten.

 

Joystick's...

Nun ja... diese Teile werden im Web im Bundle oft für 5 Euronen angeboten - sprich jedes Teil kostet ca. 1 Euro. Dementsprechend scheint auch die Qualität zu sein. Bei Anschluss an meinem ESP32 und dem Auslesen gemäss der Anleitungen im Web mit dem internen ADC-Wandler (Messwandler) ergaben sich völlig unbrauchbare Werte.

Die Nullstellung (der Wandler gibt den gemessenen Spannungswert als digitale Zahl von 0-4095 aus) weicht teilweise um mehrere hundert digitale Stellen vom Mittelwert 4095/2 = 2047 ab, desweiteren ändern sich die Messwerte beim "Kippen" des Reglers nicht wirklich gleichmässig, eine echte Ansteuerung für den späteren Fahrbetrieb lässt sich so nur schlecht realisieren...

 

Ist mir zu kompliziert..... =>.... zurück zur Startseite

 

Hardware - aktuelle Lösung / Anpassungen...

Die gekauften Teile müssen erst an die geplante Nutzung angepasst werden, es sind Zusatzbauteile notwendig und natürlich brauchen wir auch eine Steuerungskonsole.

Also habe ich mal wieder mein Sketchup und die 3D-Drucker angeworfen...die gesammelten Teil-Konstruktionen stelle ich am Ende dann als eine Sammel-Sketchup-Datei zur Verfügung....

Wie immer gibt es viele Zwischenstufen der Entwicklung, mal hat die Druckqualität des 3D-Druckers (Thema Schwinden) maszlich nicht gepasst, auch hing das Mähwerk bei ersten Versuchen einfach zu tief....und manchmal waren es einfach Denkfehler in den Funktionen..

 

Tank Chassis...

Wie schon erwähnt macht der Kettendurchhang zusammen mit den im Grundriss versetzten Motoren Probleme bei Anfahren bzw. Richtungswechsel - das Gerät dreht sich immer erst mal im Grundriss. Es muss also eine Lösung her, die Ketten so vorzuspannen, das dieses Verhalten minimiert wird....

Gleichzeitig muss die Vorspannung etwas gefedert werden, damit bei Fahrt über unebenen Grund die Kette auch nachgeben kann - sprich "die Kiste nicht kippelt"..

in den Schlitz kommt eine Feder und eine lange M3-Schraube als Endanschlag, in die Achsbuchse wird ein Gewindestab M5 eingesetzt..

Auch für die Befestigung von Mähwerk, Motor und Akku werden entsprechende Bauteile benötigt, ausserdem ist es für die Installation der Elektronik auf der Grundplatte des Chassis aktuell viel zu eng.

hier mal mit "Zwischenstufen" - die letztendlich genutzten Teile haben den roten Punkt....

 

Das Ganze sieht dann so aus...

Für die Befestigung der Messer habe ich mir einen Messerkopf konstruiert, die Buchse habe ich mit einem 5mm Bohrer noch feingebohrt, aktuell hält er an der Motorwelle sogar ohne Befestigungsschrauben (für die ich aber bereits Löcher vorgesehen habe)..

am Wellenschaft müssten ggf. dann noch M5-Gewinde für Befestigungsschrauben geschnitten werden

 

Motor-Treiber / DC-DC-Wandler...

Hier war der Aufwand überschaubar - ich habe lediglich einige Halter für die Platinen konstruiert, die ich auf die Grundplatte des Chassis geklebt habe. 

die Längsstege habe ich letztendlich rausgeschnitten, das grosse Modell ist 1mm zu lang...und das Handling beim Kleben einfacher...

 

Steuerungskonsole...

Das Thema Steuerungkonsole ist recht einfach - wir brauchen natürlich einen Grundkörper (um den ESP und die Steuerungselemente unterzubringen), dann einen Halter für die Stromversorgung des ESP aus einer Akkubank und zuletzt dann auch noch Halterungen für die kleinen Druckschalter...

Das Thema Grundkörper war schnell erledigt - ich habe es freihändig im Sketchup konstruiert, daher ist es nicht ganz symetrisch geworden...Die Stege haben Masz für die ursprünglich vorgesehenen handelsüblichen Joysticks..

der Grundkörper - eine Öffnung in der Wand ist ausmittig (die habe ich nicht gebraucht) und eine Sockelsäule zu kurz ( da habe ich eine M3-Mutter untergelegt)...

Später habe ich dann noch zwei Löcher für die Druckschalter gebohrt und einen Klemmkörper für die Akku-Bank drunter geklebt...

Halterung für die Druckschalter ( zuletzt verklebt ) und die Halterung für die Akku-Bank...

 

Joystick's...

Das Thema Joystick's war hingegen aufwendig - mit den Teilen aus dem Web konnte ich ja nicht wirklich etwas anfangen und die Steuerung sollte ja "realitätsnah" erfolgen.

Üblicherweise werden aktuelle Kettenfahrzeuge ja mit einem 2-Achsen-Joystick bzw. sogar mit einem Lenkrad gesteuert - eine "echter Panzer" (ich bin Ossi und somit eher mit sowjetischer / russischer Militärtechnik aufgewachsen) hat für jede Kette einen eigenen Hebel....

Und die notwendige Konstruktion sowie der 3D-Druck eines 2-Achsen-Joystick's wäre auch echt kompliziert geworden...

Also habe ich mir so einen kleinen Dreh-Potentiometer gegriffen, vermessen und nach mehrere Anläufen das gebaut.....

nach etwas "entgraten" passt der Dreh-Potentiometer "knirsch", die ganze Sache wird dann mittig auf die Platte geklebt...

Konsole und installierte Joystick's sehen dann so aus...

 

und hier wie versprochen die Sketchup-Datei zum Download.... 

Hinweis: Vor dem Druck sollten die Teile noch überprüft und korrigigiert werden ( z.B. Länge der Sockelsäule und die fehlerhafte Öffnung im Gehäuse der Konsole sowie die Masze an den Platinenhaltern für den DC-DC-Wandler hatten noch eine Macke, die Bohrungen in den Haltern für die Schalter können aufgrund jetziger Klebenverbindung entfallen). Das hatte ich aber nicht mehr eingepflegt...

 

Ist mir zu kompliziert..... =>.... zurück zur Startseite

 

Elektronik...

Die notwendigen elektronischen Schaltungen sind eigentlich relativ simpel, ich teile sie mal in "Fahrzeug" und " Konsole" je nach Einbauort auf...

 

Fahrzeug - Motor-Treiber...

Für die Ansteuerung des Motor-Treibers benötigen wir lediglich 3 Kabel je Motor..

Wir verbinden jeweils 2 Pin's an unserem ESP32 mit den Anschlüssen IN1/IN2 (Motor 1) bzw. IN3/IN4 (Motor2). Die verwendeten Pin's können Standard-Pin's ohne besondere Funktionen sein, ich habe die Pin's 16, 4 bzw. 25, 33 verwendet.

Für die PWM-Ansteuerung verbinden wir die beiden EN1 (Motor1) bzw. EN2 (Motor2) mit PWM-fähigen Pin's an unserem ESP - ich habe die Pin's 17 bzw. 26 verwendet.

Das war es hier auch schon....

 

Fahrzeug - Mähwerk...

Für unseren Motor für das Mähwerk ( bis zu 20 Volt direkt aus dem Akku) soll eine Schaltung sowohl das Ein-Ausschalten als auch die Regelung der Drehzahl ermöglichen.

Hier bietet sich eine Schaltung mit Optokoppler und einem MosFet an, sinngemäss der in meinem Beitrag  zu den MosFet's  bereits erläuterten Schaltung.

hier nochmals dargestellt - erstellt auf www.falstad.com

Als MosFet habe ich aktuell einen IRL3803 mit einer maximalen Leistung von ca. 15 A bei 24 Volt eingesetzt - ob das ausreichend ist, werde ich bei den Testfahrten feststellen - ansonsten habe ich noch die "grossen" MosFet's anlog dem o.g. Beitrag rumliegen.

Und natürlich habe ich noch eine Sicherung (aktuell 10A) mit eingebaut...

 

Konsole - Joystick's...

Die elektronische Lösung sieht hier im Schaltbild simpel aus, allerdings habe ich lange daran getüftelt, da auch die verwendeten kleinen Dreh-Potentiometer in der Mittelstellung nicht analog waren. Zumindest aber sind sie in der Drehung von 0-180 Grad im Anstieg des Widerstandes halbwegs symetrisch.

Die Potentiometer habe ich in der Einbau-Ansicht von unten dargestellt, das normale Symbol ist dann seperat nochmals dargestellt.

Den 10kiloOhm-Potentiometer bauen wir in den Joystick ein, mit dem 5kiloOhm-Potentiometer können wir dann den "Mittelwert" noch feinabstimmen.

 

Konsole - Druckschalter...

Die elektronische Lösung ist simpel und wird auf vielen Webseiten erklärt. Wesentlich ist hier die PullDown-Schaltung und - in diesem Projekt - die Trennung der Spannungsquelle für die Schalter von der normalen 3.3 Volt-Spannungsquelle am ESP - an der die Spannungsversorgung für die Joystick's hängt.

Aus irgendeinem Grund beeinflussen sich die Widerstände der Joystick-Schaltung und die PullDown-Widerstände hier gegenseitig, wahrscheinlich bildet sich eine Spannungsteiler und wir haben nur noch 1.6 Volt (von 3.3 Volt) an unserem Eingangs-Pin (da schaltet der ESP dann nicht auf HIGH).

Ohne den PullDown-Widerstand aber "flattern" unsere Schalter-Eingänge und schalten ständig hin und her.

Ich hab's nicht weiter untersucht, glücklicherweise kann man aber fast jeden Pin am ESP ja auch als Spannungsquelle verwenden.

 

Konsole - Drehzahlsteuerung Mähwerk...

Auch diese elektronische Lösung ist simpel und entspricht der Schaltung für die Joystick's - nur den Drehpotentiometer für die Feinabstimmung brauchen wir hier nicht..

 

Ist mir zu kompliziert..... =>.... zurück zur Startseite

Software...

Die Steuersoftware ist recht simpel, wir nutzen die ESPNow - Funktionalität und verbinden somit die beiden ESP32 über WiFi...

 

Konsole...

Hier die Programmierung für die Steuerkonsole, ich habe alle Funktionen hoffentlich ausreichend dokumentiert...

(Achtung - der Text [code].....[/code] gehört NICHT zum Programm..)

/*
 * Testversion für den ESP an der Steuerkonsole, er sendet die Daten über 
 * ESPNow an den RECIEVER-ESP und kommt dort als "Joystick" rein ..
 * 
 * ESP1 ( 1 roter Punkt ) MAC-Adresse :  08:F9:E0:B9:EA:90
 * 
 */



#include <esp_now.h>
#include <WiFi.h>


// **************************

// Name des Senders...
  char ESP_Name[] = "Joystick";

// **************************


// die ESP_Now_Einstellungen als SENDER

// Empfänger - MAC Addresse einstellen...
// uint8_t broadcastAddress[] = {0xA0, 0xA3, 0xB3, 0x2B, 0xEB, 0xB8}; // das war ESP3 der ist kaputt (MosFet's-Versuche)
uint8_t broadcastAddress[] = {0x08, 0xF9, 0xE0, 0xB9, 0xEA, 0x90};    // das ist ESP-1


// ESP-NOW - Sende - Datenblock Struktur
// MUSS BEIM EMPFÄNGER ANALOG DEFINIERT WERDEN !!!
typedef struct struct_message {
  char a[32];           // Identifikation und Meldungen
  int VR_1;             // Geschwindigkeit und Richtung linke Kette
  int VR_2;             // Geschwindigkeit und Richtung rechte Kette
  int V_Rot;            // Motordrehzahl
  int OnOff;            // Motor ein-/ausgeschaltet  => 1 / 0...
} struct_message;

// Struktur zum Zeiger myData zuweisen...
struct_message myData;

// ????....
esp_now_peer_info_t peerInfo;


// für das Auslesen des Joysticks

#define VRY_PIN_1            36   // linke Kette
#define VRY_PIN_2            34   // rechte Kette
#define V_Rot_PIN            35   // Motordrehzahl
#define OnOff_PIN_1          19   // Schalter 1
#define OnOff_PIN_2          23   // Schalter 2        

int NULL_V1 = 2047;         // die Kettenwerte werden ausgehend von 4095/2 pos/neg genutzt
int NULL_V2 = 2047;




// ********************************************************************
// wird nur 1x beim Start durchlaufen... 


void setup() {

  Serial.begin(115200); // zum seriellen Monitor Frequenz einstellen
  delay(5000);          // 5 sek warten nach Neustart
  

  // für ESP_NOW_ als Sender..

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

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
     //Serial.println("Error initializing ESP-NOW");
     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);
  
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;


  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    //Serial.println("Failed to add peer");
    return;
  }
 
   // zuerst Sendewerte zurücksetzen/definieren...
   // immer fester Wert...
   strcpy(myData.a, ESP_Name);
   // variable Werte...
   myData.VR_1 = 0;          // linke Kette
   myData.VR_2 = 0;          // rechte Kette
   myData.V_Rot = 0;         // Motordrehzahl  
   myData.OnOff = false;     // Motor ein-/ausgeschaltet  => 1 / 0...


   // die beiden Schalter-PIN's
   pinMode(OnOff_PIN_1, INPUT);
   pinMode(OnOff_PIN_2, INPUT);
   
   // PIn 25 macht die Stromquelle für die Schalter
   pinMode(25, OUTPUT);
   digitalWrite(25, HIGH);

   
}



// ********************************************************************

// Schleife wird immer wieder durchlaufen...
void loop() {


    // zuerst ESPNow-Sendewerte zurücksetzen/definieren...
    // variable Werte...
    myData.VR_1 = 0;     // linke Kette
    myData.VR_2 = 0;     // rechte Kette
    myData.V_Rot = 0;    // Motordrehzahl
   

  // wir ermitteln die Differenz zum NULLWERT und spiegeln
  // die Joystick-Werte...

   float value_V1 = (NULL_V1 - analogRead(VRY_PIN_1)); // linke Kette
   float value_V2 = (NULL_V2 - analogRead(VRY_PIN_2)); // rechte Kette
   float value_Rot = analogRead(V_Rot_PIN);              // Potentiometer Motordrahzahl..

  // die Kennwerte für die Ketten sind 0-2047 (4095/2), für den Motor 0-4095
  // wir ermitteln eine Steuerungskennzahl in Prozent als gerundeten Integer-Wert...
  // und weisen sie den ESPNow_Sendewerten zu

    myData.VR_1 =  round (( value_V1 / 2047 ) * 100);  // linke Kette
    myData.VR_2 =  round (( value_V2 / 2047 ) * 100);  // rechte Kette
    myData.V_Rot = round (( value_Rot / 4095 ) * 100); // Potentiometer Motordrehzahl..von 4095


  // die Schalter... Hier Auswertung ist BEIDE AN => Motor starten, ist nur EINER AN (egal
  // welcher => Motor aus...

  // Wenn ein Knopf gedrückt wird...

       // die Bedingung A ODER B tritt beim Drücken auf jeden Fall ein...
       // sie würde nachfolgend angeordnet die BEIDE Bedingung überstimmen...
       if ( (digitalRead(OnOff_PIN_1) == HIGH) or (digitalRead(OnOff_PIN_2) == HIGH)  ){
           myData.OnOff = false;
           delay(200); // entprellen...
           }

       // if (digitalRead(OnOff_PIN_1) == HIGH){Serial.println("Pin1");}
       // if (digitalRead(OnOff_PIN_2) == HIGH){Serial.println("Pin2");}

  
       // Die Bedingung BEIDE TRITT NICHT IMMER AUF => Anschalten

       // nur wenn das Fahrzeug NICHT oder SEHR LANGSAM fährt...
       if ( ( abs(myData.VR_1) < 20 ) and (abs(myData.VR_2) < 20  ) ) {
            if (  (digitalRead(OnOff_PIN_1) == HIGH) and (digitalRead(OnOff_PIN_2) == HIGH)  ){
                 myData.OnOff = true;
                 delay(1000); // entprellen...
                 }
            }


      Serial.print("V_1: ");
      Serial.print(myData.VR_1);
      Serial.print(" / V_2: ");
      Serial.print(myData.VR_2);
      Serial.print(" und V_Rot: ");
      Serial.println(myData.V_Rot);
      
      Serial.print("ON_OFF: ");
      Serial.println(myData.OnOff);
      
      Serial.println();  
 
           
  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

  delay(100);

}


// ********************************************************************


// VOID-Funktion 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");
}

 

Fahrzeug...

Und hier für das Fahrzeug....

(Achtung - der Text [code].....[/code] gehört NICHT zum Programm..)

/* 
 * Testversion für den ESP auf dem Tank-Chassis
 * empfängt die Daten über ESPNow vom Joystick-ESP....
*/


//Bibliotheken
#include <esp_now.h>
#include <WiFi.h>


// ESP-NOW - Sende - Datenblock Struktur
// MUSS BEIM SENDER ANALOG DEFINIERT WERDEN !!!
  typedef struct struct_message {
  char a[32];           // Identifikation und Meldungen
  int VR_1;             // Geschwindigkeit und Richtung linke Kette
  int VR_2;             // Geschwindigkeit und Richtung rechte Kette
  int V_Rot;            // Motordrehzahl
  int OnOff;            // Motor ein-/ausgeschaltet  => 1 / 0...
  } struct_message;

// ESP-NOW - Struktur zum Zeiger myData zuweisen...
  struct_message myData;


// für die Motorensteuerung 

  const int M1_EN = 17;         // LILA - PWM-Pin
  const int M1_P1 = 16;         // BLAU
  const int M1_P2 =  4;         // GRUEN
  const int M1_freq = 30000;    // Geschwindigkeits-Grundeinstellung PWM
  const int M1_pwmChannel = 1;  // der dem Pin zugeordnete Kanal PWM
  const int M1_resolution = 8 ; // 8-bit PWM
  int M1_dutyCycle = 200;       // VARIABLE - als Grundeinstellung, es soll unter 200 brummen - sonst 0-255 möglich

  const int M2_EN = 26;         // LILA - PWM-Pin
  const int M2_P1 = 25;         // BLAU
  const int M2_P2 = 33;         // GRUEN
  const int M2_freq = 30000;    // Geschwindigkeits-Grundeinstellung PWM
  const int M2_pwmChannel = 2;  // der dem Pin zugeordnete Kanal PWM
  const int M2_resolution = 8 ; // 8-bit PWM
  int M2_dutyCycle = 200;       // VARIABLE - als Grundeinstellung, es soll unter 200 brummen - sonst 0-255 möglich

  const int M3 = 19;              // MosFet für den grossen Motor  - PWM-Pin
  const int M3_freq = 30000;      // Geschwindigkeits-Grundeinstellung PWM
  const int M3_pwmChannel = 3;    // der dem Pin zugeordnete Kanal PWM
  const int M3_resolution = 8 ;  // 8-bit PWM
  int M3_dutyCycle = 200;         // VARIABLE - als Grundeinstellung, es soll unter 200 brummen - sonst 0-255 möglich

  // M1 und M2 sind auf einem handelsüblichen H-Brücken-Board für 2 DC-Motoren OHNE Step-Steuerung...
  // mit EN-Pin wird per PWM die Geschwindigkeit gesteuert, die Kombination P1/P2-Pin an/aus steuert die Drehrichtung
  // dabei muss für eine Drehung kombiniert ein Pin an und ein Pin aus sein, sonst passiert NICHTS....
  // M3 ist der grosse Motor - der wird nur mit PWM angefahren, ausschalten ist dann problemlos...



  
// eigene Initialisierung für Programmabläufe...

  bool M3_an = false;
  
  float PWM_Max = 255.00 - 125.00;        // damit wir einen float-Wert für die Berechnung haben...
  int PWM_Wert = 0;                       // siehe Hinweise zu Grundwert 125 PWM für Drehbeginn der Motoren s.u.

  

// ********************************************************************



// wird nur 1x beim Start durchlaufen... 
void setup() {
  
  // Initialize Serial Monitor - am PC
  Serial.begin(115200);

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

  // ESP-NOW - Initialisieren ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
    }
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);


// für die Motorensteuerung 

  pinMode(M1_EN, OUTPUT);
  pinMode(M1_P1, OUTPUT);
  pinMode(M1_P2, OUTPUT);

  pinMode(M2_EN, OUTPUT);
  pinMode(M2_P1, OUTPUT);
  pinMode(M2_P2, OUTPUT);

  pinMode(M3, OUTPUT);

  ledcSetup(M1_pwmChannel,M1_freq, M1_resolution);
  ledcSetup(M2_pwmChannel,M2_freq, M2_resolution);
  ledcSetup(M3_pwmChannel,M3_freq, M3_resolution);

  ledcAttachPin(M1_EN, M1_pwmChannel);
  ledcAttachPin(M2_EN, M2_pwmChannel);
  ledcAttachPin(M3, M3_pwmChannel);

  digitalWrite( M1_P1, LOW );
  digitalWrite( M1_P2, LOW );

  digitalWrite( M2_P1, LOW );
  digitalWrite( M2_P2, LOW );

  
} // ende Setup



// ********************************************************************


// Schleife wird immer wieder durchlaufen... 
void loop() {

  // keine Einträge, die relevante Funktion OnDataRecieve..s.u. wird vom System aufgerufen

} // ende loop



// ********************************************************************



// Funktion wird vom System aufgerufen, wenn Daten kommen...
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));


  if (strstr(myData.a,"Joystick")){

   /*
      // erst Mal nur Ausgabe empfangene Daten auf dem Seriellen Monitor
      // Serial.print("Bytes empfangen: ");
      // Serial.println(len);
      Serial.print("Sender ");
      Serial.println(myData.a);
      Serial.print("V1: ");
      Serial.print(myData.VR_1);
      Serial.print(" / V2: ");
      Serial.print(myData.VR_2);
      Serial.print(" und V_Rot: ");
      Serial.println(myData.V_Rot);

      Serial.print("ON_OFF: ");
      Serial.println(myData.OnOff);
      
      Serial.println();

   */      

      // JETZT DIE VERARBEITENDEN BEFEHLSSEQUENZEN


      // kommt der OnOff-Befehl  ( als INT 0/1...) , dann anfahren, sonst ausschalten...
      // der Button-Status wird jedes Mal gesendet, damit wir nicht ständig hoch- 
      // und runterfahren wird der Motorstatus zwischengespeichert...
     
      if ( myData.OnOff > 0 ) {
         // wenn der Motor den Status aus hat...
         if ( M3_an == false ) {
             // den Motor hochfahren bis zur eingestellten Geschwindigkeit V_Rot !!!
             // Änderungen gehen dann immer wenn der Motor ausgeschaltet wurde...
             PWM_Wert = round ( abs( myData.V_Rot / 100.00 ) * PWM_Max);
             for ( int M3_i = 0 ; M3_i < PWM_Wert ; M3_i += 5 ){
                 ledcWrite( M3_pwmChannel, M3_i);
                 delay(100);
                 } // endfor
             M3_an = true; // status auf an setzen..
             } // endif
                 
          } else {  // myData...
            
            //beide sind NULL => Motor ausschalten
            ledcWrite( M3_pwmChannel, 0);
            M3_an = false; // status aus aus setzen..
          }



    // FÜR KETTE1 = MOTOR1 - wir werten nur den Wert "myData.VR_1" aus = VOR/ZURÜCK

    // der gesendete Wert ist ein Prozentwert von 0-100% mit pos/neg Vorzeichen, der Nullwert
    // schwankt im Ruhezustand  bis +/- 10%... ( eigentlich < 5% )=> Reserve...
    // wenn der Wert > 0 ist wollen wir vorwärts fahren, wird er kleiner NULL dann rückwärts...

    // wir senden alle xxx ms - ein schlagartiges umschalten von vor auf rück sollte eigentlich
    // nicht möglich sein ?? ODER ??...

    // ein nennenswertes Fahrsignal gibt es erst bei Werten über 50% Ansteuerung vom Joystick, 
    // dies entspräche einem PWM-Signal von ca. 125 (von 255 MAX ), wir können also diesen Wert
    // als Startwert PWM fest vorgeben und die Differenz von 10% nach 100% auf den Restbereich 
    // von 125 PWM aufteilen... 
    

    if ( abs(myData.VR_1) < 11 ) {  // wir bleiben stehen...
      
       ledcWrite( M1_pwmChannel, 0);
       digitalWrite( M1_P1, LOW );
       digitalWrite( M1_P2, LOW );
       }
    
    if ( myData.VR_1 > 11 ) {  // wir fahren in die eine Richtung
       digitalWrite( M1_P1, HIGH );
       digitalWrite( M1_P2, LOW );
       PWM_Wert = 125 + round ( abs( myData.VR_1 / 100.00 ) * PWM_Max);
       ledcWrite( M1_pwmChannel, PWM_Wert);
       
       }

    if ( myData.VR_1 < -11 ) {  // wir fahren in die andre Richtung
       digitalWrite( M1_P1, LOW );
       digitalWrite( M1_P2, HIGH ); 
       PWM_Wert = 125 + round ( abs( myData.VR_1 / 100.00 ) * PWM_Max);
       ledcWrite( M1_pwmChannel, PWM_Wert);
      
       }



    // FÜR KETTE2 = MOTOR2 - wir werten nur den Wert "myData.VR_2" aus = VOR/ZURÜCK

    // der gesendete Wert ist ein Prozentwert von 0-100% mit pos/neg Vorzeichen, der Nullwert
    // schwankt im Ruhezustand  bis +/- 10%... ( eigentlich < 5% )=> Reserve...
    // wenn der Wert > 0 ist wollen wir vorwärts fahren, wird er kleiner NULL dann rückwärts...

    // wir senden alle xxx ms - ein schlagartiges umschalten von vor auf rück sollte eigentlich
    // nicht möglich sein ?? ODER ??...
    

    if ( abs(myData.VR_2) < 11 ) {  // wir bleiben stehen...
      
       ledcWrite( M2_pwmChannel, 0);
       digitalWrite( M2_P1, LOW );
       digitalWrite( M2_P2, LOW );

       }
    
    if ( myData.VR_2 > 11 ) {  // wir fahren in die eine Richtung
       digitalWrite( M2_P1, HIGH );
       digitalWrite( M2_P2, LOW );
       PWM_Wert = 125 + round ( abs( myData.VR_2 / 100.00 ) * PWM_Max);
       if (PWM_Wert > 255) {PWM_Wert=255;} // Sicherung gegen Rundung > 255
       ledcWrite( M2_pwmChannel, PWM_Wert);
       
       }

    if ( myData.VR_2 < -11 ) {  // wir fahren in die andre Richtung
       digitalWrite( M2_P1, LOW );
       digitalWrite( M2_P2, HIGH ); 
       PWM_Wert = 125 + round ( abs( myData.VR_2 / 100.00 ) * PWM_Max);
       ledcWrite( M2_pwmChannel, PWM_Wert);
      
       }

  delay(100);
      

  } // es sind strDate von Joystick gekommenn
        
} // end callback

 

Vorschau...

Bei ersten "Probefahrten" habe ich festgestellt, das mein "Mäher" mit Motor und Akku für die kleinen Ketten auf dem Rasen speziell auf Moos schon fast zu schwer ist - und - das die Fahrmotoren anscheinend auch etwas "schwach auf der Brust" sind.

Ich habe erst mal ( hoffentlich gleiche Bauweise und Masze ) Ketten seperat nachbestellt (dauert aus FernOst leider wieder einige Tage/Wochen) und werde zwischenzeitlich schon mal die Antriebsräder konstruieren und drucken. Dadurch kann ich die Auflagerfläche vergrössern.

Mit den Fahrmotoren muss ich noch prüfen ( auch ob es baugleiche, stärkere Motoren zu einem vernünftigen Preis gibt ), ggf. muss ich auch auf Steppermotoren umsatteln, allerdings muss die Ansteuerung dann ja auf andere Weise erfolgen.

Für die Software-Aktualisierung des fest eingebauten ESP32 auf dem Fahrwerk möchte ich eine OTA-Funktionalität einrichten (OverTheAir...Update), wie ich dies mit dem hier genutzten WIFI und gleichzeitig WLAN hinbekomme, muss ich noch ausprobieren (rein über WLAN hab ich es schon häufiger genutzt).

Also es bleibt noch "Raum für weitere Basteleien".....

Ist mir zu kompliziert..... =>.... zurück zur Startseite

 

Mai 2025 - Update - Ketten...

Mittlerweile sind die bestellten Ketten aus FernOst eingetroffen und - natürlich - haben sie abweichende Masze. Das nennt man ja wohl "Murphy's Gesetz" - ich sage immer "das Gesetz der grössten Gemeinheit"....

Somit waren meine in der Zwischenzeit anhand der Abmessungen der vorhandenen Laufräder nachkonstruierten (und schon gedruckten) Teile "für die Tonne".

Während die bereits vorhandenen Laufketten bei gleichem Durchmesser des Laufrades 20 Zähne erfordern, sind es bei den neuen Ketten dann nur noch 18 Zähne - auch die Anordnung der Zahnkränze im Grundriss ist bei den neuen Ketten abweichend.. Dafür passen Ketten und Rollen geometrisch besser zusammen - ich kann hier auf eine Spannvorrichtung verzichten.

Also habe ich mein Sketchup nochmals angeworfen und meine Konstruktion aktualisiert. Dabei habe ich dann auch gleich die "Aufhängung" der Laufrollen (die ohne Zahnkränze) mit einer Lösung für Kugellager versehen -  die Reibung der beiden Laufrollen auf dem M5-Gewindestab war einfach zu gross.

hier bereits für den 3D-Druck als "Explosionsdarstellung" aufbereitet...

Hier die Sketchup-Dateien zum Download....

Hinweis: Die Original-Laufrolle musste ich auf Durchmesser 5mm aufbohren - hier wäre möglicherweise eine alternative Konstruktionsanpassung auf einen Gewindestab M4 (natürlich dann mit Anpassung von Konstruktion und Kugellagern) sinnvoll...

Die Kugellager habe ich im Web auf einer bekannten Plattform mit "A.." bestellt -  voll gekapselt, Innendurchmesser 5mm (für M5_Gewindestangen aus dem Baumarkt), Aussendurchmesser 10mm und Dicke 4mm - 10 Stk für 4€...

Montage..

Für die Montage musste ich am Fahrgestell "bohren", das Aufhängungsloch wurde auf 9mm und die Schraublöcher auf 4mm Durchmesser aufgebohrt (ging ganz leicht, das Metall ist sehr weich). So sieht die Sache jetzt aus...

schon recht recht massiv - erinnert mich immer irgendwie an die Raupenketten der Raketen-Startrampen...

Tja, das bisherige Ergebniss..

Natürlich "sackt" die ganze Konstruktion jetzt nicht mehr so tief ein - GUT.... Aber dafür hat sich das Problem mit den wahrscheinlich "zu schwachen Motoren"  vergrössert - ein Wenden "auf der Stelle" (eine Kette vorwärts - eine Kette rückwärts) ist jetzt nicht mehr möglich. 

Also muss ich mir demnächst dann mal die Kennwerte des Motor-Treibers und ggf. meiner Stromversorgung ansehen - ob da "genug Saft ankommt"....

 

Ist mir zu kompliziert..... =>.... zurück zur Startseite

 

Mai 2025 - Update - OTA - Softwareaktualisierung...

Für den "Mäher-ESP" habe ich mir wie geplant eine Möglichkeit geschaffen, die Software über OTA (OverTheAir...Update) aktualisieren zu können, ohne den ESP32 jedes Mal ausbauen zu müssen.

Da mir die ganze Sache mit WLAN und WIFI noch immer irgendwie "ein Buch mit sieben Siegeln" ist ( verdammt - ich bin im Bauwesen tätig..), habe ich vorerst die "brachiale Methode" angewandt.

Wenn das Gerät eingeschaltet wird, dann lasse ich es ca. 20 Sekunden auf eine Softwareaktualisierung über WLAN und OTA warten, danach trenne ich die Verbindung und starte das  WIFI mit  ESP-Now...

Hat sogar beim ersten Versuch geklappt, ich kann jetzt bei Programmanpassungen in der Arduino-Oberfläche meinen ESP als "Rasentrimmer über IP-Adresse" auswählen und ihm die aktuelle Software senden... Hier nun die aktualisierte Software für den Mäher-ESP....

 

/* 
 * Testversion für den ESP auf dem Tank-Chassis
 * empfängt die Daten über ESPNow vom Joystick-ESP....
 * Update 25. Mai 2025 - jetzt mit OTA in den ersten 20 sek. nach 
 * Neustart....geht danach in den ESP-NOW-Modus..
 * 
*/


//Bibliotheken
#include <esp_now.h>
#include <WiFi.h>


// für WLAN und OTA...
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

const char* ssid = "********";          // der Name Eures WLAN !!!
const char* pass = "********";          // das Password Eures WLAN !!!




// ESP-NOW - Sende - Datenblock Struktur
// MUSS BEIM SENDER ANALOG DEFINIERT WERDEN !!!
  typedef struct struct_message {
  char a[32];           // Identifikation und Meldungen
  int VR_1;             // Geschwindigkeit und Richtung linke Kette
  int VR_2;             // Geschwindigkeit und Richtung rechte Kette
  int V_Rot;            // Motordrehzahl
  int OnOff;            // Motor ein-/ausgeschaltet  => 1 / 0...
  } struct_message;

// ESP-NOW - Struktur zum Zeiger myData zuweisen...
  struct_message myData;


// für die Motorensteuerung 

  const int M1_EN = 17;         // LILA - PWM-Pin
  const int M1_P1 = 16;         // BLAU
  const int M1_P2 =  4;         // GRUEN
  const int M1_freq = 30000;    // Geschwindigkeits-Grundeinstellung PWM
  const int M1_pwmChannel = 1;  // der dem Pin zugeordnete Kanal PWM
  const int M1_resolution = 8 ; // 8-bit PWM
  int M1_dutyCycle = 200;       // VARIABLE - als Grundeinstellung, es soll unter 200 brummen - sonst 0-255 möglich

  const int M2_EN = 26;         // LILA - PWM-Pin
  const int M2_P1 = 25;         // BLAU
  const int M2_P2 = 33;         // GRUEN
  const int M2_freq = 30000;    // Geschwindigkeits-Grundeinstellung PWM
  const int M2_pwmChannel = 2;  // der dem Pin zugeordnete Kanal PWM
  const int M2_resolution = 8 ; // 8-bit PWM
  int M2_dutyCycle = 200;       // VARIABLE - als Grundeinstellung, es soll unter 200 brummen - sonst 0-255 möglich

  const int M3 = 19;              // MosFet für den grossen Motor  - PWM-Pin
  const int M3_freq = 30000;      // Geschwindigkeits-Grundeinstellung PWM
  const int M3_pwmChannel = 3;    // der dem Pin zugeordnete Kanal PWM
  const int M3_resolution = 8 ;  // 8-bit PWM
  int M3_dutyCycle = 200;         // VARIABLE - als Grundeinstellung, es soll unter 200 brummen - sonst 0-255 möglich

  // M1 und M2 sind auf einem handelsüblichen H-Brücken-Board für 2 DC-Motoren OHNE Step-Steuerung...
  // mit EN-Pin wird per PWM die Geschwindigkeit gesteuert, die Kombination P1/P2-Pin an/aus steuert die Drehrichtung
  // dabei muss für eine Drehung kombiniert ein Pin an und ein Pin aus sein, sonst passiert NICHTS....
  // M3 ist der grosse Motor - der wird nur mit PWM angefahren, ausschalten ist dann problemlos...



  
// eigene Initialisierung für Programmabläufe...

  bool M3_an = false;
  
  float PWM_Max = 255.00 - 125.00;        // damit wir einen float-Wert für die Berechnung haben...
  int PWM_Wert = 0;                       // siehe Hinweise zu Grundwert 125 PWM für Drehbeginn der Motoren s.u.

  

// ********************************************************************



// wird nur 1x beim Start durchlaufen... 
void setup() {
  
  // Initialize Serial Monitor - am PC
  Serial.begin(115200);




// Wir überprüfen beim Einschalten des Systems, ob ggf. OTA-Updates gesendet
// werden, sprich wir müssen innerhalb der ersten - 20 sek - nach dem Einschalten
// das Update senden... (also rechtzeitig kompilieren )


  // warten bis WLAN verbunden ist....... 
  // hier würde er ohne Rückmeldemöglichkeit ohne WLAN hängen, bis WLAN da ist, 
  // wir starten daher nach 5 Versuchen neu...damit sich etwas tut...
  int wifi_retry = 0;
  while( (WiFi.status() != WL_CONNECTED) && ( wifi_retry < 5) ){
      wifi_retry++;
      WiFi.begin(ssid, pass);
      delay(5000); // über die Mesh dauert es ggf. etwas länger...
      Serial.print(".");
      }
  if ( wifi_retry >= 5){
      ESP.restart();
      }

  // Einstellungen für das OTA-Updaten
  
  ArduinoOTA.setHostname("Rasentrimmer");

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();

  // für das Updaten - wir warten jetzt 20 sek auf eine OTA-Sendung...
  if ( (WiFi.status() == WL_CONNECTED) ){ // Absturz bei fehlendem WLAN vermeiden
    for (int OTA_warten=0;OTA_warten<20;OTA_warten++){
        ArduinoOTA.handle(); // löst nach Aktualisierung einen Neustart aus...
        delay(1000); // 1 sek warten
        } // for
     } // if




  // DANACH.. gehen wir in den ESP-Now-Modus...erst mal WLAN - Verbindung trennen..
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  delay(1000); // 1 sek warten

  Serial.println("gehe in den ESP-Now-Modus");
  
  // ESP-NOW - Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // ESP-NOW - Initialisieren ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
    }
    
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);


// für die Motorensteuerung 

  pinMode(M1_EN, OUTPUT);
  pinMode(M1_P1, OUTPUT);
  pinMode(M1_P2, OUTPUT);

  pinMode(M2_EN, OUTPUT);
  pinMode(M2_P1, OUTPUT);
  pinMode(M2_P2, OUTPUT);

  pinMode(M3, OUTPUT);

  ledcSetup(M1_pwmChannel,M1_freq, M1_resolution);
  ledcSetup(M2_pwmChannel,M2_freq, M2_resolution);
  ledcSetup(M3_pwmChannel,M3_freq, M3_resolution);

  ledcAttachPin(M1_EN, M1_pwmChannel);
  ledcAttachPin(M2_EN, M2_pwmChannel);
  ledcAttachPin(M3, M3_pwmChannel);

  digitalWrite( M1_P1, LOW );
  digitalWrite( M1_P2, LOW );

  digitalWrite( M2_P1, LOW );
  digitalWrite( M2_P2, LOW );

  
} // ende Setup



// ********************************************************************


// Schleife wird immer wieder durchlaufen... 
void loop() {

  // keine Einträge, die relevante Funktion OnDataRecieve..s.u. wird vom System aufgerufen

} // ende loop



// ********************************************************************



// Funktion wird vom System aufgerufen, wenn Daten kommen...
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));


  if (strstr(myData.a,"Joystick")){

   
      // erst Mal nur Ausgabe empfangene Daten auf dem Seriellen Monitor
      // Serial.print("Bytes empfangen: ");
      // Serial.println(len);
      Serial.print("Sender ");
      Serial.println(myData.a);
      Serial.print("V1: ");
      Serial.print(myData.VR_1);
      Serial.print(" / V2: ");
      Serial.print(myData.VR_2);
      Serial.print(" und V_Rot: ");
      Serial.println(myData.V_Rot);

      Serial.print("ON_OFF: ");
      Serial.println(myData.OnOff);
      
      Serial.println();

         

      // JETZT DIE VERARBEITENDEN BEFEHLSSEQUENZEN


      // kommt der OnOff-Befehl  ( als INT 0/1...) , dann anfahren, sonst ausschalten...
      // der Button-Status wird jedes Mal gesendet, damit wir nicht ständig hoch- 
      // und runterfahren wird der Motorstatus zwischengespeichert...
     
      if ( myData.OnOff > 0 ) {
         // wenn der Motor den Status aus hat...
         if ( M3_an == false ) {
             // den Motor hochfahren bis zur eingestellten Geschwindigkeit V_Rot !!!
             // Änderungen gehen dann immer wenn der Motor ausgeschaltet wurde...
             PWM_Wert = round ( abs( myData.V_Rot / 100.00 ) * PWM_Max);
             for ( int M3_i = 0 ; M3_i < PWM_Wert ; M3_i += 5 ){
                 ledcWrite( M3_pwmChannel, M3_i);
                 delay(100);
                 } // endfor
             M3_an = true; // status auf an setzen..
             } // endif
                 
          } else {  // myData...
            
            //beide sind NULL => Motor ausschalten
            ledcWrite( M3_pwmChannel, 0);
            M3_an = false; // status aus aus setzen..
          }



    // FÜR KETTE1 = MOTOR1 - wir werten nur den Wert "myData.VR_1" aus = VOR/ZURÜCK

    // der gesendete Wert ist ein Prozentwert von 0-100% mit pos/neg Vorzeichen, der Nullwert
    // schwankt im Ruhezustand  bis +/- 10%... ( eigentlich < 5% )=> Reserve...
    // wenn der Wert > 0 ist wollen wir vorwärts fahren, wird er kleiner NULL dann rückwärts...

    // wir senden alle xxx ms - ein schlagartiges umschalten von vor auf rück sollte eigentlich
    // nicht möglich sein ?? ODER ??...

    // ein nennenswertes Fahrsignal gibt es erst bei Werten über 50% Ansteuerung vom Joystick, 
    // dies entspräche einem PWM-Signal von ca. 125 (von 255 MAX ), wir können also diesen Wert
    // als Startwert PWM fest vorgeben und die Differenz von 10% nach 100% auf den Restbereich 
    // von 125 PWM aufteilen... 
    

    if ( abs(myData.VR_1) < 11 ) {  // wir bleiben stehen...
      
       ledcWrite( M1_pwmChannel, 0);
       digitalWrite( M1_P1, LOW );
       digitalWrite( M1_P2, LOW );
       }
    
    if ( myData.VR_1 > 11 ) {  // wir fahren in die eine Richtung
       digitalWrite( M1_P1, HIGH );
       digitalWrite( M1_P2, LOW );
       PWM_Wert = 125 + round ( abs( myData.VR_1 / 100.00 ) * PWM_Max);
       ledcWrite( M1_pwmChannel, PWM_Wert);
       
       }

    if ( myData.VR_1 < -11 ) {  // wir fahren in die andre Richtung
       digitalWrite( M1_P1, LOW );
       digitalWrite( M1_P2, HIGH ); 
       PWM_Wert = 125 + round ( abs( myData.VR_1 / 100.00 ) * PWM_Max);
       ledcWrite( M1_pwmChannel, PWM_Wert);
      
       }



    // FÜR KETTE2 = MOTOR2 - wir werten nur den Wert "myData.VR_2" aus = VOR/ZURÜCK

    // der gesendete Wert ist ein Prozentwert von 0-100% mit pos/neg Vorzeichen, der Nullwert
    // schwankt im Ruhezustand  bis +/- 10%... ( eigentlich < 5% )=> Reserve...
    // wenn der Wert > 0 ist wollen wir vorwärts fahren, wird er kleiner NULL dann rückwärts...

    // wir senden alle xxx ms - ein schlagartiges umschalten von vor auf rück sollte eigentlich
    // nicht möglich sein ?? ODER ??...
    

    if ( abs(myData.VR_2) < 11 ) {  // wir bleiben stehen...
      
       ledcWrite( M2_pwmChannel, 0);
       digitalWrite( M2_P1, LOW );
       digitalWrite( M2_P2, LOW );

       }
    
    if ( myData.VR_2 > 11 ) {  // wir fahren in die eine Richtung
       digitalWrite( M2_P1, HIGH );
       digitalWrite( M2_P2, LOW );
       PWM_Wert = 125 + round ( abs( myData.VR_2 / 100.00 ) * PWM_Max);
       if (PWM_Wert > 255) {PWM_Wert=255;} // Sicherung gegen Rundung > 255
       ledcWrite( M2_pwmChannel, PWM_Wert);
       
       }

    if ( myData.VR_2 < -11 ) {  // wir fahren in die andre Richtung
       digitalWrite( M2_P1, LOW );
       digitalWrite( M2_P2, HIGH ); 
       PWM_Wert = 125 + round ( abs( myData.VR_2 / 100.00 ) * PWM_Max);
       ledcWrite( M2_pwmChannel, PWM_Wert);
      
       }

  delay(100);
      

  } // es sind strDate von Joystick gekommenn
        
} // end callback

Ich werde bei Gelegenheit noch eine "Status-LED" einbauen, damit der WLAN-OTA-Wartezeitraum aussen am Gehäuse angezeigt wird....

 

Probiert es doch einfach aus...

 zurück zur Startseite

 

 

This article was updated on Mai 29, 2025