logo elektroda
logo elektroda
X
logo elektroda

Das zweite Leben von RC-Modellen, also die Fernbedienung von Frog_Qmak

Frog_Qmak 4968 17
WERBUNG
Treść została przetłumaczona Polnisch » Deutsch Zobacz oryginalną wersję tematu
📢 Słuchaj:
  • Ferngesteuertes Offroad-Auto mit Antenne, stehend auf einem Holzboden.

    Hallo
    Ich möchte eine universelle Plattform zum Betrieb ferngesteuerter Modelle vorstellen und teilen.
    Ich habe viele Jahre lang nichts im Forum gepostet – das bedeutet nicht, dass nichts passiert ist, aber es hat sich nicht immer gelohnt, es zu zeigen. ;)

    Alles begann damit, dass ich etwas machen wollte, das mir Spaß macht und mich dazu inspiriert, mit Kabeln und Arduino herumzuspielen. Also bestellte ich ein Panzerfahrgestell bei einem chinesischen Online-Shop (sinoning.com) und so begann das Abenteuer. Nach dem Panzer kam ein Miniauto (ebenfalls aus demselben Laden) und dann wurde für 1/3 des Wertes von Neufahrzeugen, ein vollwertiges Auto mit 4x4-Antrieb und ein ferngesteuertes Schnellboot, bei Allegro als "beschädigt" gekauft. Der Schaden am Auto bestand darin, dass Wasser in das Innere eindrang und den Motor blockierte (das Auto ist theoretisch wasserdicht, verfügt über einen positiven Auftrieb und kann sich auch auf dem Wasser "bewegen"), der wiederbelebt wurde (durch Gewalt und anschließendes Drehen von Hand). Am Boot war theoretisch die Steuerung beschädigt, aber ich habe nicht überprüft, was passiert ist, weil ich von Anfang an meine eigene installieren wollte.

    Ein paar Worte zur Steuerung selbst:
    Die Fernbedienung besteht aus 2 Joysticks (Arduino-Modulen), Arduino Nano, Li-Ion-Akku, BMS-System, 5V-Aufwärtswandler und Radio (HC-12-Modul). Keine rocket science. Ich hatte ein großes Problem bei der Diagnose des Problems, dass das BMS die Batterie nicht laden wollte – die Diode blinkte sehr schnell, als ob irgendwo kein Kontakt bestand oder im Modul Rückkopplung auftritt. In meiner Verzweiflung habe ich es direkt an die Batterie gelötet (vorher über den Schalter) und damit war das Problem gelöst. Ich weiß nicht, warum der Schalter solche Probleme verursachte - vielleicht stellten die Kontakte einen elektrischen Widerstand dar und das Modul wurde z. B. durch das Radio oder den Konverter erregt. Die Fernbedienung verfügt über zwei Modi (der Modus wird durch langes Drücken des linken Joysticks geändert): Auto-/Bootsmodus (Standard: linker Joystick vorwärts/rückwärts, rechter Joystick rechts/links) und Panzermodus (beide vordere/hintere Joysticks zur Differenzialsteuerung). ). Durch kurzes Halten des linken Joysticks ändert sich der Lampenmodus (hell/mittel/aus) im großen Auto.

    Die Empfänger bestehen auch aus Arduino Nano, HC-12, sowie (Autos, Panzer) BMS und einer H-Brücke zur Steuerung der Motoren (beim Boot zur Steuerung des Motors, das Ruder wird durch ein Servo betrieben). Das kleinste Auto wird von einer LI-ION-Zelle und einem STEP-UP-Wandler angetrieben, daher der große Kondensator, damit Spannungsabfälle den Arduino nicht zurücksetzen. Die restlichen Modelle laufen mit zwei 18650 (das große Auto hat auch einen Kondensator am Stromversorgung, der aber nicht benötigt wird).

    Weitere Informationen
    Das große Auto verfügt über Lichter auf Basis von WS2812B (zwei weiße vorne, ein rotes hinten).

    Bootssteuerung ist komplizierter, da der „normale PWM-Code“ nicht zum Betrieb des Servos verwendet werden kann, da dies auf andere Weise erfolgt. Alle Empfänger haben einen identischen Code; Beim Start prüft Arduino, ob an einem der Pins die entsprechende Spannung anliegt (versorgt vom 3,3-V-Ausgang) und aktiviert in diesem Fall den „Bootsmodus“. Bei anderen Modellen ist dieser Pin nicht gebrückt – so ist das Programm universell und es ist nicht nötig, einen weiteren „Modus“ in der Fernbedienung hinzuzufügen.

    Das Boot verfügt über einen Schutz gegen niedrige Batteriespannung – er wird über einen Spannungsteiler gemessen und verfügt über zwei Aktivierungsschwellen. Bei Erreichen der ersten Stufe ertönt für einige Sekunden ein akustisches Signal (5V-Summer, gesteuert durch den BS170-Transistor). Bei Erreichen der zweiten Stufe schaltet sich das akustische Signal dauerhaft ein und die Motorleistung wird reduziert (PWM max 50 %). Das in den Werkszellen verwendete BMS unterbricht den Strom auch bei Tiefentladung nicht, was Sinn macht, denn es ist besser, die Batterien zu zerstören, als das Boot 10 Meter vom Ufer entfernt festzustecken.
    Die Steuerung des Servos erfolgt über eine Softwarebibliothek. Dies liegt daran, dass die Standard-Servobibliothek einen Konflikt mit der Bibliothek hatte, die für die Steuerung des WS2812 verantwortlich ist (wahrscheinlich ein Konflikt aufgrund der Verwendung desselben Timers).
    [F]
    Das Programm verfügt auch über kommentierte Abschnitte zum Testen der Batterie im Boot. Bevor ich feststellte, dass das BMS sie nicht abschaltete, schrieb ich ein Skript, das die niedrigste gemessene Versorgungsspannung im EEPROM speicherte und nach dem Anschließen des Arduino an den Computer verschickte es über Serial. Ich wollte wissen, bis zu welchem Grad die Zellen entladen werden könnten, um die Schutzschwellen richtig einzustellen, aber das erwies sich als unnötig.

    Die Fernbedienung und das große Spielzeugauto verfügen über Anschlüsse zum Laden der Batterien; für ein kleines Auto und das Boot gibt es Ladegeräte.

    Im Allgemeinen habe ich festgestellt, dass die „Spiral“-Antenne im Sender schlecht funktioniert, ein normaler Draht geeigneter Länge funktioniert jedoch gut. Die Antennen in der Fernbedienung und im Auto sind in Goldstiftfassungen montiert, so dass sie zum Transport leicht abgenommen werden können. Das Boot verfügt standardmäßig über eine Spiralantenne. HC-12-Funkgeräte sind sehr cool, die theoretische Reichweite (bei niedriger Bitrate, direkte Sicht) beträgt bis zu einem Kilometer. Ich füge zwei Dokumente bei, die für ihre Bedienung nützlich sein werden – sie enthalten eine Beschreibung der Funktionen und Konfiguration.

    Kalibrierung wird benötigt, um den Code an einen gegebenen Joystick (Neutralpunkt) und Servo (auch) anzupassen. Die Werte sind in den Kommentaren beschrieben.

    Ich habe keine Schaltpläne, aber ich denke, dass man anhand der Beschreibungen und Fotos leicht herausfinden kann, wo es langgeht. Ich weiß, dass es (besonders bei der Fernbedienung) ein Spinnennetz aus Kabeln gibt, aber ich verschwende meine Zeit nicht mit dem Entwerfen von Platinen, ich genieße Elektronik und das Schreiben von Programmen.
    Der Code ist stark kommentiert (auf Englisch), sodass das Verständnis der Programme kein Problem darstellen sollte. Die Reichweite in der gewählten Konfiguration (Funkbitrate, Antenne) beträgt mindestens 200 m (vielleicht mehr, habe ich nicht überprüft, bei einer solchen Entfernung ist es schwierig, das Modell zu steuern).
    Wenn es jemanden interessiert, lohnt es sich, dieses Thema zu verfolgen. Wenn es ein Update der Programme gibt, werde ich es hinzufügen.

    Unten findet man die Fotos und den Code.
    Fernsteuerung mit zwei Joysticks auf einer schwarzen Box für ferngesteuerte Geräte.

    Innenraum einer Fernbedienung mit elektronischen Komponenten und verbundenen Kabeln.

    Fahrgestell eines ferngesteuerten Automodells mit Arduino-Elektronik und Kabeln.

    Nahaufnahme des Inneren eines Gehäuses mit elektronischen Komponenten.

    Ferngesteuertes Offroad-Auto mit Antenne, stehend auf einem Holzboden.

    Elektronische Einrichtung mit Arduino-Modulen in einem ferngesteuerten Fahrzeug.

    Nahaufnahme von zwei Li-Ion-Batteriezellen in einem schwarzen Gehäuse, umgeben von Drähten und einer Sicherung.

    Ferngesteuertes Boot mit sichtbarem Innenraum und elektronischen Komponenten.

    Nahaufnahme der Elektronik in einem orangenen ferngesteuerten Boot.

    SENDER
    // delay(1);//It is necessary for proper message sending. Without this messages sometimes are merged.
    //$$ separates values, ! ends the message
    
    
    #include <SoftwareSerial.h>
    SoftwareSerial mySerial(2, 3); //RX, TX
    
    //L: 3-507-1017 --> 1020 for smooth operation [506;508]
    //R: 3-526-1017 --> 1020 for smooth operation [525;527]
    //STEER [R]: 0-517-1022 [521;523]
    int ax; //analog read joystick A
    byte af; //analog joystick A forward
    byte ab; //analog joystick A backward
    
    int bx; //analog read joystick B
    byte bf; //analog joystick B forward
    byte bb; //analog joystick B backward
    
    boolean mode = false; //Tank or Car mode (default: car)
    int buttontest; //conunting time of button being pressed
    
    String toSend;
    
    
    void setup()
    {
      pinMode(4, OUTPUT);
      pinMode(12, OUTPUT);
      pinMode(11, OUTPUT);
      pinMode(10, OUTPUT);
      pinMode(9, OUTPUT);
      pinMode(5, OUTPUT);
      pinMode(6, OUTPUT);
    
      digitalWrite(4, HIGH); //DISABLE AT MODE
      digitalWrite(12, HIGH);//RIGHT JOYSTICK VCC
      digitalWrite(11, LOW);//RIGHT JOYSTICK GND
      digitalWrite(10, HIGH);//LEFT JOYSTICK VCC
      digitalWrite(9, LOW);//LEFT JOYSTICK GND
      digitalWrite(5, LOW);//BUZZER GND
      digitalWrite(6, LOW);//BUZZER VCC
    
      pinMode(A0, INPUT); //LEFT JOYSTICK BUTTON
      pinMode(A1, INPUT); //RIGHT JOYSTICK BUTTON
      pinMode(A5, INPUT); //RIGHT JOYSTICK FORWARD & BACKWARD
      pinMode(A6, INPUT); //RIGHT JOYSTICK RIGHT & LEFT
      pinMode(A2, INPUT); //LEFT JOYSTICK FORWARD & BACKWARD
    
      Serial.begin(9600);
      pinMode(4, OUTPUT); //for MODE setup
      digitalWrite(4, LOW); //ENTER AT MODE
      delay(50);//necessary to wait after mode change
      mySerial.begin(9600);//9600 adjust after adjusting communication speed using AT+BXXX
      mySerial.println("AT+FU3");
      delay(50);
      mySerial.println("AT+B9600");//9600
      delay(50);
      mySerial.println("AT+RX"); //AT MODE REQUIRED TO BE ON (4 LOW)
      delay(100);
      digitalWrite(4, HIGH); //EXIT AT MODE
      delay(50);//necessary to wait after mode change
    }
    
    
    
    void loop()
    {
      //RESET OLD VALUES TO AVOID CONFLICTS
      af = 0;
      ab = 0;
      bf = 0;
      bb = 0;
    
    
    
      ////////////////////////////////STEERING MODE CHECK
      if (analogRead(A0) < 10) //BUTTON PRESSED
    
      {
        buttontest = buttontest + 1; //COUNTING TIME OF BUTTON BEING PRESSED
        mySerial.print("BUTTON PRESSED !");
        Serial.println("BUTTON PRESSED !");
      }
      else
      {
        buttontest = 0; //RESET IN CASE OF ACCIDENTAL CLICK
      }
    
      //Serial.println(buttontest);
    
      if (buttontest == 40 ) //BUTTON PRESSED - SENT LIGHT ADJUST SIGNAL
      {
        toSend = String("E") + "!"; 
        mySerial.print(toSend);
        delay(1);
        digitalWrite(6, HIGH);
        delay(100);
        digitalWrite(6, LOW);
        delay(100);
        digitalWrite(6, HIGH);
        delay(100);
        digitalWrite(6, LOW);
        delay(1000);
      }
    
    
      if (buttontest == 41) //BUTTON PRESSED - SENT LIGHT ON/OFF SIGNAL
      {
        toSend = toSend = String("F") + "!"; 
        mySerial.print(toSend);
        delay(1);
        digitalWrite(6, HIGH);
        delay(1000);
        digitalWrite(6, LOW);
      }
    
    
    
      if (buttontest >= 42) //BUTTON PRESSED - CHANGE TO TANK MODE
      {
        mode = !mode;
        buttontest = 0;
        mySerial.print("MODE CHANGED !");
        delay(1);
        Serial.println("MODE CHANGED !");
        digitalWrite(6, HIGH);
        delay(4000);
        digitalWrite(6, LOW);
      }
    
    
    
      ////////////////////////////////////////LEFT JOYSTICK READ & CALCULATE
      ax = analogRead(A2); //LEFT JOYSTICK
      //  if (mode == 1)
      //  {
      //    Serial.print("A2 LEFT:  ");
      //    Serial.println(ax);
      //  }
      //  else
      //  {
      //    Serial.print("A2 MOVE: ");
      //    Serial.println(ax);
      //  }
    
    
    
    //Serial.print("AX READ: ");
    //Serial.println(ax);
    
      //af is PWM for A engine forward
      if (ax > 508)
      {
        af = map(ax, 508, 1020, 0, 255); //af is PWM for A engine forward
        //Serial.print("LEFT FORWARD: ");
        //Serial.println(af);
        toSend = "A" + String(af, DEC) + "!"; 
        mySerial.print(toSend);
        delay(5);
      }
    
    if (ax >= 506 && ax <=508) //to send zero command in case of neutral joistick position
    {
         toSend = "A" + String(0, DEC) + "!";  
         mySerial.print(toSend);
         delay(5);
         toSend = "B" + String(0, DEC) + "!";  
         mySerial.print(toSend);
         delay(5);
    }
    
      if (ax < 506)
      {
        ab = map(ax, 3, 506, 255, 0); //ab is PWM for A engine backward
        //Serial.print("LEFT BACKWARD: ");
        //Serial.println(ab);
        toSend = "B" + String(ab, DEC) + "!"; 
        mySerial.print(toSend);
        delay(5);
      }
      ////////////////////////////////END OF LEFT JOYSTICK READ & CALCULATE
    
    
    
      ////////////////////////////////////////RIGHT JOYSTICK READ & CALCULATE
      ///////////READING POSITION FROM CORRECT JOYSTICK OUTPUT
      if (mode == 1)
      {
        bx = analogRead(A5); //IF IN TANK MODE
        //    Serial.print("A5 RIGHT: ");
        //   Serial.println(bx);
      }
      else
      {
        bx = analogRead(A4); //IF IN CAR MODE
        //Serial.print("A6 STEER: ");
        //Serial.println(bx);
      }
      ///////////END OF READING FROM CORRECT JOYSTICK OUTPUT
    
      ///////////CALCULATING PWM ACCORDING TO
      //JOYSTICK'S ZERO CALIBRATION POSITION
      if (mode == 1) //IF IN TANK MODE
      {
        if (bx > 527)
        {
          bf = map(bx, 527, 1020, 0, 255); // bf is PWM for B engine forward
          //Serial.print("RIGHT FORWARD: ");
          //Serial.println(bf);
          toSend = "C" + String(bf, DEC) + "!"; 
          mySerial.print(toSend);
          delay(5);
        }
    
        if (bx < 525)
        {
          bb = map(bx, 3, 527, 255, 0); //bb is PWM for B engine backward
          //Serial.print("RIGHT BACKWARD: ");
          //Serial.println(bb);
          toSend = "D" + String(bb, DEC) + "!"; 
          mySerial.print(toSend);
          delay(5);
        }
      }
      else //IF IN CAR MODE
      {
        if (bx > 517)
        {
          bf = map(bx, 517, 1022, 0, 255); //bf is PWM for B engine forward
          //Serial.print("STEER RIGHT: ");
          //Serial.println(bf);
          toSend = "C" + String(bf, DEC) + "!"; 
          mySerial.print(toSend);
          //Serial.println(toSend);
          delay(5);
        }
    
    if (bx >= 516 && bx <=517) //to send zero command in case of neutral joistick position
    {
         toSend = "C" + String(0, DEC) + "!";  
         mySerial.print(toSend);
         delay(5);
         toSend = "D" + String(0, DEC) + "!";  
         mySerial.print(toSend);
         delay(5);
    }
    
        if (bx < 516)
        {
          bb = map(bx, 0, 517, 255, 0); //bb is PWM for B engine backward
          //Serial.print("STEER LEFT: ");
          //Serial.println(bb);
          toSend = "D" + String(bb, DEC) + "!"; 
          mySerial.print(toSend);
          //Serial.println(toSend);
          delay(5);
        }
      }
    
      ////////////////RIGHT JOYSTICK DIAG
      //Serial.print("AX: ");
      //Serial.println(ax);
      //Serial.print("BX: ");
      //Serial.println(bx);
      /////////////////////////////////END OF LEFT JOYSTICK READ & CALCULATE
    
    
    }// END OF LOOP


    EMPFÄNGER
    #include <SoftwareSerial.h>
    #include <Adafruit_NeoPixel.h>
    //#include <EEPROM.h>
    #include <PWMServo.h>//software PWM used because servo library had conflict with other used functions using PWM generated by the same internal closk
    PWMServo myservo;  // create servo object to control a servo
    SoftwareSerial mySerial(2, 3); //RX, TX
    Adafruit_NeoPixel
    strip = Adafruit_NeoPixel(3, 13, NEO_GRB + NEO_KHZ800); //NO of pixels, PIN
    byte af, ab, bf, bb;
    boolean light = 0; //LIGHT ON/OFF, default = OFF
    boolean change = false; // flag to mark change to use WS2812B communication once for light ON/OFF. Constant communication interrupts message receiving
    boolean lightadjustment = false; // flag to mark change to use WS2812B communication once for light level adjustment. Constant communication interrupts message receiving
    byte xy; //light brightness pre set setting
    byte brightness = 64; //brightness level (0-255), default = 64
    boolean boatmode;// if true, then boat mode
    byte modecount = 0; //no. of successful read sequences
    int  bootval;// voltage check at boot to detect whether it is a boat or not
    byte neutral = 85; //neutral position of servo
    byte servoangle; //servo's angle
    int serwoPWM;// calculated value to steer servo by generating PWM
    unsigned long counter; //time from last message
    unsigned long nowtime; //time now. Used further to calculate time past since previous loop
    //unsigned long pinginterval; // for signalling range ping messages
    float voltageread; //voltage read at input
    float batvoltage; //calculated battery level (incl. calculated offset)
    byte mediumdischargecount = 0; //to avoid one - time battery voltage drops,alarm will be activated after few times threshold is reached
    byte deepdischargecount = 0; //to avoid one - time battery voltage drops,alarm will be activated after few times threshold is reached
    long mediumbatlevelalarmtime; //time of buzzer's activation
    boolean mediumbatlevelalarmactivation = false;
    boolean deepdischargealarmactivation = false;
    
    //int lowestbatvoltage; ////////////////////USED ONLY AT BOOT TO HAVE ANY VALUE FOR IF FUNCTION TO COMPARE TO
    //int lowestbatEEPROM;
    
    
    
    void setup()
    {
      //writeIntIntoEEPROM(7000);//EEPROM LOW RESET USED TO START A NEW RECORDING
      //PIN D11 BURNT !!!!!!!!!!!!
      //PINS A6&A7 cannot be used as analog output in Arduino Nano
      pinMode(4, OUTPUT); //AT MODE SWITCH
      pinMode(5, OUTPUT);
      pinMode(6, OUTPUT);
      pinMode(10, OUTPUT);//SERVO
      pinMode(13, OUTPUT); //built in led + WS2812B
      pinMode(A1, OUTPUT); //GND for voltage sensing
      pinMode(A0, INPUT); //voltage check at boot to detect whether it is a boat or not
      pinMode(A2, INPUT); //battery voltage check
      pinMode(A5, OUTPUT); //low battery buzzer output
      digitalWrite(A1, LOW); //GND for voltage sensing
      digitalWrite(A5, LOW); //deactivate buzzer
      digitalWrite(4, LOW); //ENTER AT MODE
      delay(50);//necessary to wait after AT mode change
    
      Serial.begin(9600);
      mySerial.begin(9600);//adjust after adjusting communication speed using AT+BXXX
      mySerial.println("AT+FU3");
      delay(50);
      mySerial.println("AT+B9600");
      delay(50);
      mySerial.println("AT+RX"); //AT MODE REQUIRED TO BE ON (4 LOW)
      delay(100);
      digitalWrite(4, HIGH); //EXIT AT MODE
      delay(50);//necessary to wait after mode change\
      analogReference(INTERNAL); //1,1V
      modecheck(); //Function to detect whether hardware is a boat or not
    
      analogReference(INTERNAL); //1,1V for battery measurement
    
      if (boatmode == true)
      {
        myservo.attach(SERVO_PIN_B); //Library works only at PIN9 and 10 (already used)
        servostart(); //Sequence for servo movement at boat's boot
        testbeep(); //Test buzzer
        //Serial.print("LOWEST VOLTAGE FROM EEPROM: ");
        //Serial.println(readIntFromEEPROM());
      }
      else
      {
        strip.begin(); // INITIALIZE NeoPixel strip object
        strip.clear();
        strip.show();
        startsequence(); //LED BLINK at car's boot
      }
    } ///////////////////////////////////////////END OF SETUP
    
    
    void loop()
    {
      ///////////////////////LOST CONNECTION PROTECTION
      nowtime = millis();
      if ((nowtime - counter) > 1000) //1000 MS SIGNAL LOST TRIGGER
      {
        //Serial.println(nowtime-counter);
        //Serial.println("CONNECTION LOST !!!");
        if (boatmode == false) //IF IN CAR MODE
        {
          digitalWrite(11, LOW);
          digitalWrite(10, LOW);
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
        else //IF IN BOAT MODE
        {
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
      }
      ///////////////////////END OF LOST CONNECTION PROTECTION
    
      //////////////////////////100 MS SIGNAL PING TRIGGER
      //    if ((nowtime - pinginterval) > 50)
      //    {
      //      //Serial.println("PING INTERVAL");
      //      //Serial.println(nowtime-pinginterval);//Loop time
      //      pinginterval = millis();
      //      ();
      //    }
      ///////////////////////END OF SIGNAL PING TRIGGER
    
    
      ////////////////////////////////////// MESSAGE RECEIVING
      while (mySerial.available())
      {
        static String receivedMessage = ""; // Store the received message
        char receivedChar = mySerial.read();
    
        if (receivedMessage.length() == 0)
        {
          if (receivedChar == 'A' || receivedChar == 'B' || receivedChar == 'C' || receivedChar == 'D')
          {
            receivedMessage = receivedChar; // Start building the message with the received character
          }
          if (receivedChar == 'F')
          {
            light = !light;
            change = true; // FLAG FOR LIGHT STATE CHANGE
            //Serial.println("LIGHT ON/OFF !");
          }
          if (receivedChar == 'E')
          {
            lightadjustment = true; // FLAG FOR LIGHT ADJUSTMENT
          }
        }//////////////END OF receivedMessage.length() == 0
    
        else
        {
          if (receivedChar == '!')
          {
            // Message received and ends with '!'
            Serial.println(receivedMessage);//////////////////////////////////////
            // Serial.println("MESSAGE RECEIVED, CONNECTION OK!");
            counter = millis();
            processMessage(receivedMessage, boatmode, neutral, deepdischargealarmactivation);
            receivedMessage = ""; // Clear the received message for the next one
          }
          else
          {
            receivedMessage += receivedChar;
          }
        }
      }//END OF WHILE
      /////////////////////////////////// END OF MESSAGE RECEIVING
    
      ////////////////////////////////// LIGHT ON&OFF
      if (light == true && change == true) //turn ON the light to the pre set level
      {
        change = false; //function activated only once
        lighton(); // turn ON the light function
      }
    
      if (light == false && change == true) //turn OFF the light
      {
        change = false; //function activated only once
        lightoff(); // turn the light OFF function
      }
      ////////////////////////////////// END OF LIGHT ON&OFF
    
    
      ////////////////////////////////// LIGHT LEVEL & ADJUST
      if (lightadjustment == true)
      {
        if (xy == 0)
        {
          Serial.println("MAX");
          strip.setBrightness(255);
          strip.show();
          xy = 1;
          lightadjustment = false;
        }
      }
    
      if (lightadjustment == true)
      {
        if (xy == 1)
        {
          Serial.println("DEFAULT");
          strip.setBrightness(64);
          strip.show();
          xy = 0;
          lightadjustment = false;
        }
      }
      ////////////////////////////////// END OF LIGHT LEVEL &ADJUST
    
    
      /////////////////////////////////// VOLTAGE READ AND BUZZER ACTIVATION
      if (boatmode == true)
      {
        voltageread = analogRead(A2);
        //Serial.println(voltageread);
        batvoltage = 10.88 * (long)voltageread * 1100 / 1024; //Convert voltageread to long to correctly handle multiplication (without int overflow). Voltage appplied through 1/10 divider. 0.88 after 10 for calibration
        //Serial.print("READ BATTERY VOLTAGE: ");
        //Serial.println(batvoltage);
      }
    
      //batvoltage=1.3;// BUZZER & LOW BATTERY PWM TEST
    
    
      if (batvoltage <= 6.6)
      {
        if (mediumbatlevelalarmactivation == false) //if medium battery level alarm has not been activated yet
        {
          mediumdischargecount = mediumdischargecount + 1;
          //Serial.print("MEDIUM BAT VOLTAGE COUNT:");
          //Serial.println(mediumdischargecount);
        }
      }
    
      if (batvoltage <= 5.8)
      {
        if (deepdischargealarmactivation == false) ////if battery deep discharge alarm has not been activated yet
        {
          deepdischargecount = deepdischargecount + 1;
          //Serial.print("DEEP BAT VOLTAGE COUNT:");
          //Serial.println(deepdischargecount);
        }
      }
    
      if (mediumdischargecount == 10) //medium battery level alarm activation
      {
        if (mediumbatlevelalarmactivation == false) //activate medium battery alarm only once
        {
          mediumbatlevelalarmtime = millis();
          Serial.println("MEDIUM BATTERY LEVEL ALARM !!!");
          digitalWrite(A5, HIGH); //activate buzzer
          mediumbatlevelalarmactivation = true; //medium battery alarm will not be activated again
        }
      }
    
      if (((millis() - mediumbatlevelalarmtime) > 10000 && (millis() - mediumbatlevelalarmtime) < 14000) ) //if alarm has been activated for more than 10 seconds but only once
      {
        digitalWrite(A5, LOW); //turn off the buzzer
      }
    
      if (deepdischargecount == 10) //low battery level alarm activation
      {
        digitalWrite(A5, HIGH); //activate buzzer
        if (deepdischargealarmactivation == false)
        {
          Serial.println("LOW BATTERY LEVEL ALARM !!!"); //send message only once
        }
        deepdischargealarmactivation = true;
        digitalWrite(A5, HIGH); //permanently activate the buzzer
      }
    
      /////////////////////////////////// END OF VOLTAGE READ AND BUZZER ACTIVATION
    
      //  /////////////////////////////////// VOLTAGE READ AND EEPROM READ&WRITE
      //  if (boatmode == true)
      //  {
      //    voltageread = analogRead(A2);
      //    Serial.print("ANALOG VOLTAGE: ");
      //    Serial.println(voltageread);
      //    batvoltage = 10.88 * (long)voltageread * 1100 / 1024; //Convert voltageread to long to correctly handle multiplication (without int overflow). Voltage appplied through 1/10 divider. 0.88 after 10 for calibration
      //    Serial.print("READ   VOLTAGE: ");
      //    Serial.println(batvoltage);
      //
      //    if (batvoltage > 3000) //to prevent from reading when battery is not connected (analog pin is grounded by 1k resistor)
      //    {
      //      if (batvoltage < lowestbatEEPROM) //if current voltage is lower than the lowest recorded in EEPROM
      //      {
      //        lowestbatvoltage = batvoltage;
      //        writeIntIntoEEPROM(lowestbatvoltage);
      //        Serial.print("!!!!!! NEW LOWEST VOLTAGE RECORDED: ");
      //        Serial.println(lowestbatvoltage);
      //      }
      //    }
      //
      //    Serial.print("LOWEST VOLTAGE: ");
      //    Serial.print(lowestbatvoltage);
      //    Serial.println(" (SINCE BOOT)");
      //    lowestbatEEPROM = readIntFromEEPROM(); //read lowest battery value stored in EEPROM
      //    Serial.print("LO BAT EEPROM : ");
      //    Serial.println(lowestbatEEPROM);
      //  }/////////////////////////////////// END OF VOLTAGE READ AND EEPROM READ&WRITE
    
    
    }////////////////////////////////////END OF LOOP
    
    
    
    ////////////////////////////////////FUNCTIONS///////////////////////////////////////////
    
    ///////////////////////////////////////////PROCESS MESSAGE
    void processMessage(String receivedMessage, boolean boatmode, byte bootval, boolean deepdischargealarmactivation)
    {
      //Serial.println(receivedMessage); //////////////////////////////// RECEIVED MESSAGE
    
      if (receivedMessage.charAt(0) == 'A')
      {
        af = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'B')
      {
        ab = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'C')
      {
        bf = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'D')
      {
        bb = receivedMessage.substring(1).toInt();
      }
    
    
      if (boatmode == false) //////////////////////PWM GENERATION IF IN CAR MODE
      {
        if (af > 3) //A FORWARD PWM&LOW
        {
          analogWrite(11, af);
          digitalWrite(10, LOW);
        }
    
        if (ab > 3) //A BACKWARD PWM&LOW
        {
          digitalWrite(11, LOW);
          analogWrite(10, ab);
        }
    
        if (bf > 3) //B FORWARD PWM&LOW
        {
          analogWrite(6, bf);
          digitalWrite(5, LOW);
        }
    
        if (bb > 3) //B BACKWARD ENGINE PWM&LOW
        {
          digitalWrite(6, LOW);
          analogWrite(5, bb);
        }
    
        if (bf <= 3 && bb <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT(DO NOT INTERPRETE "0" VALUE)
        {
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
    
        if (af <= 3 && ab <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT (DO NOT INTERPRETE "0" VALUE)
        {
          digitalWrite(10, LOW);
          digitalWrite(11, LOW);
        }
      } ////////////////////////END OF CAR MODE PWM GENERATION
    
      else//////////////////////PWM GENERATION IF IN BOAT MODE
      {
        if (af > 3) //A FORWARD PWM&LOW
        {
          if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
          {
            analogWrite(5, af);
            digitalWrite(6, LOW);
          }
          else //if deep battery discharege alarm is activated
          {
            analogWrite(5, (af / 3)); //speed reduced by 33%
            digitalWrite(6, LOW);
          }
        }
    
        if (ab > 3) //A BACKWARD PWM&LOW
        {
          if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
          {
            digitalWrite(5, LOW);
            analogWrite(6, ab);
          }
          else //if deep battery discharege alarm is activated
          {
            digitalWrite(5, LOW);
            analogWrite(6, (ab / 3)); //speed reduced by 33%
          }
        }
    
        if (bf > 3) //B FORWARD PWM&LOW
        {
          servoangle = map(bf, 3, 255, neutral, (neutral - 55));
          myservo.write(servoangle);
        }
    
        if (bb > 3) //B BACKWARD ENGINE PWM&LOW
        {
          servoangle = map(bb, 3, 255, neutral, (neutral + 55));
          myservo.write(servoangle);
        }
    
    
        if (af <= 3 && ab <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT (DO NOT INTERPRETE "0" VALUE)
        {
          digitalWrite(5, LOW);
          digitalWrite(6, LOW);
        }
    
        if (bf <= 3 && bb <= 3) //FOR NEUTRAL POSITIONAS PROGRAM DO NOT ZERO BY DEFAULT(DO NOT INTERPRETE "0" VALUE)
        {
          myservo.write(neutral);
        }
      } ////////////////////////END OF BOAT MODE PWM GENERATION
    
      //    FOR DEBUG ONLY. USING INTERRUPTS RECEIVED SIGNAL & OPERATION
      //    Serial.print("AF: ");
      //    Serial.println(af);
      //    Serial.print("AB: ");
      //    Serial.println(ab);
      //    Serial.print("BF: ");
      //    Serial.println(bf);
      //    Serial.print("BB: ");
      //    Serial.println(bb);
      //    FOR DEBUG ONLY. USING INTERRUPTS RECEIVED SIGNAL & OPERATION
    } /////////////////////////////////////////////////Process Message End
    
    void lighton()
    {
      strip.setBrightness(brightness);
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
    }
    
    void lightoff()
    {
      strip.setBrightness(0);
      strip.show();
    }
    
    void startsequence() //LED BLINK AT START
    {
      digitalWrite(13, HIGH); //BUILT IN LED ON
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
      delay(50);
      digitalWrite(13, LOW); //BUILT IN LED OFF
      strip.setBrightness(0);
      strip.show();
      delay(50);
      digitalWrite(13, HIGH); //BUILT IN LED ON
      strip.setBrightness(255);
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
      delay(50);
      digitalWrite(13, LOW); //BUILT IN LED OFF
      strip.setBrightness(0);
      strip.show();
    }
    
    void servostart() //SEQUENCE OF SERVO MOVEMENTS AT START
    {
      myservo.write(neutral + 55);                // sets the servo position according to the scaled value
      delay(200);
      myservo.write(neutral - 55);                // sets the servo position according to the scaled value
      delay(200);
      myservo.write(neutral); // sets the servo position according to the scaled value
      delay(100);
    }
    
    void testbeep()
    {
        digitalWrite(A5, HIGH);
        delay(50);
        digitalWrite(A5, LOW);  
        delay(50);
        digitalWrite(A5, HIGH);
        delay(50);
        digitalWrite(A5, LOW);
        delay(50);
        digitalWrite(A5, HIGH);
        delay(50);
        digitalWrite(A5, LOW);  
    }
    
    boolean modecheck() //voltage check at boot to detect whether it is a boat or not
    {
      for (byte i = 0; i < 5; i++)
      {
        bootval = analogRead(A0);
        if (bootval > 600 && bootval < 700) //A0 value at USB approx. 659. 655, 665, at boat different
        {
          modecount = modecount + 1;
        }
        delay(100);
      }
    
      if (modecount == 5)
      {
        boatmode = true;
        Serial.println("BOAT MODE !");
        return boatmode;
      }
      else
      {
        Serial.println("CAR MODE !");
      }
    }// END OF MODE CHECK
    
    //void writeIntIntoEEPROM(int lowestbatvoltage)
    //{
    //  EEPROM.update(0, lowestbatvoltage >> 8); //address, variable. Shift by 8n bite, meaning saving only firts 8 bits from the digit in the first (out of two) bytes
    //  EEPROM.update(0 + 1, lowestbatvoltage & 0xFF); //For the second byte, we make an AND operation with 0xFF, which is the hexadecimal representation of 255 (you could write “& 255” instead of “& 0xFF”). This way, we only get the 8 bits on the right.
    //}
    //
    //int readIntFromEEPROM()
    //{
    //  return lowestbatEEPROM = (EEPROM.read(0) << 8) + EEPROM.read(0 + 1);
    //}
    
    //void sendping()
    //{
    //  mySerial.print("XXXXX");
    //  Serial.println("!"); //////////////////////////////// PING SENT
    //}

    Cool? DIY-Rangliste
    Hast du ein Problem mit Arduino? Stelle bei uns eine Frage. Besuche unser Arduino-Forum.
    Über den Autor
    Frog_Qmak
    Niveau 25  
    Offline 
    Frog_Qmak hat 1319 Beiträge geschrieben mit der Bewertung 293, und dabei 7 Mal geholfen. Wohnt in der Stadt Kraków. Er ist seit 2007 bei uns.
  • WERBUNG
  • #2 20840369
    gulson
    Forenbetreiber
    Vielen Dank für die Prä­sen­ta­ti­on. Projekte rund um RC-Modelle gab es schon lange nicht mehr. Gib mir mal Packstation an und ich schicke dir ein kleines Geschenk!
  • #3 20840472
    Karol966
    Niveau 31  
    Einer der Geschäfte schrieb:
    „Übertragungsreichweite: von 1 m bis 1000 m (weniger als 1 Meter, es funktioniert möglicherweise nicht richtig)“, im Ernst, können damit bis zu 1000 Meter erreicht werden?
  • #4 20840483
    Frog_Qmak
    Niveau 25  
    Ich habe es nicht ausprobiert – vielleicht ist es mit der niedrigsten Bitrate und der Verwendung von Richtantennen möglich. Ich war positiv überrascht, als sich herausstellte, dass er die 200 m schafft (ich habe es nicht weiter probiert) mit der „Spiral“-Antenne am Empfänger, teilweise versteckt im Plastikboot und zusätzlich von mir abgedeckt (ich ging mit dem Rücken zum Sender und trug es in meinen Händen).
  • #5 20841216
    Jawi_P
    Niveau 36  
    Ich habe noch nichts von HC-12-Modulen gehört, vielleicht probiere ich es eines Tages mal aus. Schön, dass das RC-Projekt erschienen ist.
  • WERBUNG
  • #6 20841316
    ArturAVS
    Moderator
    @Frog_Qmak, hast du über den Einsatz von LoRa-Modulen nachgedacht? Oder z. B. nRF24L01? Ich hatte ein paar Sachen angesammelt und wollte etwas bauen.
  • #7 20841809
    Frog_Qmak
    Niveau 25  
    Ich habe im Internet eine Anleitung für dieses Radio gefunden :) Ich habe es einmal mit NRF versucht, aber es gelang mir nicht, sie zum Laufen zu bringen, also landeten sie in der Box, und dann, nach ein paar Jahren, stieß ich auf HC :) Ich habe LoRa noch nicht ausprobiert und weiß nicht, wie teuer sie sind :)
  • WERBUNG
  • #8 20842248
    bb84
    Niveau 21  
    So etwas wäre nützlich, um ein U-Boot in einer Tiefe von 2-3 m zu steuern.
  • #9 20842364
    Krzysztof Kamienski
    Niveau 43  
    @Frog_Qmak, vielleicht ist es nicht dumm, aber mit dem Bearbeitungsstil hast du mir den Appetit aufs Frühstück verdorben. Entschuldigung.
  • #10 20842596
    Frog_Qmak
    Niveau 25  
    @Krzysztof Kamienski, ich weiß, dass es drinnen nicht so toll ist, ;) aber übermäßiges Verwöhnen gibt mir keine Befriedigung, ich entwickle lieber das Programm oder neue Modelle und habe Spaß damit, als mich zu zwingen und „auszubrennen“.
  • #12 20843857
    Frog_Qmak
    Niveau 25  
    Ein Boot (Feilun FT009) angeblich 30 km/h, ein großes Auto (Revell Aqua Crawler) angeblich 20 km/h :) Ich werde das Boot nur im Freien testen, aber es hat einen speziellen Motor mit Wasserkühlung, der 8-12 A verbraucht.
  • #13 20850945
    mpier
    Niveau 29  
    Hallo
    Ich kenne die Module nicht und habe mich nicht allzu sehr mit dem Code befasst, aber die im Programm verwendete Sendemethode könnte (hat?) einen großen Nachteil haben – den hohen Overhead des si4463-Protokolls. Hinzu kommt die Verzögerung von stm8s selbst, das nicht weiß, wie viele Daten du sendest, und wahrscheinlich eine bestimmte Zeit nach dem letzten Byte wartet, bevor es sie an den Sender sendet (daher wahrscheinlich die Verzögerung (5 ms) nach der Übertragung).
    Wenn du außerdem jeweils einen Kanal empfängst und den Timer jedes Mal ab dem zuletzt empfangenen Paket aktualisierst, besteht eine geringe Chance, dass du nur vorübergehend weniger wichtige Pakete senden kannst und die benötigten Pakete nicht ankommen und der Empfänger es nicht bemerkt (z. B. diejenigen zum Bremsen werden nicht ankommen).

    Ich denke, dass du durch das gemeinsame Senden aller Daten und die Auswahl der entsprechenden Datenlänge (wahrscheinlich ist Platz für die Prüfsumme und möglicherweise die Paketnummer) die Steuerungsgeschwindigkeit und Fehlererkennungseffizienz erhöhen und gleichzeitig den Bandbreitenverbrauch (durchschnittlich) reduzieren kannst (die Übertragungszeit wird sich erheblich verkürzen). Anhand der Paketnummer kannst du die Signalqualität ermitteln und z. B. im Falle einer schwachen Batterie reagieren.

    Bei kleineren Autos sollte dieses hc12-Modul ohne Arduino funktionieren, wenn du es neu programmierst.

    Grüße
  • WERBUNG
  • #14 20850977
    Frog_Qmak
    Niveau 25  
    Hallo, vielen Dank für die wertvolle Bemerkung.
    Bei einem großen Modell (das beispielsweise aufgrund seines Gewichts eine Gefahr darstellen könnte) oder anderen Anwendungen, bei denen es auf Zuverlässigkeit ankommt, müsste darauf geachtet werden.
    In meinem speziellen Fall sendet die Fernbedienung ununterbrochen Daten. Wenn sich der Joystick also in der neutralen Position befindet, empfängt der Empfänger dieses Paket (auch wenn nicht beim ersten Mal).
    Zuvor hatte ich mit dem von dir beschriebenen Problem zu kämpfen (Nachrichtenlänge – alle Positionen werden in einer Nachricht gesendet), aber ich habe den Code optimiert und jetzt sind die Nachrichten viel kürzer.
    Gute Idee mit dieser Paketnummerierung zur Beurteilung der Signalqualität – das muss ich mir merken!
  • #15 21046407
    Frog_Qmak
    Niveau 25  
    Hallo,

    Ich füge aktualisierte (verbesserte) Versionen der Software für Sender und Empfänger hinzu.


    Wichtigste Änderungen:
    1. Ich habe Unterstützung für Modellmotorsteuerungen (ESC) hinzugefügt, als Alternative zu H-Brücken. Ich hatte viele Probleme mit brennenden H-Brücken (der Motor verbraucht sowieso 10...13A, erzeugt also viele Überspannungen*). Ich habe mehrere Monate mit dem Testen verschiedener Lösungen verbracht, habe dann auf den Redox Ultra 45-Regler gesetzt. Es ist wichtig, dass der Regler beim Start „scharf“ gesetzt werden muss, indem die neutrale Position des Steuerknüppels beim Start und die entsprechende Reihenfolge der Bewegungen simuliert werden (maximal nach unten, maximal nach oben, neutral). Ich hatte ein weiteres „chinesisches“ 20 A auf dem Weg (viele davon auf Allegro), ich habe viele Kombinationen getestet, keine davon hat funktioniert. Redox begann sofort.
    2. Ich habe im Sender ein zweites "!" hinzugefügt am Ende der Nachricht. Oft ging ein einzelner "verloren" (ich nehme an, es könnte eine Frage der weiteren Optimierung des Empfängercodes oder einiger Konflikte in seinen Timern gewesen sein), was zu Betriebsinstabilität ("Vibrationen" des Servos und Mikrounterbrechungen des Motors führte). ). Das zweite Zeichen schadet nichts und die Probleme verschwanden sofort.
    3. Diverse kleinere Optimierungen am Code und seiner Lesbarkeit.

    *Ich habe auf diese Weise viele Brücken verbrannt, ebenso den in Arduino eingebauten Stabilisator. Transile und zusätzliche Kondensatoren haben nicht geholfen. Wer Interesse hat, dem schicke ich es gerne zu VERKNÜPFUNG zum Thread.

    SENDER
    
    //! ends the message. 2x ! are used, because sometimes single "!" was lost causing receiver merge two messages together which resulted in noise.
    
    #include <SoftwareSerial.h>
    SoftwareSerial mySerial(2, 3); //RX, TX
    
    //L: 3-507-1017 --> 1020 for smooth operation [506;508]
    //R: 3-526-1017 --> 1020 for smooth operation [525;527]
    //STEER [R]: 0-517v518-1022 [521;523]
    int ax; //analog read joystick A
    byte af; //analog joystick A forward
    byte ab; //analog joystick A backward
    
    int bx; //analog read joystick B
    byte bf; //analog joystick B forward
    byte bb; //analog joystick B backward
    
    boolean mode = false; //Tank or Car mode (default: car)
    int buttontest; //conunting time of button being pressed
    
    String toSend;
    
    
    void setup()
    {
      pinMode(4, OUTPUT);
      pinMode(12, OUTPUT);
      pinMode(11, OUTPUT);
      pinMode(10, OUTPUT);
      pinMode(9, OUTPUT);
      pinMode(5, OUTPUT);
      pinMode(6, OUTPUT);
    
      digitalWrite(4, HIGH); //DISABLE AT MODE
      digitalWrite(12, HIGH);//RIGHT JOYSTICK VCC
      digitalWrite(11, LOW);//RIGHT JOYSTICK GND
      digitalWrite(10, HIGH);//LEFT JOYSTICK VCC
      digitalWrite(9, LOW);//LEFT JOYSTICK GND
      digitalWrite(5, LOW);//BUZZER GND
      digitalWrite(6, LOW);//BUZZER VCC
    
      pinMode(A0, INPUT); //LEFT JOYSTICK BUTTON
      pinMode(A1, INPUT); //RIGHT JOYSTICK BUTTON
      pinMode(A5, INPUT); //RIGHT JOYSTICK FORWARD & BACKWARD
      pinMode(A6, INPUT); //RIGHT JOYSTICK RIGHT & LEFT
      pinMode(A2, INPUT); //LEFT JOYSTICK FORWARD & BACKWARD
    
      Serial.begin(9600);
      pinMode(4, OUTPUT); //for MODE setup
      digitalWrite(4, LOW); //ENTER AT MODE
      delay(50);//necessary to wait after mode change
      mySerial.begin(9600);//9600 adjust after adjusting communication speed using AT+BXXX
      mySerial.println("AT+FU3");
      delay(50);
      mySerial.println("AT+B9600");//9600
      delay(50);
      mySerial.println("AT+RX"); //AT MODE REQUIRED TO BE ON (4 LOW)
      delay(100);
      digitalWrite(4, HIGH); //EXIT AT MODE
      delay(50);//necessary to wait after mode change
    }
    
    
    
    void loop()
    {
      //RESET OLD VALUES TO AVOID CONFLICTS
      af = 0;
      ab = 0;
      bf = 0;
      bb = 0;
    
    
    
      ////////////////////////////////STEERING MODE CHECK
      if (analogRead(A0) < 10) //BUTTON PRESSED
    
      {
        buttontest = buttontest + 1; //COUNTING TIME OF BUTTON BEING PRESSED
        mySerial.print("BUTTON PRESSED !");
        Serial.println("BUTTON PRESSED !");
      }
      else
      {
        buttontest = 0; //RESET IN CASE OF ACCIDENTAL CLICK
      }
    
      //Serial.println(buttontest);
    
      if (buttontest == 40 ) //BUTTON PRESSED - SENT LIGHT ADJUST SIGNAL
      {
        toSend = String("E") + "!"; 
        mySerial.print(toSend);
        delay(1);
        digitalWrite(6, HIGH);
        delay(100);
        digitalWrite(6, LOW);
        delay(100);
        digitalWrite(6, HIGH);
        delay(100);
        digitalWrite(6, LOW);
        delay(1000);
      }
    
    
      if (buttontest == 41) //BUTTON PRESSED - SENT LIGHT ON/OFF SIGNAL
      {
        toSend = toSend = String("F") + "!"; 
        mySerial.print(toSend);
        delay(1);
        digitalWrite(6, HIGH);
        delay(1000);
        digitalWrite(6, LOW);
      }
    
    
    
      if (buttontest >= 42) //BUTTON PRESSED - CHANGE TO TANK MODE
      {
        mode = !mode;
        buttontest = 0;
        mySerial.print("MODE CHANGED !");
        delay(1);
        Serial.println("MODE CHANGED !");
        digitalWrite(6, HIGH);
        delay(4000);
        digitalWrite(6, LOW);
      }
    
    
    
      ////////////////////////////////////////LEFT JOYSTICK READ & CALCULATE
      ax = analogRead(A2); //LEFT JOYSTICK
      //  if (mode == 1)
      //  {
      //    Serial.print("A2 LEFT:  ");
      //    Serial.println(ax);
      //  }
      //  else
      //  {
      //    Serial.print("A2 MOVE: ");
      //    Serial.println(ax);
      //  }
    
    
    
    //Serial.print("AX READ: ");
    //Serial.println(ax);
    
      //af is PWM for A engine forward
      if (ax > 508)
      {
        af = map(ax, 508, 1020, 0, 255); //af is PWM for A engine forward
        //Serial.print("LEFT FORWARD: ");
        //Serial.println(af);
        toSend = "A" + String(af, DEC) + "!!"; 
        mySerial.print(toSend);
        delay(5);
      }
    
    if (ax >= 506 && ax <=508) //to send zero command in case of neutral joistick position
    {
         toSend = "A" + String(0, DEC) + "!!";  
         mySerial.print(toSend);
         delay(5);
         toSend = "B" + String(0, DEC) + "!!";  
         mySerial.print(toSend);
         delay(5);
    }
    
      if (ax < 506)
      {
        ab = map(ax, 3, 506, 255, 0); //ab is PWM for A engine backward
        //Serial.print("LEFT BACKWARD: ");
        //Serial.println(ab);
        toSend = "B" + String(ab, DEC) + "!!"; 
        mySerial.print(toSend);
        delay(5);
      }
      ////////////////////////////////END OF LEFT JOYSTICK READ & CALCULATE
    
    
    
      ////////////////////////////////////////RIGHT JOYSTICK READ & CALCULATE
      ///////////READING POSITION FROM CORRECT JOYSTICK OUTPUT
      if (mode == 1)
      {
        bx = analogRead(A5); //IF IN TANK MODE
        //    Serial.print("A5 RIGHT: ");
        //   Serial.println(bx);
      }
      else
      {
        bx = analogRead(A4); //IF IN CAR MODE
        //Serial.print("A6 STEER: ");
        //Serial.println(bx);
      }
      ///////////END OF READING FROM CORRECT JOYSTICK OUTPUT
    
      ///////////CALCULATING PWM ACCORDING TO
      //JOYSTICK'S ZERO CALIBRATION POSITION
      if (mode == 1) //IF IN TANK MODE
      {
        if (bx > 527)
        {
          bf = map(bx, 527, 1020, 0, 255); // bf is PWM for B engine forward
          //Serial.print("RIGHT FORWARD: ");
          //Serial.println(bf);
          toSend = "C" + String(bf, DEC) + "!!"; 
          mySerial.print(toSend);
          delay(5);
        }
    
        if (bx < 525)
        {
          bb = map(bx, 3, 527, 255, 0); //bb is PWM for B engine backward
          //Serial.print("RIGHT BACKWARD: ");
          //Serial.println(bb);
          toSend = "D" + String(bb, DEC) + "!!"; 
          mySerial.print(toSend);
          delay(5);
        }
      }
      else //IF IN CAR MODE
      {
        if (bx > 520)
        {
          bf = map(bx, 517, 1022, 0, 255); //bf is PWM for B engine forward
          //Serial.print("STEER RIGHT: ");
          //Serial.println(bf);
          toSend = "C" + String(bf, DEC) + "!!"; 
          mySerial.print(toSend);
          //Serial.println(toSend);
          delay(5);
        }
    
    if (bx >= 515 && bx <=520) //to send zero command in case of neutral joistick position
    {   
         toSend = "C" + String(0, DEC) + "!!";  
         mySerial.print(toSend);
         delay(5);
         toSend = "D" + String(0, DEC) + "!!";  
         mySerial.print(toSend);
         delay(5);
    }
    
        if (bx < 515)
        {
          bb = map(bx, 0, 517, 255, 0); //bb is PWM for B engine backward
          //Serial.print("STEER LEFT: ");
          //Serial.println(bb);
          toSend = "D" + String(bb, DEC) + "!!"; 
          mySerial.print(toSend);
          //Serial.println(toSend);
          delay(5);
        }
      }
    
      ////////////////RIGHT JOYSTICK DIAG
    //  Serial.print("AX: ");
    //  Serial.println(ax);
    //  Serial.print("BX: ");
    //  Serial.println(bx);
      /////////////////////////////////END OF LEFT JOYSTICK READ & CALCULATE
    
    
    }// END OF LOOP
    


    EMPFÄNGER
    
    #include <SoftwareSerial.h>
    #include <Adafruit_NeoPixel.h>
    //#include <EEPROM.h>
    #include <PWMServo.h>//software PWM used because servo library had conflict with other used functions using PWM generated by the same internal clock
    PWMServo myservo;  // create servo object to control a servo
    PWMServo esc;  // create servo object to control an ESC (motor controller)
    SoftwareSerial mySerial(2, 3); //RX, TX
    Adafruit_NeoPixel
    strip = Adafruit_NeoPixel(3, 13, NEO_GRB + NEO_KHZ800); //NO of pixels, PIN
    byte af, ab, bf, bb;
    boolean light = 0; //LIGHT ON/OFF, default = OFF
    boolean change = false; // flag to mark change to use WS2812B communication once for light ON/OFF. Constant communication interrupts message receiving
    boolean lightadjustment = false; // flag to mark change to use WS2812B communication once for light level adjustment. Constant communication interrupts message receiving
    byte xy; //light brightness pre set setting
    byte brightness = 64; //brightness level (0-255), default = 64
    boolean boatmode;// if true, then boat mode
    byte modecount = 0; //no. of successful read sequences
    int  bootval;// voltage check at boot to detect whether it is a boat or not
    byte neutral = 85; //neutral position of servo
    byte servoangle; //servo's angle
    byte escangle;// mapped value to be sent as "servo" output to ESC
    int serwoPWM;// calculated value to steer servo by generating PWM
    unsigned long counter; //time from last message
    unsigned long nowtime; //time now. Used further to calculate time past since previous loop
    //unsigned long pinginterval; // for signalling range ping messages
    float voltageread; //voltage read at input
    float batvoltage; //calculated battery level (incl. calculated offset)
    byte mediumdischargecount = 0; //to avoid one - time battery voltage drops,alarm will be activated after few times threshold is reached
    byte deepdischargecount = 0; //to avoid one - time battery voltage drops,alarm will be activated after few times threshold is reached
    long mediumbatlevelalarmtime; //time of buzzer's activation
    boolean mediumbatlevelalarmactivation = false;
    boolean deepdischargealarmactivation = false;
    
    //int lowestbatvoltage; ////////////////////USED ONLY AT BOOT TO HAVE ANY VALUE FOR IF FUNCTION TO COMPARE TO
    //int lowestbatEEPROM;
    
    
    
    void setup()
    {
      //writeIntIntoEEPROM(7000);//EEPROM LOW RESET USED TO START A NEW RECORDING
      //PIN D11 BURNT !!!!!!!!!!!!
      //PINS A6&A7 cannot be used as analog output in Arduino Nano
      pinMode(4, OUTPUT); //AT MODE SWITCH
      pinMode(5, OUTPUT);
      pinMode(6, OUTPUT);
      pinMode(10, OUTPUT);//SERVO
      pinMode(13, OUTPUT); //built in led + WS2812B
      pinMode(A1, OUTPUT); //GND for voltage sensing
      pinMode(A0, INPUT); //voltage check at boot to detect whether it is a boat or not
      pinMode(A2, INPUT); //battery voltage check
      pinMode(A5, OUTPUT); //low battery buzzer output
      digitalWrite(A1, LOW); //GND for voltage sensing
      digitalWrite(A5, LOW); //deactivate buzzer
      digitalWrite(4, LOW); //ENTER AT MODE
      delay(50);//necessary to wait after AT mode change
    
      Serial.begin(9600);
      mySerial.begin(9600);//adjust after adjusting communication speed using AT+BXXX
      mySerial.println("AT+FU3");
      delay(50);
      mySerial.println("AT+B9600");
      delay(50);
      mySerial.println("AT+RX"); //AT MODE REQUIRED TO BE ON (4 LOW)
      delay(100);
      digitalWrite(4, HIGH); //EXIT AT MODE
      delay(50);//necessary to wait after mode change\
      analogReference(INTERNAL); //1,1V
      modecheck(); //Function to detect whether hardware is a boat or not
    
      analogReference(INTERNAL); //1,1V for battery measurement
    
      if (boatmode == true)
      {
        myservo.attach(SERVO_PIN_B); //Library works only at PIN9 and 10 - rudder 10
        esc.attach(SERVO_PIN_A); //Library works only at PIN9 and 10 - motor controller 9
        //ESCinit(); //ARM ESC (MOTOR CONTROLLER)///////////////////////////////////////
        servostart(); //Sequence for servo movement at boat's boot
        testbeep(); //Test buzzer
        //Serial.print("LOWEST VOLTAGE FROM EEPROM: ");
        //Serial.println(readIntFromEEPROM());
      }
      else
      {
        strip.begin(); // INITIALIZE NeoPixel strip object
        strip.clear();
        strip.show();
        startsequence(); //LED BLINK at car's boot
      }
    
    
    } ///////////////////////////////////////////END OF SETUP
    
    
    void loop()
    {
    
    //  esc.write(120);
    //  delay(250);
    //  esc.write(70);
    //  delay(250);
      
      ///////////////////////LOST CONNECTION PROTECTION
      nowtime = millis();
      if ((nowtime - counter) > 1000) //1000 MS SIGNAL LOST TRIGGER
      {
        //Serial.println(nowtime-counter);
        //Serial.println("CONNECTION LOST !!!");
        if (boatmode == false) //IF IN CAR MODE
        {
          digitalWrite(11, LOW);
          digitalWrite(10, LOW);
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
        else //IF IN BOAT MODE
        {
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
      }
      ///////////////////////END OF LOST CONNECTION PROTECTION
    
      //////////////////////////100 MS SIGNAL PING TRIGGER
      //    if ((nowtime - pinginterval) > 50)
      //    {
      //      //Serial.println("PING INTERVAL");
      //      //Serial.println(nowtime-pinginterval);//Loop time
      //      pinginterval = millis();
      //      ();
      //    }
      ///////////////////////END OF SIGNAL PING TRIGGER
    
    
      ////////////////////////////////////// MESSAGE RECEIVING
      while (mySerial.available())
      {
        static String receivedMessage = ""; // Store the received message
        char receivedChar = mySerial.read();
    
        if (receivedMessage.length() == 0)
        {
          if (receivedChar == 'A' || receivedChar == 'B' || receivedChar == 'C' || receivedChar == 'D')
          {
            receivedMessage = receivedChar; // Start building the message with the received character
          }
          if (receivedChar == 'F')
          {
            light = !light;
            change = true; // FLAG FOR LIGHT STATE CHANGE
            //Serial.println("LIGHT ON/OFF !");
          }
          if (receivedChar == 'E')
          {
            lightadjustment = true; // FLAG FOR LIGHT ADJUSTMENT
          }
        }//////////////END OF receivedMessage.length() == 0
    
        else
        {
          if (receivedChar == '!')
          {
            // Message received and ends with '!'
            Serial.println(receivedMessage);//////////////////////////////////////
            // Serial.println("MESSAGE RECEIVED, CONNECTION OK!");
            counter = millis();
            processMessage(receivedMessage, boatmode, neutral, deepdischargealarmactivation);
            receivedMessage = ""; // Clear the received message for the next one
          }
          else
          {
            receivedMessage += receivedChar;
          }
        }
      }//END OF WHILE
      /////////////////////////////////// END OF MESSAGE RECEIVING
    
      ////////////////////////////////// LIGHT ON&OFF
      if (light == true && change == true) //turn ON the light to the pre set level
      {
        change = false; //function activated only once
        lighton(); // turn ON the light function
      }
    
      if (light == false && change == true) //turn OFF the light
      {
        change = false; //function activated only once
        lightoff(); // turn the light OFF function
      }
      ////////////////////////////////// END OF LIGHT ON&OFF
    
    
      ////////////////////////////////// LIGHT LEVEL & ADJUST
      if (lightadjustment == true)
      {
        if (xy == 0)
        {
          Serial.println("MAX");
          strip.setBrightness(255);
          strip.show();
          xy = 1;
          lightadjustment = false;
        }
      }
    
      if (lightadjustment == true)
      {
        if (xy == 1)
        {
          Serial.println("DEFAULT");
          strip.setBrightness(64);
          strip.show();
          xy = 0;
          lightadjustment = false;
        }
      }
      ////////////////////////////////// END OF LIGHT LEVEL &ADJUST
    
    
      /////////////////////////////////// VOLTAGE READ AND BUZZER ACTIVATION
      if (boatmode == true)
      {
        voltageread = analogRead(A2);
        //Serial.println(voltageread);
        batvoltage = 10.88 * (long)voltageread * 1100 / 1024; //Convert voltageread to long to correctly handle multiplication (without int overflow). Voltage appplied through 1/10 divider. 0.88 after 10 for calibration
        //Serial.print("READ BATTERY VOLTAGE: ");
        //Serial.println(batvoltage);
      }
    
      //batvoltage=1.3;// BUZZER & LOW BATTERY PWM TEST
    
    
      if (batvoltage <= 6.6)
      {
        if (mediumbatlevelalarmactivation == false) //if medium battery level alarm has not been activated yet
        {
          mediumdischargecount = mediumdischargecount + 1;
          //Serial.print("MEDIUM BAT VOLTAGE COUNT:");
          //Serial.println(mediumdischargecount);
        }
      }
    
      if (batvoltage <= 5.8)
      {
        if (deepdischargealarmactivation == false) ////if battery deep discharge alarm has not been activated yet
        {
          deepdischargecount = deepdischargecount + 1;
          //Serial.print("DEEP BAT VOLTAGE COUNT:");
          //Serial.println(deepdischargecount);
        }
      }
    
      if (mediumdischargecount == 10) //medium battery level alarm activation
      {
        if (mediumbatlevelalarmactivation == false) //activate medium battery alarm only once
        {
          mediumbatlevelalarmtime = millis();
          Serial.println("MEDIUM BATTERY LEVEL ALARM !!!");
          digitalWrite(A5, HIGH); //activate buzzer
          mediumbatlevelalarmactivation = true; //medium battery alarm will not be activated again
        }
      }
    
      if (((millis() - mediumbatlevelalarmtime) > 10000 && (millis() - mediumbatlevelalarmtime) < 14000) ) //if alarm has been activated for more than 10 seconds but only once
      {
        digitalWrite(A5, LOW); //turn off the buzzer
      }
    
      if (deepdischargecount == 10) //low battery level alarm activation
      {
        digitalWrite(A5, HIGH); //activate buzzer
        if (deepdischargealarmactivation == false)
        {
          Serial.println("LOW BATTERY LEVEL ALARM !!!"); //send message only once
        }
        deepdischargealarmactivation = true;
        digitalWrite(A5, HIGH); //permanently activate the buzzer
      }
    
      /////////////////////////////////// END OF VOLTAGE READ AND BUZZER ACTIVATION
    
      //  /////////////////////////////////// VOLTAGE READ AND EEPROM READ&WRITE
      //  if (boatmode == true)
      //  {
      //    voltageread = analogRead(A2);
      //    Serial.print("ANALOG VOLTAGE: ");
      //    Serial.println(voltageread);
      //    batvoltage = 10.88 * (long)voltageread * 1100 / 1024; //Convert voltageread to long to correctly handle multiplication (without int overflow). Voltage appplied through 1/10 divider. 0.88 after 10 for calibration
      //    Serial.print("READ   VOLTAGE: ");
      //    Serial.println(batvoltage);
      //
      //    if (batvoltage > 3000) //to prevent from reading when battery is not connected (analog pin is grounded by 1k resistor)
      //    {
      //      if (batvoltage < lowestbatEEPROM) //if current voltage is lower than the lowest recorded in EEPROM
      //      {
      //        lowestbatvoltage = batvoltage;
      //        writeIntIntoEEPROM(lowestbatvoltage);
      //        Serial.print("!!!!!! NEW LOWEST VOLTAGE RECORDED: ");
      //        Serial.println(lowestbatvoltage);
      //      }
      //    }
      //
      //    Serial.print("LOWEST VOLTAGE: ");
      //    Serial.print(lowestbatvoltage);
      //    Serial.println(" (SINCE BOOT)");
      //    lowestbatEEPROM = readIntFromEEPROM(); //read lowest battery value stored in EEPROM
      //    Serial.print("LO BAT EEPROM : ");
      //    Serial.println(lowestbatEEPROM);
      //  }/////////////////////////////////// END OF VOLTAGE READ AND EEPROM READ&WRITE
    
    
    }////////////////////////////////////END OF LOOP
    
    
    
    ////////////////////////////////////FUNCTIONS///////////////////////////////////////////
    
    ///////////////////////////////////////////PROCESS MESSAGE
    void processMessage(String receivedMessage, boolean boatmode, byte bootval, boolean deepdischargealarmactivation)
    {
      //Serial.println(receivedMessage); //////////////////////////////// RECEIVED MESSAGE
    
      if (receivedMessage.charAt(0) == 'A')
      {
        af = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'B')
      {
        ab = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'C')
      {
        bf = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'D')
      {
        bb = receivedMessage.substring(1).toInt();
      }
    
    
      if (boatmode == false) //////////////////////PWM GENERATION IF IN CAR MODE
      {
        if (af > 3) //A FORWARD PWM&LOW
        {
          analogWrite(11, af);
          digitalWrite(10, LOW);
        }
    
        if (ab > 3) //A BACKWARD PWM&LOW
        {
          digitalWrite(11, LOW);
          analogWrite(10, ab);
        }
    
        if (bf > 3) //B FORWARD PWM&LOW
        {
          analogWrite(6, bf);
          digitalWrite(5, LOW);
        }
    
        if (bb > 3) //B BACKWARD ENGINE PWM&LOW
        {
          digitalWrite(6, LOW);
          analogWrite(5, bb);
        }
    
        if (bf <= 3 && bb <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT(DO NOT INTERPRETE "0" VALUE)
        {
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
    
        if (af <= 3 && ab <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT (DO NOT INTERPRETE "0" VALUE)
        {
          digitalWrite(10, LOW);
          digitalWrite(11, LOW);
        }
      } ////////////////////////END OF CAR MODE PWM GENERATION
    
      else//////////////////////PWM GENERATION IF IN BOAT MODE
      {
    
    
        ////////////////////////////////////////////////////////////IF ESC CONTROLLER USED
        if (af > 3) //A FORWARD ESC
        {
          if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
          {
            escangle = map(af, 3, 255, 90, 180);
            esc.write(escangle);
          }
          else //if deep battery discharege alarm is activated
          {
            escangle = map(af, 3, 255, 90, 120); //max speed reduced to 1/3
            esc.write(escangle);
          }
        }
    
        if (ab > 3) //A BACKWARD ESC
        {
          if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
          {
            escangle = map(ab, 3, 255, 90, 10); //cannot be "0", issue with ESC (too low PWM signal?)
            esc.write(escangle);
          }
          else //if deep battery discharege alarm is activated
          {
            escangle = map(ab, 3, 255, 90, 70); //max speed reduced to 1/3
            esc.write(escangle);
          }
        }
            ////////////////////////////////////////////////////////////IF ESC CONTROLLER USED
        
        ////////////////////////////////////////////////////////////IF PWM CONTROLLER USED
    //    if (af > 3) //A FORWARD PWM&LOW
    //    {
    //      if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
    //      {
    //        analogWrite(5, af);
    //        digitalWrite(6, LOW);
    //      }
    //      else //if deep battery discharege alarm is activated
    //      {
    //        analogWrite(5, (af / 3)); //speed reduced by 33%
    //        digitalWrite(6, LOW);
    //      }
    //    }
    //
    //    if (ab > 3) //A BACKWARD PWM&LOW
    //    {
    //      if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
    //      {
    //        digitalWrite(5, LOW);
    //        analogWrite(6, ab);
    //      }
    //      else //if deep battery discharege alarm is activated
    //      {
    //        digitalWrite(5, LOW);
    //        analogWrite(6, (ab / 3)); //speed reduced by 33%
    //      }
    //    }
            ////////////////////////////////////////////////////////////IF PWM CONTROLLER USED
    
        if (bf > 3) //B FORWARD PWM&LOW -->here SERVO
        {
          servoangle = map(bf, 3, 255, neutral, (neutral - 55));
          myservo.write(servoangle);
        }
    
        if (bb > 3) //B BACKWARD ENGINE PWM&LOW --> here SERVO
        {
          servoangle = map(bb, 3, 255, neutral, (neutral + 55));
          myservo.write(servoangle);
        }
    
    
        if (af <= 3 && ab <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT (DO NOT INTERPRETE "0" VALUE)
        {
          esc.write(90);//if ESC used
          //digitalWrite(5, LOW); //IF PWM CONTROLLER USED
          //digitalWrite(6, LOW); //IF PWM CONTROLLER USED
        }
    
        if (bf <= 3 && bb <= 3) //FOR NEUTRAL POSITIONAS PROGRAM DO NOT ZERO BY DEFAULT(DO NOT INTERPRETE "0" VALUE)
        {
          myservo.write(neutral);
        }
      } ////////////////////////END OF BOAT MODE PWM GENERATION
    
      //    FOR DEBUG ONLY. USING INTERRUPTS RECEIVED SIGNAL & OPERATION
      //    Serial.print("AF: ");
      //    Serial.println(af);
      //    Serial.print("AB: ");
      //    Serial.println(ab);
      //    Serial.print("BF: ");
      //    Serial.println(bf);
      //    Serial.print("BB: ");
      //    Serial.println(bb);
      //    FOR DEBUG ONLY. USING INTERRUPTS RECEIVED SIGNAL & OPERATION
    } /////////////////////////////////////////////////Process Message End
    
    void lighton()
    {
      strip.setBrightness(brightness);
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
    }
    
    void lightoff()
    {
      strip.setBrightness(0);
      strip.show();
    }
    
    void startsequence() //LED BLINK AT START
    {
      digitalWrite(13, HIGH); //BUILT IN LED ON
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
      delay(50);
      digitalWrite(13, LOW); //BUILT IN LED OFF
      strip.setBrightness(0);
      strip.show();
      delay(50);
      digitalWrite(13, HIGH); //BUILT IN LED ON
      strip.setBrightness(255);
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
      delay(50);
      digitalWrite(13, LOW); //BUILT IN LED OFF
      strip.setBrightness(0);
      strip.show();
    }
    
    void servostart() //SEQUENCE OF SERVO MOVEMENTS AT START
    {
      myservo.write(neutral + 55);                // sets the servo position according to the scaled value
      delay(200);
      myservo.write(neutral - 55);                // sets the servo position according to the scaled value
      delay(200);
      myservo.write(neutral); // sets the servo position according to the scaled value
      delay(100);
    }
    
    void testbeep()
    {
      digitalWrite(A5, HIGH);
      delay(50);
      digitalWrite(A5, LOW);
      delay(50);
      digitalWrite(A5, HIGH);
      delay(50);
      digitalWrite(A5, LOW);
      delay(50);
      digitalWrite(A5, HIGH);
      delay(50);
      digitalWrite(A5, LOW);
    }
    
    void shortbeep()
    {
      digitalWrite(A5, HIGH);
      delay(25);
      digitalWrite(A5, LOW);
    }
    
    boolean modecheck() //voltage check at boot to detect whether it is a boat or not
    {
      for (byte i = 0; i < 5; i++)
      {
        bootval = analogRead(A0);
        if (bootval > 600 && bootval < 700) //A0 value at USB approx. 659. 655, 665, at boat different
        {
          modecount = modecount + 1;
        }
        delay(100);
      }
    
      if (modecount == 5)
      {
        boatmode = true;
        Serial.println("BOAT MODE !");
        return boatmode;
      }
      else
      {
        Serial.println("CAR MODE !");
      }
    }// END OF MODE CHECK
    
    void ESCinit()
    {
      byte pos = 0;
      esc.write(0);
    
      for (pos = 0; pos < 181; pos += 1)
      {
        esc.write(pos);
        delay(10);
        //Serial.println(pos);
      }
      shortbeep();
      delay(200);
    
      for (pos = 180; pos < 181; pos -= 1)
      {
        esc.write(pos);
        delay(10);
        //Serial.println(pos);
      }
      shortbeep();
      delay(200);
      for (pos = 0; pos < 91; pos += 1)
      {
        esc.write(pos);
        delay(10);
        //Serial.println(pos);
      }
      shortbeep();
      delay(200);
    }
    
    //void writeIntIntoEEPROM(int lowestbatvoltage)
    //{
    //  EEPROM.update(0, lowestbatvoltage >> 8); //address, variable. Shift by 8n bite, meaning saving only firts 8 bits from the digit in the first (out of two) bytes
    //  EEPROM.update(0 + 1, lowestbatvoltage & 0xFF); //For the second byte, we make an AND operation with 0xFF, which is the hexadecimal representation of 255 (you could write “& 255” instead of “& 0xFF”). This way, we only get the 8 bits on the right.
    //}
    //
    //int readIntFromEEPROM()
    //{
    //  return lowestbatEEPROM = (EEPROM.read(0) << 8) + EEPROM.read(0 + 1);
    //}
    
    //void sendping()
    //{
    //  mySerial.print("XXXXX");
    //  Serial.println("!"); //////////////////////////////// PING SENT
    //}
    
  • #16 21046953
    Slawek K.
    Niveau 35  
    Es ist schwer, von Optimierung zu sprechen, bis du viele Verzögerungen aus dem Code, insbesondere dem Empfänger, eliminiert hast. Mach diese Übung und sende jedes Mal einen inkrementierten Zähler der gesendeten Frames auf der Senderseite und erhöhe den Zähler der empfangenen Frames auf der Empfängerseite. Vergleiche dann beide Zähler auf der Empfängerseite und du wirst sehen, wie groß der Unterschied ist :)

    Grüße
  • #17 21048100
    Frog_Qmak
    Niveau 25  
    Vielen Dank für dein Kommentar. Der Code könnte zwar noch weiter optimiert werden, es wären jedoch erhebliche Änderungen erforderlich. Bisher funktioniert es einwandfrei, die Reichweite ist mehr als ausreichend, es besteht also kein Grund, es hervorzukramen. Eine Einfügung mit ESC-Unterstützung kann für jemanden nützlich sein. Ich habe viel darüber gelesen, wie man damit umgeht. Auf diese Weise gewinnt das Projekt an Universalität.
  • #18 21120072
    Frog_Qmak
    Niveau 25  
    Hallo,

    ich füge eine weitere Revision des Empfängercodes hinzu. Zusätzlich zu kleineren Verbesserungen gibt es zwei wesentliche Änderungen.

    1. Da das Boot SEHR manövrierfähig ist, d. h. bei hoher Geschwindigkeit und Ruderausschlag fast stehen bleibt und sich an Ort und Stelle dreht, habe ich einen Ruderausschlagbegrenzer hinzugefügt, d. h. bei einem bestimmten Joystickausschlag wird die entsprechende Servobewegung abgeschwächt, während zur Aufrechterhaltung der hohen Manövrierfähigkeit in der nahen Endposition das Servo wieder heftig reagiert.

    (2) Da der Propeller, der sich mit enormer Geschwindigkeit dreht, das Boot um seine Achse schwenkt und somit verdreht, habe ich einen "Offset" mit der Möglichkeit der Kalibrierung hinzugefügt. Das funktioniert, indem man den Joystick auf der Fernsteuerung in die Richtung schwenkt, in die das Ruder schwingen soll, und dann einen Knopf auf dem anderen Joystick gedrückt hält (wie beim Wechseln der Lichter an einem Auto). Dadurch wird der "Offset" um 1 (Servoposition, nicht Winkel) in diese Richtung geändert und der neue Wert im EEPROM gespeichert, so dass die Kalibrierung nicht wiederholt werden muss. Das Ruder schwingt nur dann (der Offset ist eingeschaltet), wenn der Motor "vorwärts" läuft, denn dann tritt das beschriebene Phänomen auf (die Bewegung nach hinten ist nicht so wichtig). In der Praxis funktioniert das gut, wenn auch nicht perfekt, denn wenn die Batterien schwächer werden, sinkt auch die Motordrehzahl, so dass der "ursprüngliche" Versatz zu stark wird und das Boot wieder leicht zu drehen beginnt. Nichtsdestotrotz ist es kein Problem, neu zu kalibrieren, und eine Sturzkurve als Funktion der Batteriespannung zu erstellen, ist den enormen Zeitaufwand nicht wert, der nötig wäre, um eine entsprechende Funktion in den Code einzufügen und zu kalibrieren :D .

    PS. Es hat sich allerdings herausgestellt, dass es bei größeren Entfernungen Probleme bei der Übertragung gibt (kurze Unterbrechungen des Motors - wahrscheinlich falsch gelesene Werte durch "verlorene" Nachrichtenabschlusszeichen, oder andere Probleme). Ich werde vielleicht noch einmal zurückkehren, um diese Probleme zu beheben. Es handelt sich nicht um ein lebensrettendes Gerät, und zum Herumspielen, bis es ausreicht, ist die Zufriedenheit da.

    
    #include <SoftwareSerial.h>
    #include <Adafruit_NeoPixel.h>
    #include <EEPROM.h>
    #include <PWMServo.h>//software PWM used because servo library had conflict with other used functions using PWM generated by the same internal clock
    PWMServo myservo;  // create servo object to control a servo
    PWMServo esc;  // create servo object to control an ESC (motor controller)
    SoftwareSerial mySerial(2, 3); //RX, TX
    Adafruit_NeoPixel
    strip = Adafruit_NeoPixel(3, 13, NEO_GRB + NEO_KHZ800); //NO of pixels, PIN
    byte af, ab, bf, bb;
    boolean light = 0; //LIGHT ON/OFF, default = OFF
    boolean change = false; // flag to mark change to use WS2812B communication once for light ON/OFF. Constant communication interrupts message receiving
    boolean lightadjustment = false; // flag to mark change to use WS2812B communication once for light level adjustment. Constant communication interrupts message receiving
    byte xy; //light brightness pre set setting
    byte brightness = 64; //brightness level (0-255), default = 64
    boolean boatmode;// if true, then boat mode
    byte modecount = 0; //no. of successful read sequences
    int  bootval;// voltage check at boot to detect whether it is a boat or not
    byte neutral = 86; //neutral position of servo
    byte neutralmove;// neutral position of servo during boat's forward movement
    byte servoangle; //servo's angle
    byte escangle;// mapped value to be sent as "servo" output to ESC
    int serwoPWM;// calculated value to steer servo by generating PWM
    unsigned long counter; //time from last message
    unsigned long nowtime; //time now. Used further to calculate time past since previous loop
    //unsigned long pinginterval; // for signalling range ping messages
    float voltageread; //voltage read at input
    float batvoltage; //calculated battery level (incl. calculated offset)
    byte mediumdischargecount = 0; //to avoid one - time battery voltage drops,alarm will be activated after few times threshold is reached
    byte deepdischargecount = 0; //to avoid one - time battery voltage drops,alarm will be activated after few times threshold is reached
    long mediumbatlevelalarmtime; //time of buzzer's activation
    boolean mediumbatlevelalarmactivation = false;
    boolean deepdischargealarmactivation = false;
    byte maxleftangle = 55;//MAX LEFT RUDDER DEFLECTION OF BOAT (IN RANGE OF 0-255, NOT DEGREE)
    byte maxrightangle = 45;//MAX RIGHT RUDDER DEFLECTION OF BOAT (IN RANGE OF 0-255, NOT DEGREE)
    byte newoffsetvalue; // new offset value to be saved in EEPROM
    boolean updateeepromflag = false; //if true, then offset value in EEPROM must be updated
    
    //int lowestbatvoltage; ////////////////////USED ONLY AT BOOT TO HAVE ANY VALUE FOR IF FUNCTION TO COMPARE TO
    //int lowestbatEEPROM;
    
    
    void setup()
    {
      //writeIntIntoEEPROM(17000);//EEPROM LOW RESET USED TO START A NEW RECORDING
      //PINS A6&A7 cannot be used as analog output in Arduino Nano
      pinMode(4, OUTPUT); //AT MODE SWITCH
      pinMode(5, OUTPUT);
      pinMode(6, OUTPUT);
      pinMode(10, OUTPUT);//SERVO
      pinMode(13, OUTPUT); //built in led + WS2812B
      pinMode(A1, OUTPUT); //GND for voltage sensing
      pinMode(A0, INPUT); //voltage check at boot to detect whether it is a boat or not
      pinMode(A2, INPUT); //battery voltage check
      pinMode(A5, OUTPUT); //low battery buzzer output
      digitalWrite(A1, LOW); //GND for voltage sensing
      digitalWrite(A5, LOW); //deactivate buzzer
      digitalWrite(4, LOW); //ENTER AT MODE
      delay(50);//necessary to wait after AT mode change
    
      Serial.begin(9600);
      mySerial.begin(9600);//adjust after adjusting communication speed using AT+BXXX
      mySerial.println("AT+FU3");
      delay(50);
      mySerial.println("AT+B9600");
      delay(50);
      mySerial.println("AT+RX"); //AT MODE REQUIRED TO BE ON (4 LOW)
      delay(100);
      digitalWrite(4, HIGH); //EXIT AT MODE
      delay(50);//necessary to wait after mode change\
      analogReference(INTERNAL); //1,1V
      modecheck(); //Function to detect whether hardware is a boat or not
    
      analogReference(INTERNAL); //1,1V internal refercence voltage for battery measurement
    
      if (boatmode == true)
      {
        myservo.attach(SERVO_PIN_B); //Library works only at PIN9 and 10 - rudder 10
        esc.attach(SERVO_PIN_A); //Library works only at PIN9 and 10 - motor controller 9
        //ESCinit(); //ARM ESC (MOTOR CONTROLLER). NOT USED WITH THIS ESC; OWN SEQUENCE USED
        servostart(); //Sequence for servo movement at boat's boot
        testbeep(); //Test buzzer
        //Serial.print("LOWEST VOLTAGE FROM EEPROM: ");
        //Serial.println(readIntFromEEPROM());
        //Serial.print("OFFSET READ FROM EEPROM: ");
        //Serial.println(readoffsetfromeeprom());// read rudder's offset value during forward movement to compensate for propeller's movement
        neutralmove = readoffsetfromeeprom(); //set new offset value as neutral while moving forward
        //Serial.print("NEUTRAL MOVEMENT OFFSET: ");
        //Serial.println(neutralmove);
      }
      else
      {
        strip.begin(); // INITIALIZE NeoPixel strip object
        strip.clear();
        strip.show();
        startsequence(); //LED BLINK at car's boot
      }
    
    } ///////////////////////////////////////////END OF SETUP
    
    
    void loop()
    {
    
      ///////////////////////LOST CONNECTION PROTECTION
      nowtime = millis();
      if ((nowtime - counter) > 1000) //1000 MS SIGNAL LOST TRIGGER
      {
        //Serial.println(nowtime-counter);
        //Serial.println("CONNECTION LOST !!!");
        if (boatmode == false) //IF IN CAR MODE
        {
          digitalWrite(11, LOW);
          digitalWrite(10, LOW);
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
        else //IF IN BOAT MODE
        {
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
      }
      ///////////////////////END OF LOST CONNECTION PROTECTION
    
      //////////////////////////100 MS SIGNAL PING TRIGGER
      //    if ((nowtime - pinginterval) > 50)
      //    {
      //      //Serial.println("PING INTERVAL");
      //      //Serial.println(nowtime-pinginterval);//Loop time
      //      pinginterval = millis();
      //      ();
      //    }
      ///////////////////////END OF SIGNAL PING TRIGGER
    
    
      ////////////////////////////////////// MESSAGE RECEIVING
      while (mySerial.available())
      {
        static String receivedMessage = ""; // Store the received message
        char receivedChar = mySerial.read();
    
        if (receivedMessage.length() == 0)
        {
          if (receivedChar == 'A' || receivedChar == 'B' || receivedChar == 'C' || receivedChar == 'D')
          {
            receivedMessage = receivedChar; // Start building the message with the received character
          }
          if (receivedChar == 'F')
          {
            light = !light;
            change = true; // FLAG FOR LIGHT STATE CHANGE
            //Serial.println("LIGHT ON/OFF !");
          }
          if (receivedChar == 'E')
          {
            lightadjustment = true; // FLAG FOR LIGHT ADJUSTMENT
            updateeepromflag = true; //Flag to mark that offset value in EEPROM must be updated
          }
        }//////////////END OF receivedMessage.length() == 0
    
        else
        {
          if (receivedChar == '!')
          {
            // Message received and ends with '!'
            //Serial.println(receivedMessage);
            // Serial.println("MESSAGE RECEIVED, CONNECTION OK!");
            counter = millis();
            processMessage(receivedMessage, boatmode, neutral, deepdischargealarmactivation);
            receivedMessage = ""; // Clear the received message for the next one
          }
          else
          {
            receivedMessage += receivedChar;
          }
        }
      }//END OF WHILE
      /////////////////////////////////// END OF MESSAGE RECEIVING
    
      ////////////////////////////////// LIGHT ON&OFF
      if (light == true && change == true) //turn ON the light to the pre set level
      {
        change = false; //function activated only once
        lighton(); // turn ON the light function
      }
    
      if (light == false && change == true) //turn OFF the light
      {
        change = false; //function activated only once
        lightoff(); // turn the light OFF function
      }
      ////////////////////////////////// END OF LIGHT ON&OFF
    
    
      ////////////////////////////////// LIGHT LEVEL & ADJUST
      if (lightadjustment == true)
      {
        if (xy == 0)
        {
          //Serial.println("MAX");
          strip.setBrightness(255);
          strip.show();
          xy = 1;
          lightadjustment = false;
        }
      }
    
      if (lightadjustment == true)
      {
        if (xy == 1)
        {
          //Serial.println("DEFAULT");
          strip.setBrightness(64);
          strip.show();
          xy = 0;
          lightadjustment = false;
        }
      }
      ////////////////////////////////// END OF LIGHT LEVEL &ADJUST
    
      ///////////////////////////////////SAVE NEW RUDDER'S OFFSET IN EEPROM
      if (updateeepromflag == true)
      {
    
        if (bf > 3)
        {
          newoffsetvalue = neutralmove - 1;
          updateoffsettoeeprom (newoffsetvalue); //save to EEPROM
        }
        if (bb > 3)
        {
          newoffsetvalue = neutralmove + 1;
          updateoffsettoeeprom (newoffsetvalue); //save to EEPROM
        }
        //Serial.print("OLD MOVE NEUTRAL OFFSET: ");
        //Serial.println(neutralmove);
        neutralmove = newoffsetvalue; // update also current setting
        updateeepromflag = false; //execute only once
        //Serial.print("NEW MOVE NEUTRAL OFFSET: ");
        //Serial.println(neutralmove);
    
      }
      ////////////////////////////////// END OF SAVE NEW RUDDER'S OFFSET IN EEPROM
    
    
      /////////////////////////////////// VOLTAGE READ AND BUZZER ACTIVATION
      if (boatmode == true)
      {
        voltageread = analogRead(A2);
        //Serial.print("BAT VOLTAGE READ: ");
        //Serial.println(voltageread);
        batvoltage = 10.88 * (long)voltageread * 1100 / 1024; //Convert voltageread to long to correctly handle multiplication (without int overflow). Voltage appplied through 1/10 divider. 1,1 is internal reference voltage. 10* because of reststor divider, .88 for calibration
        //Serial.print("CALCULATED VOLTAGE: ");
        //Serial.println(batvoltage);
      }
    
      //batvoltage=1.3;// BUZZER & LOW BATTERY PWM TEST
    
    
      if (batvoltage <= 6.8)
      {
        if (mediumbatlevelalarmactivation == false) //if medium battery level alarm has not been activated yet
        {
          mediumdischargecount = mediumdischargecount + 1;
          //Serial.print("MEDIUM BAT VOLTAGE COUNT:");
          //Serial.println(mediumdischargecount);
        }
      }
    
      if (batvoltage <= 6.0)
      {
        if (deepdischargealarmactivation == false) ////if battery deep discharge alarm has not been activated yet
        {
          deepdischargecount = deepdischargecount + 1;
          //Serial.print("DEEP BAT VOLTAGE COUNT:");
          //Serial.println(deepdischargecount);
        }
      }
    
      if (mediumdischargecount == 10) //medium battery level alarm activation
      {
        if (mediumbatlevelalarmactivation == false) //activate medium battery alarm only once
        {
          mediumbatlevelalarmtime = millis();
          Serial.println("MEDIUM BATTERY LEVEL ALARM !!!");
          digitalWrite(A5, HIGH); //activate buzzer
          mediumbatlevelalarmactivation = true; //medium battery alarm will not be activated again
        }
      }
    
      if (((millis() - mediumbatlevelalarmtime) > 10000 && (millis() - mediumbatlevelalarmtime) < 14000) ) //if alarm has been activated for more than 10 seconds but only once
      {
        digitalWrite(A5, LOW); //turn off the buzzer
      }
    
      if (deepdischargecount == 10) //low battery level alarm activation
      {
        digitalWrite(A5, HIGH); //activate buzzer
        if (deepdischargealarmactivation == false)
        {
          Serial.println("LOW BATTERY LEVEL ALARM !!!"); //send message only once
        }
        deepdischargealarmactivation = true;
        digitalWrite(A5, HIGH); //permanently activate the buzzer
      }
    
      /////////////////////////////////// END OF VOLTAGE READ AND BUZZER ACTIVATION
    
      //  /////////////////////////////////// VOLTAGE READ AND EEPROM READ&WRITE
      //    if (boatmode == true)
      //    {
      //      voltageread = analogRead(A2);
      //      Serial.print("ANALOG VOLTAGE: ");
      //      Serial.println(voltageread);
      //      batvoltage = 10.88 * (long)voltageread * 1100 / 1024; //Convert voltageread to long to correctly handle multiplication (without int overflow). Voltage appplied through 1/10 divider. 0.88 after 10 for calibration
      //      Serial.print("READ   VOLTAGE: ");
      //      Serial.println(batvoltage);
      //
      //      if (batvoltage > 3000) //to prevent from reading when battery is not connected (analog pin is grounded by 1k resistor)
      //      {
      //        if (batvoltage < lowestbatEEPROM) //if current voltage is lower than the lowest recorded in EEPROM
      //        {
      //          lowestbatvoltage = batvoltage;
      //          writeIntIntoEEPROM(lowestbatvoltage);
      //          Serial.print("!!!!!! NEW LOWEST VOLTAGE RECORDED: ");
      //          Serial.println(lowestbatvoltage);
      //        }
      //      }
      //
      //      Serial.print("LOWEST VOLTAGE: ");
      //      Serial.print(lowestbatvoltage);
      //      Serial.println(" (SINCE BOOT)");
      //      lowestbatEEPROM = readIntFromEEPROM(); //read lowest battery value stored in EEPROM
      //      Serial.print("LO BAT EEPROM : ");
      //      Serial.println(lowestbatEEPROM);
      //    }/////////////////////////////////// END OF VOLTAGE READ AND EEPROM READ&WRITE
    
    
    }////////////////////////////////////END OF LOOP
    
    
    
    //////////////////////////////////////////FUNCTIONS/////////////////////////////////////////////////
    
    ///////////////////////////////////////////PROCESS MESSAGE
    void processMessage(String receivedMessage, boolean boatmode, byte bootval, boolean deepdischargealarmactivation)
    {
      //Serial.println(receivedMessage); //////////////////////////////// RECEIVED MESSAGE
      if (receivedMessage.charAt(0) == 'A')
      {
        af = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'B')
      {
        ab = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'C')
      {
        bf = receivedMessage.substring(1).toInt();
      }
    
      if (receivedMessage.charAt(0) == 'D')
      {
        bb = receivedMessage.substring(1).toInt();
      }
    
    
      if (boatmode == false) //////////////////////PWM GENERATION IF IN CAR MODE
      {
        if (af > 3) //A FORWARD PWM&LOW
        {
          analogWrite(11, af);
          digitalWrite(10, LOW);
        }
    
        if (ab > 3) //A BACKWARD PWM&LOW
        {
          digitalWrite(11, LOW);
          analogWrite(10, ab);
        }
    
        if (bf > 3) //B FORWARD PWM&LOW
        {
          analogWrite(6, bf);
          digitalWrite(5, LOW);
        }
    
        if (bb > 3) //B BACKWARD ENGINE PWM&LOW
        {
          digitalWrite(6, LOW);
          analogWrite(5, bb);
        }
    
        if (bf <= 3 && bb <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT(DO NOT INTERPRETE "0" VALUE)
        {
          digitalWrite(6, LOW);
          digitalWrite(5, LOW);
        }
    
        if (af <= 3 && ab <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT (DO NOT INTERPRETE "0" VALUE)
        {
          digitalWrite(10, LOW);
          digitalWrite(11, LOW);
        }
      } ////////////////////////END OF CAR MODE PWM GENERATION
    
      else//////////////////////PWM GENERATION IF IN BOAT MODE
      {
        ////////////////////////////////////////////////////////////IF ESC CONTROLLER USED
        if (af > 3) //A FORWARD ESC
        {
          if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
          {
            escangle = map(af, 3, 255, 90, 180);
            esc.write(escangle);
            myservo.write(neutralmove); //set rudder to offset during forward movement
            //Serial.println("OFFSET MOVE ACTIVATED!!");
          }
          else //if deep battery discharege alarm is activated
          {
            escangle = map(af, 3, 255, 90, 120); //max speed reduced to 1/3
            esc.write(escangle);
            myservo.write(neutralmove); //set rudder to offset during forward movement
            //Serial.println("OFFSET MOVE ACTIVATED!!");
          }
        }
    
        if (ab > 3) //A BACKWARD ESC
        {
          if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
          {
            escangle = map(ab, 3, 255, 90, 10); //cannot be "0", issue with ESC (too low PWM signal?)
            esc.write(escangle);
          }
          else //if deep battery discharege alarm is activated
          {
            escangle = map(ab, 3, 255, 90, 70); //max speed reduced to 1/3
            esc.write(escangle);
          }
        }
        ////////////////////////////////////////////////////////////END OF IF ESC CONTROLLER USED
    
        ////////////////////////////////////////////////////////////IF PWM H-BRIDGE CONTROLLER USED
        //    if (af > 3) //A FORWARD PWM&LOW
        //    {
        //      if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
        //      {
        //        analogWrite(5, af);
        //        digitalWrite(6, LOW);
        //        myservo.write(neutralmove); //set rudder to offset during forward movement
        //      }
        //      else //if deep battery discharege alarm is activated
        //      {
        //        analogWrite(5, (af / 3)); //speed reduced by 33%
        //        digitalWrite(6, LOW);
        //        myservo.write(neutralmove); //set rudder to offset during forward movement
        //      }
        //    }
        //
        //    if (ab > 3) //A BACKWARD PWM&LOW
        //    {
        //      if (deepdischargealarmactivation == false) //if deep battery discharege alarm is not activated
        //      {
        //        digitalWrite(5, LOW);
        //        analogWrite(6, ab);
        //      }
        //      else //if deep battery discharege alarm is activated
        //      {
        //        digitalWrite(5, LOW);
        //        analogWrite(6, (ab / 3)); //speed reduced by 33%
        //      }
        //    }
        ////////////////////////////////////////////////////////////END OF IF PWM H-BRIDGE CONTROLLER USED
    
        if (bf > 3) //B FORWARD PWM&LOW -->here SERVO RIGHT
        {
          if (bf < 240) // MORE DELICATE RUDDER MOVEMENT FOR SMALLER JOYSTICK'S ANGLE
          {
            servoangle = map(bf, 3, 255, neutral, (neutral - 35));
            myservo.write(servoangle);
          }
    
          else      //LARGER JOYSTICK'S ANGLE - NORMAL RESPONSE
          {
            servoangle = map(bf, 3, 255, neutral, (neutral - maxrightangle));
            myservo.write(servoangle);
          }
        }
    
        if (bb > 3) //B BACKWARD ENGINE PWM&LOW --> here SERVO LEFT
        {
          if (bb < 240) // MORE DELICATE RUDDER MOVEMENT FOR SMALLER JOYSTICK'S ANGLE
          {
            servoangle = map(bb, 3, 255, neutral, (neutral + 35));
            myservo.write(servoangle);
          }
          else    //LARGER JOYSTICK'S ANGLE - NORMAL RESPONSE
          {
            servoangle = map(bb, 3, 255, neutral, (neutral + maxleftangle));
            myservo.write(servoangle);
          }
        }
        //    {
        //      servoangle = map(bf, 3, 255, neutral, (neutral - maxrightangle));
        //      myservo.write(servoangle);
        //    }
        //
        //    if (bb > 3) //B BACKWARD ENGINE PWM&LOW --> here SERVO
        //    {
        //      servoangle = map(bb, 3, 255, neutral, (neutral + maxleftangle));
        //      myservo.write(servoangle);
        //    }
    
        if (af <= 3 && ab <= 3) //FOR ZEROING AS PROGRAM DO NOT ZERO BY DEFAULT (DO NOT INTERPRETE "0" VALUE)
        {
          esc.write(90);//if ESC used
          //digitalWrite(5, LOW); //IF PWM H-BRIDGE CONTROLLER USED
          //digitalWrite(6, LOW); //IF PWM H-BRIDGE CONTROLLER USED
        }
    
        if (bf <= 3 && bb <= 3 ) //FOR NEUTRAL POSITION  AS PROGRAM DO NOT ZERO BY DEFAULT(DO NOT INTERPRETE "0" VALUE)
        {
          if (af <= 3) //WITHOUT OVERWRITING OFFSET IF IN MOVE
          {
            myservo.write(neutral);
          }
        }
      } ////////////////////////END OF BOAT MODE PWM GENERATION
    
      //    FOR DEBUG ONLY. USING INTERRUPTS RECEIVED SIGNAL & OPERATION
      //    Serial.print("AF: ");
      //    Serial.println(af);
      //    Serial.print("AB: ");
      //    Serial.println(ab);
      //    Serial.print("BF: ");
      //    Serial.println(bf);
      //    Serial.print("BB: ");
      //    Serial.println(bb);
      //    FOR DEBUG ONLY. USING INTERRUPTS RECEIVED SIGNAL & OPERATION
    } ///////////////////////////////////////////////////////////////////////////////////////////////Process Message End
    
    void lighton() ////////////////////////////LED ON IN CAR MODE
    {
      strip.setBrightness(brightness);
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
    }
    
    void lightoff() //////////////////////////// LED OFF IN CAR MODE
    {
      strip.setBrightness(0);
      strip.show();
    }
    
    void startsequence() ////////////////////////////LED BLINK AT START IN CAR MODE
    {
      digitalWrite(13, HIGH); //BUILT IN LED ON
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
      delay(50);
      digitalWrite(13, LOW); //BUILT IN LED OFF
      strip.setBrightness(0);
      strip.show();
      delay(50);
      digitalWrite(13, HIGH); //BUILT IN LED ON
      strip.setBrightness(255);
      strip.setPixelColor(0, strip.Color(255, 255, 255));
      strip.setPixelColor(1, strip.Color(255, 255, 255));
      strip.setPixelColor(2, strip.Color(255, 0, 0));
      strip.show();
      delay(50);
      digitalWrite(13, LOW); //BUILT IN LED OFF
      strip.setBrightness(0);
      strip.show();
    } ////////////////////////////END OF LED BLINK AT START IN CAR MODE
    
    void servostart() ////////////////////////////SEQUENCE OF SERVO MOVEMENTS AT START
    {
      myservo.write(neutral + maxleftangle);                // sets the servo position according to the scaled value - left
      delay(200);
      myservo.write(neutral - maxrightangle);                // sets the servo position according to the scaled value - right
      delay(200);
      myservo.write(neutral); // sets the servo position according to the scaled value
      delay(100);
    }
    
    void testbeep()
    {
      digitalWrite(A5, HIGH);
      delay(50);
      digitalWrite(A5, LOW);
      delay(50);
      digitalWrite(A5, HIGH);
      delay(50);
      digitalWrite(A5, LOW);
      delay(50);
      digitalWrite(A5, HIGH);
      delay(50);
      digitalWrite(A5, LOW);
    }
    
    void shortbeep()
    {
      digitalWrite(A5, HIGH);
      delay(25);
      digitalWrite(A5, LOW);
    }
    
    boolean modecheck() ////////////////////////////voltage check at boot to detect whether it is a boat or not
    {
      for (byte i = 0; i < 5; i++)
      {
        bootval = analogRead(A0);
        //Serial.println(bootval);//for calibration
        if (bootval > 600 && bootval < 810) //A0 value at USB approx. 770, at boat different -- FORUSB to be calibrated for each Arduino independently using Serial.println(bootval), for battery to be calculated manually or readand store in EEPROM;
        {
          modecount = modecount + 1;
        }
        delay(100);
      }
    
      if (modecount == 5)
      {
        boatmode = true;
        Serial.println("BOAT MODE !");
        return boatmode;
      }
      else
      {
        Serial.println("CAR MODE !");
      }
    }/////////////////////////////////////// END OF MODE CHECK
    
    void ESCinit()//////////////////////////ESC INITIATION (ARM) SEQUENCE
    {
      byte pos = 0;
      esc.write(0);
    
      for (pos = 0; pos < 181; pos += 1)
      {
        esc.write(pos);
        delay(10);
        //Serial.println(pos);
      }
      shortbeep();
      delay(200);
    
      for (pos = 180; pos < 181; pos -= 1)
      {
        esc.write(pos);
        delay(10);
        //Serial.println(pos);
      }
      shortbeep();
      delay(200);
      for (pos = 0; pos < 91; pos += 1)
      {
        esc.write(pos);
        delay(10);
        //Serial.println(pos);
      }
      shortbeep();
      delay(200);
    }
    
    void updateoffsettoeeprom (byte newoffsetvalue)
    {
      EEPROM.update(3, newoffsetvalue); //address, variable
    }
    
    byte readoffsetfromeeprom()
    {
      return neutralmove = EEPROM.read(3);
    }
    
    //void writeIntIntoEEPROM(int lowestbatvoltage)
    //{
    //  EEPROM.update(0, lowestbatvoltage >> 8); //address, variable. Shift by 8n bite, meaning saving only firt 8 bits from the digit will be in the first (out of two) bytes
    //  EEPROM.update(0 + 1, lowestbatvoltage & 0xFF); //For the second byte, we make an AND operation with 0xFF, which is the hexadecimal representation of 255 (you could write “& 255” instead of “& 0xFF”). This way, we only get the 8 bits on the right.
    //}
    
    //int readIntFromEEPROM()
    //{
    //  return lowestbatEEPROM = (EEPROM.read(0) << 8) + EEPROM.read(0 + 1);
    //}
    
    //void sendping()
    //{
    //  mySerial.print("XXXXX");
    //  Serial.println("!"); //////////////////////////////// PING SENT
    //}
    

    [F]
📢 Słuchaj:

Themenzusammenfassung

In der Diskussion wird eine universelle Plattform für den Betrieb von RC-Modellen vorgestellt, die auf Arduino basiert. Der Autor beschreibt seine Erfahrungen mit verschiedenen ferngesteuerten Fahrzeugen, darunter ein Panzerfahrgestell und ein 4x4-Auto, das als "beschädigt" gekauft wurde. Es wird über die Reichweite der Fernbedienung diskutiert, wobei eine Reichweite von bis zu 200 m erreicht wurde. Die Verwendung von LoRa- und nRF24L01-Modulen wird in Betracht gezogen, um die Reichweite und Zuverlässigkeit zu verbessern. Der Autor hat auch die Software für Sender und Empfänger aktualisiert, um die Steuerung von Modellmotoren (ESC) zu unterstützen und die Manövrierfähigkeit des Bootes zu optimieren. Es werden technische Herausforderungen wie Signalverzögerungen und die Notwendigkeit einer effizienten Datenübertragung angesprochen.
Vom Sprachmodell generierte Zusammenfassung.
WERBUNG