Modifikation für Brushless-Motor-ESC

jemihi

New member
Moin,

wo muss ich jetzt im Code das Servo "brushless"
Code:
Servo brushless;
deklarieren und mit
Code:
brushless.attach(pinMotorMowPWM)
initialisieren, damit ich in drivers.cpp mir meine
Code:
void setBrushless(int speed)
Funktion benutzen kann, die ich dann in der mower.cpp in der Funktion
Code:
void Mower::setActuator(char type, int value){
  switch (type){
    case ACT_MOTOR_MOW: setBrushless(value); break;

einsetzen kann. Welche Grenzen hat value, 0 bis 255 oder -255 bis +255 oder 0 bis 1023 oder -1023 bis +1023, geht mir da um die Drehzahlregelung des Mähmotors (mein ESC hat keinen Govenor-Mode)?

In der alten Version war das Klassen-Konzept nicht enthalten und ich hab da wenig Erfahrung mit ... in der 9.3.0 hatte ich das alles in die ardumower.ino geschrieben. Also das Servo im Kopf deaklriert, die Funktion auch oben reingeschrieben, das Servo in der Setup-Funktion initialisiert und dann in der config.h benutzt. Der (in der 9.3.0 programmierte) Regler hat aber extrem schlecht funktioniert, denke da war noch ein Fehler bei value-Bereich drin. Außerdem glaube ich, dass der Arduino die Initialisierung des ESC nicht ganz korrekt macht (Pin wird zu spät gesetzt, da der Arduino länger zum booten braucht als der ESC, aber das sind Krankheiten, die ich noch wegbekomme ...).

Gruß,
Jem
 
Hallo,

hier meine Brushless Einstellungen (SVN Version):

Betroffen sind 3 Dateien:

-ardumower.ino
-robot.h
-mower.cpp


-ardumower.ino:
Zeile 41: //#include --> #include


-robot.h:
Zeile 34: //#include --> #include
Zeile 210: --> Servo brushless;


-mower.cpp
(brushless ESC an 5V, Masse und pinMotorMowPWM anschliesen (bei mir Pin 8))
Zeile 266: --> brushless.attach(pinMotorMowPWM);
Zeile 267: --> brushless.write(45);

Zeile 421: case ACT_MOTOR_MOW: setL298N(pinMotorMowDir, pinMotorMowPWM, value); break;
aendern in:
case ACT_MOTOR_MOW: {
int VAL = map (value, 0, 255, 45, 155);
brushless.write(VAL);}break;


Erklärung:
Servotiming 1ms (linker Anschlag) bis 2ms (rechter Anschlag)
somit sollte 0 => 1ms und 255 => 2ms ergeben.
Bei meinem Mega ergeben die Sollwerte 0..255 ==> ca. 0,7ms .. 2,6ms (mit Oszi gemessen)
Durch verändern und messen ermittelt: 45 => 1ms und 155 => 2ms

siehe http://de.wikipedia.org/wiki/Servo siehe http://en.wikipedia.org/wiki/File:ServoPwm.png
 
Ich hatte das jetzt übergangsweise mit einem extra Nano erledigt. Der hat sich nicht nur um die Drehzahlregelung gekümmert, sondern auch gleich den Strom überwacht und aufgezeichnet. Außerdem konnte ich die Regelung schön in meinem eigenen Code-Wurst-Style zusammenklatschen.

Außerdem hatte ich damit den (vorher) nicht funktionierenden Ultraschallsensor zum laufen gebracht, der Code ist im Programm demnach nicht mehr nötig, ich hab ihn aber mal drin gelassen.

Ich weiss es ist absolut unvollkommen, deswegen bitte nicht lachen, aber es funktioniert extrem gut und ich glaube, ich werde es so lassen ...


Code:
#include <Servo.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(4,7,8,10,11,13);
unsigned long duration=0;
unsigned long timer;
unsigned long timer2=0;
unsigned long timer3=0;
unsigned long timer4=0;
double pwm=1000.0;
double rpm=0.0;
long count=0;
double abstand = 0.0;
double i = 0.0;
double strom = 0.0;
double strom_kalib = 509.0;
double gesamtstrom = 0.0;
double sollwert = 3600.0;
long sollwert_counter = 0;

int trigger = 3;
int echo = 12;
int esc = 9;
int enable = 5;
int zunah = 6;

Servo brushless;

double getDistance()  //Sonar
{
  double distance;
  unsigned long pulseduration = 0;
  
  digitalWrite(trigger, LOW);
  delayMicroseconds(50);  // Hier hab ich längere Delays eingetragen, damit der SR04 innerhalb der Spezifikation läuft und die Ergebnisse SIND besser.
  digitalWrite(trigger, HIGH);
  delayMicroseconds(25);
  digitalWrite(trigger, LOW);
  
  pulseduration = pulseIn(echo, HIGH, 3000);
  distance = (double)pulseduration / 58.8; // Umrechnung in cm
  
  return distance;
}

void setup()
{
  attachInterrupt(0, blink, CHANGE); // Pin 2
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);
  brushless.attach(esc);
  pinMode(enable, INPUT);
  pinMode(zunah, OUTPUT);
  Serial.begin(9600);
  brushless.writeMicroseconds(pwm);
  timer = millis() + 10000;
  Serial.print("SETUP | Timer = ");
  Serial.println(timer);
  digitalWrite(zunah, HIGH);
  lcd.begin(16,2);
  lcd.clear();
}

void loop()
{
  bool AnAus;
  strom = strom * 0.99 + (double)analogRead(A0) * 0.01;
  if (1 == digitalRead(enable))  // Dazu die L298M-Funktion im Mega leicht umgeschrieben ...
  {
      AnAus = true;
      if (timer4 == 0)
      {
          timer4 = millis()+12000;  // Hochdrehen ohne Regelung
      }
  }
  else
  {
      AnAus = false;
      timer4 = 0;
      strom_kalib = strom_kalib * 0.9 + 0.1 * strom;  // Nullwert für Kalibrierung
      sollwert_counter = 0;
      sollwert = 3600.0;
  }
  
  if (millis() > (timer3+50))
  {
      rpm = rpm * 0.7 + (double)duration * 600.0 * 0.3;  //Drehzahl berechnen
      duration = 0;
      abstand = abstand * 0.7 + getDistance() * 0.3;  // Abstand berechnen
      
      i = 0.7 * i + (strom - strom_kalib) * -74.05432625 * 0.3;  // Strom berechnen
      timer3 = millis();
  }
  
  if ((abstand < 45.0) && (abstand > 5.0))  
  {
      digitalWrite(zunah, LOW);  // Geht auf Bumper Left
  }
  else
  {
      digitalWrite(zunah, HIGH);
  }
  
  if (millis() > (timer+250))
  {
      timer = millis();
      if (AnAus)
      {
          if (millis() > timer4)
          {
              if (rpm > ((int)(sollwert * 1.17)))  // 4212
              {
                  pwm = pwm - 2.0;
              }
              else if (rpm < ((int)(sollwert * 0.83)))  // 2988
              {
                  pwm = pwm + 2.0;
              }
              if (rpm > ((int)(sollwert * 1.09)))  // 3924
              {
                  pwm = pwm - 1.5;
              }
              else if (rpm < ((int)(sollwert * 0.91)))  // 3276
              {
                  pwm = pwm + 1.5;
              }
              else if (rpm > ((int)(sollwert * 1.03)))  // 3708
              {
                  pwm = pwm - 1.0;
              }
              else if (rpm < ((int)(sollwert * 0.97)))  // 3492
              {
                  pwm = pwm + 1.0;
              }
              if (i > 4000.0)
              {
                  pwm = pwm - 5.0;
              }
              if (rpm < ((int)(sollwert * 0.75)))
              {
                  sollwert_counter++;
              }
              else if ( rpm > ((int)(sollwert * 1.25)))
              {
                  sollwert_counter--;
              }
          }
          else
          {
              pwm = 1130.0;
          }
          pwm = (float)constrain((int)pwm, 1130, 1240);
      }
      else
      {
          pwm = 1000.0;
      }
      brushless.writeMicroseconds((int)pwm);
      
  }
  if ((millis() - timer2) > 1000)
  {
      timer2 = millis();
      gesamtstrom = gesamtstrom + (i / 3600.0);
      if (gesamtstrom < 1500.0)
      {
          if (sollwert_counter >= 8)
          {  
              sollwert = sollwert + 25.0;
              sollwert_counter = 0;
          }
          else if (sollwert_counter <= -8)
          {
              sollwert = sollwert - 25.0;
              sollwert_counter = 0;
          }
          if (sollwert >= 4000.0)
          {
              sollwert = 4000.0;
          }
          else if (sollwert <= 3000.0)
          {
              sollwert = 3000.0;
          }
      }
      else
      {
          if (sollwert > 3600.0)
          {
              sollwert = 3600.0;
          }
      } 
      Serial.print(count);
      Serial.print(" | Timer = ");
      Serial.print(timer);
      Serial.print(" | Timer2 = ");
      Serial.print(timer2);
      Serial.print(" | Timer3 = ");
      Serial.print(timer3);
      Serial.print(" | Timer4 = ");
      Serial.print(timer4);
      Serial.print(" | rpm = ");
      Serial.print(rpm);
      Serial.print(" | pwm = ");
      Serial.print(pwm);
      Serial.print(" | Abstand = ");
      Serial.println(abstand);
      lcd.setCursor(0,0);
      lcd.print("RPM");
      lcd.setCursor(0,1);
      lcd.print("PWM");
      lcd.setCursor(9,0);
      lcd.print("G");
      lcd.setCursor(9,1);
      lcd.print("I");
      lcd.setCursor(4,0);
      lcd.print("    ");
      lcd.setCursor(11,0);
      lcd.print("     ");
      lcd.setCursor(11,1);
      lcd.print("     ");
      lcd.setCursor(4,1);
      lcd.print("    ");
      lcd.setCursor(4,0);
      lcd.print(int(rpm));
      lcd.setCursor(11,0);
      lcd.print((int)gesamtstrom);
      lcd.setCursor(4,1);
      lcd.print(int(pwm));
      lcd.setCursor(11,1);
      lcd.print((int)i);
      count++;
  }
}

void blink()
{
  duration++;
}


Mein Brushless hatte einen Stromverbrauch von knappen 6Ah, als die Regelung mal nicht funktionierte (Drehzahlsensor falsch angeklemmt). Dabei eine Drehzahl von etwa 5900 U/min. Nun wird auf etwa 3600 U/min geregelt, das Ansprechverhalten bei Einfahrt ins hohe Gras ist akzeptabel und der Verbrauch liegt im Durchschnitt bei 1200 Ah. Damit kann ich gut leben.

Wenn ich irgendwann mal die Muße habe, werde ich den Nano per I2C an den Mega anschließen.

Gruß,
Jem
 
Oben