logo elektroda
logo elektroda
X
logo elektroda

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

Frog_Qmak 
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
//}

Über den Autor
Frog_Qmak
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.

Kommentare

Kommentar hinzufügen
gulson 30 Nov 2023 17:42

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! [Mehr erfahren]

Karol966 30 Nov 2023 18:54

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... [Mehr erfahren]

Frog_Qmak 30 Nov 2023 19:03

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... [Mehr erfahren]

Jawi_P 01 Dez 2023 10:35

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. [Mehr erfahren]

ArturAVS 01 Dez 2023 11:42

@frogqmak, hast du über den Einsatz von LoRa-Modulen nachgedacht? Oder z. B. nRF24L01? Ich hatte ein paar Sachen angesammelt und wollte etwas bauen. [Mehr erfahren]

Frog_Qmak 01 Dez 2023 18:03

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... [Mehr erfahren]

bb84 01 Dez 2023 23:26

So etwas wäre nützlich, um ein U-Boot in einer Tiefe von 2-3 m zu steuern. [Mehr erfahren]

Krzysztof Kamienski 02 Dez 2023 04:45

@frogqmak, vielleicht ist es nicht dumm, aber mit dem Bearbeitungsstil hast du mir den Appetit aufs Frühstück verdorben. Entschuldigung. [Mehr erfahren]

Frog_Qmak 02 Dez 2023 10:55

@krzysztofkamienski, 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... [Mehr erfahren]

OPservator 02 Dez 2023 16:29

Was ist die Höchstgeschwindigkeit? [Mehr erfahren]

Frog_Qmak 03 Dez 2023 07:38

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... [Mehr erfahren]

mpier 07 Dez 2023 17:34

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.... [Mehr erfahren]

Frog_Qmak 07 Dez 2023 18:03

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... [Mehr erfahren]

Frog_Qmak 15 Apr 2024 17:31

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,... [Mehr erfahren]

Slawek K. 16 Apr 2024 05:55

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... [Mehr erfahren]

Frog_Qmak 16 Apr 2024 21:53

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,... [Mehr erfahren]

Frog_Qmak 15 Jun 2024 16:28

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... [Mehr erfahren]