zweiter Perimeterempfänger in Azurit

Biland

Member
Guten Morgen zusammen,
ich bin grade dabei, meinem Mower einen zweiten Perimeterempfänger zu spendieren. Aus dem zweiten Empfänger brauche ich eigentlich nur das Signal (isInside) um im Random Mähbetrieb folgendes zu realisieren:
- wenn der Empfänger "left" getriggert wird (IsInside = 0) dann Fahre Rückwärts und Roll = Right
- wenn der Empfägner "rechts" getriggert wird (IsInsideR = 0) dann Farhe Rückwärts und Roll = Left

Ich möchte damit den Random Roll ersetzten.

Die elektrische Installation ist ja kein Problem. In derSoftware habe ich auch bereits ein paar Parameter angepasst und Variablen hinzugefügt.
z.B.: isInside --> isInsideR / perimeterTriggerTime --> perimeterTriggerTimeR / perimeterMag --> perimeterMagR / ...

Den Code habe ich an den enstprechenden Stellen auch so umgeschrieben, dass die neuen Variablen von dem neuen Receiver kommen wie z.B. hier:
Code:
  if ((perimeterUse) && (millis() >= nextTimePerimeter)){   
    if (stateCurr == STATE_PERI_TRACK) nextTimePerimeter = millis() +  30;   
    else nextTimePerimeter = millis() +  50;   // 50
    perimeterMag = readSensor(SEN_PERIM_LEFT);
    perimeterMagR = readSensor(SEN_PERIM_RIGHT);   // Smi: Hinzu
    if (stateCurr == STATE_PERI_FIND)perimeterMagMedian.add(abs(perimeterMag));
    if ((perimeter.isInside(0) != perimeterInside)){     
      perimeterCounter++;
            setSensorTriggered(SEN_PERIM_LEFT);
      perimeterLastTransitionTime = millis();
      perimeterInside = perimeter.isInside(0);
    }   
    if ((perimeter.isInsideR(0) != perimeterInsideR)){     
      perimeterCounter++;
      setSensorTriggered(SEN_PERIM_RIGHT);
      perimeterLastTransitionTime = millis();
      perimeterInsideR = perimeter.isInsideR(0);
    }

dies funktioniert auch bei den Mag Werten. Leider klappt es nicht bei der Variable "isInsideR". Im Perimeter Plot sowie im Log währed des Radom Mowings reagiert der neue Receiver (right) nicht auf die Schleife bzw. erkennt er nicht wenn wer die PeriSchleife überquert. Der bestehende Sensor (left) reagiert dafür doppelt und triggert laut Log jeweils SEN_PERIM_LEFT und SEN_PERIM_RIGHT.

Ich hoffe mir kann hier ein Azurit Experte helfen. Meine Skills beim Programmieren sind auch sehr sehr begrenzt ;-)
 
Ich habe das bei mir (vergleichbar) umgesetzt.
Ich nutze den zweiten Empfänger für:
- Drehen, am Draht (wie Du auch)
- Softborder : da stoppt das innere Rad und der Mäher dreht nach innen ohne zurück zu fahren (vorausgesetzt, der Winkel ist flach genug. Das ist sehr nützlich in engen Passagen, denn dann pendelt er zwischen den Begrenzungen
- es gibt noch Drahtfolgen, das habe ich noch nicht ausreichend getestet, - da läuft er Zeit x am Draht entlang
- Perimetertracking: reduziert die Unruhe im Antrieb und schont den Servo bei 4wd
Der zweite Empfänger bringt auch mehr Sicherheit vor ungewollten Ausflügen in die Beete

Ich stelle meine code später in meinem Beitrag ein und gebe Dir Bescheid, dann kannst Du Dir das ansehen.

Gruß Fürst Ruprecht
 
erledigt ;-) aber dein Code interessiert mich auf jedenfall. Du hattest mir den ja vor ca. einem Jahr schonmal gesendet aber dort war wahrscheinlich das "SoftBorder" noch nicht im Code oder? Habs zumindest eben nicht gesehen ;-)
 
das einizige was noch probleme bereitet ist nun die Signalstärke vom Coil / Empfänger left (also der, der ohnehin verbaut ist bzw. war). Die Signalstärke ist aufeinmal so niedrig das ich ständig Timeouts habe und der Mower auch nicht mehr startet sobald er etwas weiter von der schleife entfernt steht (perimeter to far away). Spannung am Ausgang des Spannungswandlers im Perimetersender ist auf 12V und der Schleifenwiderstand beträgt 4Ohm + einen in Reihegeschalteten 10Ohm Leistungswiderstand. Das sollte also passen. Ich vermute es liegt einfach an den neuen Positionen der Empfängerspulen ... werd mir morgen mal ein Bild davon machen.

Kannst du bzw. Ihr mir ggf. noch sagen, wo im Code die Zuordung der im Bluetooth Perimeterplott angezeigten Werte eingestellt werden kann? Seit dem ich den zweiten Empfänger in den Code integriert hab, stimmt hier die Zuordnung nicht mehr (siehe Screenshot).
 

Anhänge

  • smag_magPNG.PNG
    smag_magPNG.PNG
    60,1 KB · Aufrufe: 12
Zuletzt bearbeitet:
Azurit-Code ist eingestellt.
Ich nutze nicht die App sondern das WebControl mit eigenem "LiveData"-Plot. Daher ist die pfod und die html-Dateien abweichend.
Ob mein Stand des WebControl mit der Handy-App läuft, kann ich nicht sagen (eher nicht).
Die Zuordnung findet in der pfod.cpp statt.
Wenn Du die zu meinem azurit-code passende WebControl-Dateien möchtest, sag Bescheid.

Gruß Fürst Ruprecht
 
Danke für deinen Support.

Hab dein Konzept der Erkennung, welcher Perimeterempfänger zuerst bzw. zuletzt den Drath überfährt in meinen Code integriert und das Mähen im Random Mode funktioniert nun wie ich es mir vorgestellt habe.

Den Codeteil für die APP habe ich auch angepasst sodass alle Werte sauber in der App dargestellt werden.
Das Thema mit dem Webcontrol interessiert mich auch jedoch möchte ich mir erstmal das Tracking ansehen.

Wie gehst du in deinem Code damit um? Nutzt du beide Empfänger oder nur einen wie in der Azurit es als Standard gecoded ist?
 
Ich habe das Tracking deutlich angepaßt und nutze beide Empfänger .
Das Funktionsprinzip in Azurit beruht darauf, daß der Single- Empfänger über dem Draht zwischen Draußen und Drinnen pendelt. Das ist für eine aktive Lenkung/Servo sehr ungünstig, weil sie permanent arbeiten muß. Beim Zweiradantrieb belastet das natürlich auch die Mechanik, das sieht man aber nicht so deutlich, nur manche bemängeln das unruhige Tracking.
Ich lasse bei zwei Empfängern einen Draußen und einen Drinnen laufen und schreite ein, wenn beide auf der gleichen Seite sind. Man kann zudem die Signalstärke beider Empfänger nutzen zur Feinsteuerung. Bei Anfahren des Drahtes ist die Erkennung auch anders, da man direkt erkennen kann, ob man in die richtige Richtung fährt. Es wäre auch denkbar, daß der Mäher beide Richtungen zum Fahren zur Ladestation nutzt (habe ich aber nicht umgesetzt).
Mit dem Abstand der Empfänger zueinander muß ich noch experimentieren.
Gruß Fürst Ruprecht
 
Hi Fürst Ruprecht hab mir deinen Code und das Tracking mal angeschaut und bei mir integriert das tracking ist wirklich super smooth und sauber. An einem Punkt habe ich jedoch Probleme:
- Tracking im Uhrzeigersinn (Perimetersensor rechts drinnen / links draußen)

An einer 90° Ecke nach links ist das Tracking nicht aggresiv genug. Der Mower nimmt die Kurve nicht eng genug und kommt mit beiden Sensoren nach innen.
Nach einer Zeit schaltet er dann um in Perimeter_Find er ist dann aber schon viel zu weit weg vom Draht.

Vom Drahtverlauf her, ist es auf meinem Grundstück die einzige scharfe Linkskurve. Sonst gibt es nirgendwo Probleme.
An welcher Stelle, kann ich den Code anpassen damit ich folgende Logik integrieren kann:?
- Ausgangssitation: sauberes Tracking im Uhrzeigersinn (rechte Spule innen / links Spule außen)
- nun kommt die 90° links Kurve
- sobald linke Empfänger Spule auch innen dann:

--> Motor rechts = MaxSpeedperiPwm/2 und Motor links = -MaxSpeedperiPwm/2 (>> also Rückwärts)



Code:
//PID controller: track perimeter
void Robot::motorControlPerimeter() {
  //3 states
  //wire is lost
  //On the wire staright line pid fast action
  //Back slowly to the wire pid soft action

  //Control the perimeter motor only each 30ms
  if (millis() < nextTimeMotorPerimeterControl) return;
  nextTimeMotorPerimeterControl = millis() + 30; //possible 15ms with the DUE
    /*  PID:
   *  e = w - x  
   *  y = y_old + kp*(e-e_old) + ki*Ta*e + kd/Ta*(e-2*e_old1+e_old2)  
   *  für x = 0 => e = w
   *  y = y_old + kp*(w-w_old) + ki*Ta*w + kd/Ta*(w-2*w_old+w_old2)
   */

  //PerimeterMagMaxValue=2000;  //need to change in the future    
  //tell to the pid where is the mower   (Pid.x)
  perimeterPID.x = 0;                                                                                                               //SMI: Tracking neu
  perimeterPID.w = (double(perimeterMag) / perimeterMagMaxValue)+(double(perimeterMagR) / perimeterMagMaxValueR);                   //steuert bereits auf Drahtmitte
   //tell to the Pid where to go (Pid.w)
   if ((!perimeterInside) && (perimeterInsideR)) {                                                                                  //fährt über den Draht
        perimeterPID.w = (double(perimeterMag) / perimeterMagMaxValue)+(double(perimeterMagR) / perimeterMagMaxValueR);
        perimeterLastTransitionTime = millis();
  }  
  else if(perimeterInside && perimeterInsideR) {  
    perimeterPID.w -= -0.5;
  }
  else if(!perimeterInside && !perimeterInsideR) {
    perimeterPID.w += 0.5;                              
  }

  //parameter the PID
  perimeterPID.y_min = -MaxSpeedperiPwm ;
  perimeterPID.y_max = MaxSpeedperiPwm ;
  perimeterPID.max_output = MaxSpeedperiPwm ;
  //and compute
  perimeterPID.compute();


  //First state wire is lost
  //important to understand TrackingPerimeterTransitionTimeOut It's if during this maximum duration the robot does not make a transition in and  out then it is supposed to have lost the wire, the PID is stopped to go into blocking mode of one of the two wheels.
  // If the trackingPerimeterTransitionTimeOut is too large the robot goes too far out of the wire and goes round in a circle outside the wire without finding it

  // If the second condition is true the robot has lost the wire since more trackingPerimeterTransitionTimeOut (2500ms) for example it is then necessary to stop one of the 2 wheels to make a half turn and find again the wire
  if ((millis() > stateStartTime + 2000) && (millis() > perimeterLastTransitionTime + trackingPerimeterTransitionTimeOut)) {   // SMI: war ((millis() > stateStartTime + 10000)
      //Begin second condition  FR:siehe "void Robot::checkPerimeterFind("
     
      if (perimeterInsideR){                                                            //SMI: rechter Schleifenempfänger innen                                                                    
      if ( (!perimeterInside)&&(perimeterInsideR) ) {                                 //SMI: rechts drin / links draußen >> fährt bereits auf dem Draht  
        leftSpeedperi = rightSpeedperi = MaxSpeedperiPwm/2;                           //SMI: etwas langsamer          
      } else {                                                                        //SMI: beide Empfänger innen >> zu weit drinn, leichte Linkskurve
        rightSpeedperi = MaxSpeedperiPwm / 1.5;                                       //SMI: bereits getestet MaxSpeedperiPwm / 2
        leftSpeedperi =  MaxSpeedperiPwm / 3;                                         //SMI: bereits getestet -MaxSpeedperiPwm / 2
        // we record The time at which the last wire loss occurred
        lastTimeForgetWire = millis();
       // if we have lost the wire from too long time (the robot is running inside the wire we start state_peri_find again)
        if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {    
          Console.println(F("Error: tracking error"));                                //SMI: zu lange nicht auf Draht >> grade aus und Peri find
          addErrorCounter(ERR_TRACKING);
          leftSpeedperi=rightSpeedperi=motorSpeedMaxRpm / 1.5;        
          setMotorPWM( leftSpeedperi, rightSpeedperi, false);  
          //send to motor
          setNextState(STATE_PERI_FIND, 0);
          //Console.print("motorControlPerimeter setNextState STATE_PERI_FIND ( ");Console.print(leftSpeedperi);Console.print(",");Console.print(rightSpeedperi);Console.println(")");
          return;
        }            
      }
    } else { // (!perimeterrightInside)                                           //SMI: linker und rechter Epfänger draußen >> rückwärts rechts                                                            
        rightSpeedperi = -MaxSpeedperiPwm / 1.5;      
        leftSpeedperi  = -MaxSpeedperiPwm / 3;    
        setMotorMowPWM(0,true);
        // we record The time at which the last wire loss occurred
        lastTimeForgetWire = millis();
        // if we have lost the wire from too long time (the robot is running outside the wire we stop everything)
        if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {    
          Console.println(F("Error: tracking error"));
          addErrorCounter(ERR_TRACKING);
          setNextState(STATE_ERROR,0);
          return;
        }                  
        //Console.print("leftSpeedperi, rightSpeedperi=");    Console.print(leftSpeedperi);Console.print(" ");    Console.print(rightSpeedperi);Console.println(" ");
        //send to motor
        setMotorPWM( leftSpeedperi, rightSpeedperi, false);  
        //Console.print("motorControlPerimeter !perimeterrightInside ( ");Console.print(leftSpeedperi);Console.print(",");Console.print(rightSpeedperi);Console.println(")");
        //End second condition
    }
  } else {
    //we are in straight line the pid is total and not/2
    rightSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5  - perimeterPID.y));
    leftSpeedperi =  max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5  + perimeterPID.y));  
       
    //Console.print("leftSpeedperi, rightSpeedperi=");    Console.print(leftSpeedperi);Console.print(" ");    Console.print(rightSpeedperi);Console.println(" ");
    setMotorPWM( leftSpeedperi, rightSpeedperi, false);
    //Console.print("motorControlPerimeter - lenken( ");Console.print(leftSpeedperi);Console.print(",");Console.print(rightSpeedperi);Console.println(")");
  }
  //if the mower move in perfect straight line the transition between in and out is longuer so you need to reset the perimeterLastTransitionTime
  if (abs(perimeterMag ) < perimeterMagMaxValue/4) {
    perimeterLastTransitionTime = millis(); //initialise perimeterLastTransitionTime in perfect sthraith line
  }
}
 
Zuletzt bearbeitet:
da fällt mir folgendes dazu ein:
1. den P-Anteil im PID-Regler (pfod-App) erhöhen . Dadurch reagiert der Mäher stärker auf die Abweichung. Das sollte bereits genügen.
2. negative Werte zulassen - durch max(0,…. kann das Motorsignal nicht negativ werden

„ } else {
//we are in straight line the pid is total and not/2
rightSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5 - perimeterPID.y));
leftSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5 + perimeterPID.y)); „

wenn der P-Wert des Reglers erhöht wird, wird perimeterPID.y größer und „MaxSpeedperiPwm/1.5 - perimeterPID.y“ kann negativ werden. Durch max(0, min(..
wird das aber nicht kleiner als 0. Du kannst anstelle 0 zB. -MaxSpeedperiPWM/2 eintragen

Gruß Fürst Ruprecht
 
Hi danke dir!

... das mit dem "-MaxSpeedperiPWM/2" werd ich morgen mal probieren.

Hatte eben noch mit einem Problem zu kämpfen, dass der Mower die Kontakte der Ladestation nicht mehr erkannt hat und dadurch das PerimeterTracking nicht gestoppt hat. Zusätzlich lädt er nicht. Spannung liegt an den Kontakten an. Will mir morgen mal die Sicherung EF1 anschauen. Vielleicht ist die hinüber.
 
Hi also der Mower läuft wieder es war wirklich die Sicherung. MIt der Erhöhung des P-Anteils meinst du die Variable: "perimeterPID.Kp" oder?
Hab diesen mal von 50 auf 95 erhöht. Das Lenkverhalten ist aggresiver (noch ohne ins "vibrieren / Schlangenlinie" zu kommen.
Leider reicht es bei dem 90° Knick nach links noch nicht aus. Beide Sensoren kommen ins Innere und der Mower fährt einen zu weiten Bogen.
Die Inneren Räder sind im Stillstand. Da hilft nun nur, die inneren Räder etwas Rückwärts laufen zu lassen.
Welchen teil im Code muss ich hierfür anpassen?

Hab den Teil nach "//we are in straight line the pid is total and not/2" angepasst und die "0" durch ein "-MaxSpeedperiPwm/2" ersetzt aber er dreht nicht Rückwärts.
Ist das die Richtige Stelle im Code? oder Muss ich eher Hier etwas anpassen?
...
if (perimeterInsideR){ //SMI: rechter Schleifenempfänger innen
if ( (!perimeterInside)&&(perimeterInsideR) ) { //SMI: rechts drin / links draußen >> fährt bereits auf dem Draht
leftSpeedperi = rightSpeedperi = MaxSpeedperiPwm/2; //SMI: etwas langsamer
} else { //SMI: beide Empfänger innen >> zu weit drinn, leichte Linkskurve
rightSpeedperi = MaxSpeedperiPwm / 1.5; //SMI: bereits getestet MaxSpeedperiPwm / 2
leftSpeedperi = MaxSpeedperiPwm / 3; //SMI: bereits getestet -MaxSpeedperiPwm / 2

...


Code:
//PID controller: track perimeter
void Robot::motorControlPerimeter() {
  //3 states
  //wire is lost
  //On the wire staright line pid fast action
  //Back slowly to the wire pid soft action

  //Control the perimeter motor only each 30ms
  if (millis() < nextTimeMotorPerimeterControl) return;
  nextTimeMotorPerimeterControl = millis() + 30; //possible 15ms with the DUE
    /*  PID:
   *  e = w - x   
   *  y = y_old + kp*(e-e_old) + ki*Ta*e + kd/Ta*(e-2*e_old1+e_old2)   
   *  für x = 0 => e = w
   *  y = y_old + kp*(w-w_old) + ki*Ta*w + kd/Ta*(w-2*w_old+w_old2)
   */ 
 
  //PerimeterMagMaxValue=2000;  //need to change in the future     
  //tell to the pid where is the mower   (Pid.x)
  perimeterPID.x = 0;                                                                                                               //SMI: Tracking neu
  perimeterPID.w = (double(perimeterMag) / perimeterMagMaxValue)+(double(perimeterMagR) / perimeterMagMaxValueR);                   //steuert bereits auf Drahtmitte
   //tell to the Pid where to go (Pid.w)
   if ((!perimeterInside) && (perimeterInsideR)) {                                                                                  //fährt über den Draht
        perimeterPID.w = (double(perimeterMag) / perimeterMagMaxValue)+(double(perimeterMagR) / perimeterMagMaxValueR);
        perimeterLastTransitionTime = millis();
  }   
  else if(perimeterInside && perimeterInsideR) {   
    perimeterPID.w -= -0.5;
  }
  else if(!perimeterInside && !perimeterInsideR) {
    perimeterPID.w += 0.5;                               
  }
 
  //parameter the PID
  perimeterPID.y_min = -MaxSpeedperiPwm ;
  perimeterPID.y_max = MaxSpeedperiPwm ;
  perimeterPID.max_output = MaxSpeedperiPwm ;
  //and compute
  perimeterPID.compute();


  //First state wire is lost
  //important to understand TrackingPerimeterTransitionTimeOut It's if during this maximum duration the robot does not make a transition in and  out then it is supposed to have lost the wire, the PID is stopped to go into blocking mode of one of the two wheels.
  // If the trackingPerimeterTransitionTimeOut is too large the robot goes too far out of the wire and goes round in a circle outside the wire without finding it

  // If the second condition is true the robot has lost the wire since more trackingPerimeterTransitionTimeOut (2500ms) for example it is then necessary to stop one of the 2 wheels to make a half turn and find again the wire
  if ((millis() > stateStartTime + 2000) && (millis() > perimeterLastTransitionTime + trackingPerimeterTransitionTimeOut)) {   // SMI: war ((millis() > stateStartTime + 10000)
      //Begin second condition  FR:siehe "void Robot::checkPerimeterFind("
      
      if (perimeterInsideR){                                                            //SMI: rechter Schleifenempfänger innen                                                                     
      if ( (!perimeterInside)&&(perimeterInsideR) ) {                                 //SMI: rechts drin / links draußen >> fährt bereits auf dem Draht   
        leftSpeedperi = rightSpeedperi = MaxSpeedperiPwm/2;                           //SMI: etwas langsamer           
      } else {                                                                        //SMI: beide Empfänger innen >> zu weit drinn, leichte Linkskurve
        rightSpeedperi = MaxSpeedperiPwm / 1.5;                                       //SMI: bereits getestet MaxSpeedperiPwm / 2
        leftSpeedperi =  MaxSpeedperiPwm / 3;                                         //SMI: bereits getestet -MaxSpeedperiPwm / 2
        // we record The time at which the last wire loss occurred
        lastTimeForgetWire = millis(); 
       // if we have lost the wire from too long time (the robot is running inside the wire we start state_peri_find again)
        if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {     
          Console.println(F("Error: tracking error"));                                //SMI: zu lange nicht auf Draht >> grade aus und Peri find
          addErrorCounter(ERR_TRACKING);
          leftSpeedperi=rightSpeedperi=motorSpeedMaxRpm / 1.5;         
          setMotorPWM( leftSpeedperi, rightSpeedperi, false);   
          //send to motor
          setNextState(STATE_PERI_FIND, 0);
          //Console.print("motorControlPerimeter setNextState STATE_PERI_FIND ( ");Console.print(leftSpeedperi);Console.print(",");Console.print(rightSpeedperi);Console.println(")");
          return;
        }             
      }
    } else { // (!perimeterrightInside)                                           //SMI: linker und rechter Epfänger draußen >> rückwärts rechts                                                             
        rightSpeedperi = -MaxSpeedperiPwm / 1.5;       
        leftSpeedperi  = -MaxSpeedperiPwm / 3;     
        setMotorMowPWM(0,true);
        // we record The time at which the last wire loss occurred
        lastTimeForgetWire = millis();
        // if we have lost the wire from too long time (the robot is running outside the wire we stop everything)
        if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {     
          Console.println(F("Error: tracking error"));
          addErrorCounter(ERR_TRACKING);
          setNextState(STATE_ERROR,0);
          return;
        }                   
        //Console.print("leftSpeedperi, rightSpeedperi=");    Console.print(leftSpeedperi);Console.print(" ");    Console.print(rightSpeedperi);Console.println(" ");
        //send to motor
        setMotorPWM( leftSpeedperi, rightSpeedperi, false);   
        //Console.print("motorControlPerimeter !perimeterrightInside ( ");Console.print(leftSpeedperi);Console.print(",");Console.print(rightSpeedperi);Console.println(")");
        //End second condition
    } 
  } else {
    //we are in straight line the pid is total and not/2
  //  rightSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5  - perimeterPID.y));
      rightSpeedperi = max(-MaxSpeedperiPwm/2, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5  - perimeterPID.y));
  //  leftSpeedperi =  max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5  + perimeterPID.y));   
      leftSpeedperi =  max(-MaxSpeedperiPwm/2, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5  + perimeterPID.y)); 
        
    //Console.print("leftSpeedperi, rightSpeedperi=");    Console.print(leftSpeedperi);Console.print(" ");    Console.print(rightSpeedperi);Console.println(" ");
    setMotorPWM( leftSpeedperi, rightSpeedperi, false);
    //Console.print("motorControlPerimeter - lenken( ");Console.print(leftSpeedperi);Console.print(",");Console.print(rightSpeedperi);Console.println(")");
  }
  //if the mower move in perfect straight line the transition between in and out is longuer so you need to reset the perimeterLastTransitionTime
  if (abs(perimeterMag ) < perimeterMagMaxValue/4) {
    perimeterLastTransitionTime = millis(); //initialise perimeterLastTransitionTime in perfect sthraith line
  } 
}
 
Nein, das ist die falsche Stelle, weil „trackingPerimeterTransitionTimeOut„ überschritten ist, was bedeutet, daß der Draht verloren wurde.
Ich denke …
 
An der Stelle sehe ich jetzt nicht die Ursache (was nichts heißen soll).
Kann im Moment den code nicht einsehen, es könnte aber am Motorregler liegen, der keine negativen Werte zuläßt. Welcher kommt bei Dir zum Einsatz (abhängig von IMU)?
 
Hi danke für dein Feedback. Ich nutzte den MC33926 Dual ... hab gestern nochmal den Standard Code Azurit (Tracking mit einer Spule) geflasht. Dort drehen die Inneren Räder bei extrem engen Kurven rückwärts. den Motortreiber schieße ich demnach aus.

Welcher Teil des Codes (Tracking) ist für das Tracking verantwortlich, wenn der Mower nach Innen den Drath verloren hat?
 
Fehlt im dem Block des Codes ... nicht ein "setMotorPWM( leftSpeedperi, rightSpeedperi, false);" (Zeile 4 und 11)

Code:
if (perimeterInsideR){                                                            //SMI: rechter Schleifenempfänger innen                                                                   
if ( (!perimeterInside)&&(perimeterInsideR) ) {                                 //SMI: rechts drin / links draußen >> fährt bereits auf dem Draht 
leftSpeedperi = rightSpeedperi = MaxSpeedperiPwm/2;                           //SMI: etwas langsamer         
// fehlt hier nicht ein: setMotorPWM( leftSpeedperi, rightSpeedperi, false);
}
else {                                                                        //SMI: beide Empfänger innen >> zu weit drinn, leichte Linkskurve
rightSpeedperi = MaxSpeedperiPwm / 1.5;                                       //SMI: bereits getestet MaxSpeedperiPwm / 2
leftSpeedperi =  MaxSpeedperiPwm / 3;                                         //SMI: bereits getestet -MaxSpeedperiPwm / 2
// we record The time at which the last wire loss occurred
lastTimeForgetWire = millis();
// fehlt hier nicht ein: setMotorPWM( leftSpeedperi, rightSpeedperi, false);

// if we have lost the wire from too long time (the robot is running inside the wire we start state_peri_find again)
if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {   
Console.println(F("Error: tracking error"));                                //SMI: zu lange nicht auf Draht >> grade aus und Peri find
addErrorCounter(ERR_TRACKING);
leftSpeedperi=rightSpeedperi=motorSpeedMaxRpm / 1.5;       
setMotorPWM( leftSpeedperi, rightSpeedperi, false);
//send to motor
setNextState(STATE_PERI_FIND, 0);
return;
}           
}
}
 
Nein. Im oberen Teil wird nur der PID-Regler gefüttert. Damit wird dann der Motorregler aufgerufen, wenn der Mäher in „straight line“ fährt. Alles andere funktioniert ohne PID-Regler durch Vorgabe der konkreten Raddrehzahl.
Ich habe gerade meinen neuen Servo-DIY-Antrieb der Lenkung getestet.
Wenn mein Mäher die Kurve nicht kriegt, dann fährt er ein wenig zurück und nimmt neu Anlauf. Das muß Deiner auch können. Dazu sind in der App entsprechend die Zeiten für Rückwärtsfahren und Kurve einzustellen.
Vielleicht stellst Du mal ein Video ein, wie es beim Fehlerfall aussieht - Videos sind immer schön :)
Auch wenn der Code recht schwer zu verstehen ist, muß man den Erstellern zugestehen, daß er sehr gut durchdacht ist. Ich habe viele meiner Änderungen wieder zurück genommen. Also meine Empfehlung: zuerst das vorhandene möglichst (verstehen) und ausschöpfen.
Ich sehe mir später noch den Regler an.
Gruß Fürst Ruprecht
 
1. Im Regler sehe ich nix.
2. Du kannst noch folgendes ändern:
perimeterPID.max_output = MaxSpeedperiPwm
-> damit wird die Radgeschwindigkeit aktuell maximal 1/2 MaxSpeedperiPWM.
perimeterPID.max_output = 3/2*MaxSpeedperiPwm
Das erklärt aber nicht, warum er im Regelbereich nicht mit einem Rad rückwärts fährt.
Erhöhe testweise kp weiter.

3. "- Tracking im Uhrzeigersinn .. 90° Knick nach links noch nicht aus.....Die Inneren Räder sind im Stillstand. Da hilft nun nur, die inneren Räder etwas Rückwärts laufen zu lassen. "
- also die linken Räder müssen rückwärts, die rechten vorwärts laufen, oder nicht?

if ((millis() > stateStartTime + 10000) && (millis() > perimeterLastTransitionTime + trackingPerimeterTransitionTimeOut)) { <-- HAT DRAHT VERLOREN
//Begin second condition FR:siehe "void Robot::checkPerimeterFind("

if (perimeterrightInside){ //FR: 2 Schleifenempfänger
// inside //FR: dann ist er drinnen
if ( (!perimeterleftInside)&&(perimeterrightInside) ) { //FR: fährt bereits auf dem Draht
leftSpeedperi = rightSpeedperi = MaxSpeedperiPwm/2; //FR: mach mal etwas langsamer
} else { //FR: zu weit drinn, leichte Linkskurve <---DAS IST DIESER FALL
rightSpeedperi = MaxSpeedperiPwm / 1.5;
leftSpeedperi = MaxSpeedperiPwm / 3; <-- DANN HIER EINEN NEGATIVEN WERT

Gruß Fürst Ruprecht
 
Hallo so nun funktioniert es. Und es ist wahrscheinlich doch wie ich es im Vorfeld beschrieben habe.
In deinem Code fehlt für den Fall, dass beide Perimeter Empfänger innen sind, der Befehl setmotorpwm "setMotorPWM( leftSpeedperi, rightSpeedperi, false);"

Schau mal genau hin...
auf jeden Teil deines Codes folgt "setMotorPWM( leftSpeedperi, rightSpeedperi, false);"
1. if: perimeterEmpfanger links = raus & perimeterEmpfänger rechts = innen
2. else (also: perimeterEmpfanger links = innen & perimeterEmpfänger rechts = innen) hier fehlt der Befehl "setMotorPWM( leftSpeedperi, rightSpeedperi, false);"
2b. wenn der Draht zu lange verloren ist dann Error and Perimeter Find
3. if: perimeterEmpfanger links = raus & perimeterEmpfänger rechts = raus
4. in Straight

Ich hab den Befehl nun eingefügt. Nun reagiert der Mower auch auf die Anpassung in Zeile 5 und 6 .


Code:
if (perimeterInsideR){                                                            //SMI: rechter Schleifenempfänger innen                                                                     
if ( (!perimeterInside)&&(perimeterInsideR) ) {                                 //SMI: rechts drin / links draußen >> fährt bereits auf dem Draht   
leftSpeedperi = rightSpeedperi = MaxSpeedperiPwm/2;                           //SMI: etwas langsamer           
} else {                                                                        //SMI: beide Empfänger innen >> zu weit drinn, leichte Linkskurve
rightSpeedperi = MaxSpeedperiPwm;                                       //SMI: bereits getestet MaxSpeedperiPwm / 2
leftSpeedperi =  -MaxSpeedperiPwm;                                         //SMI: bereits getestet -MaxSpeedperiPwm / 2
// we record The time at which the last wire loss occurred
lastTimeForgetWire = millis(); 
setMotorPWM( leftSpeedperi, rightSpeedperi, false);   
// if we have lost the wire from too long time (the robot is running inside the wire we start state_peri_find again)
if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {     
Console.println(F("Error: tracking error"));                                //SMI: zu lange nicht auf Draht >> grade aus und Peri find
addErrorCounter(ERR_TRACKING);
leftSpeedperi=rightSpeedperi=motorSpeedMaxRpm / 1.5;         
setMotorPWM( leftSpeedperi, rightSpeedperi, false);   
setNextState(STATE_PERI_FIND, 0);
return;
}             
}
 
Du hast Recht, da fehlt ein Befehl.
Der sollte aber etwas anders plaziert werden, sonst erfaßt er nicht die erste Bedingung:
Danke.
Gruß Fürst Ruprecht

Code:
if (perimeterrightInside){ //SCHLEIFE-1
// inside //FR: dann ist er drinnen
if ( (!perimeterleftInside)&&(perimeterrightInside) ) { //FR: fährt bereits auf dem Draht
leftSpeedperi = rightSpeedperi = MaxSpeedperiPwm/2; //FR: mach mal etwas langsamer
} else { //FR: zu weit drinn, leichte Linkskurve
rightSpeedperi = MaxSpeedperiPwm / 1.5;
leftSpeedperi = MaxSpeedperiPwm / 3;
// we record The time at which the last wire loss occurred
lastTimeForgetWire = millis();
// if we have lost the wire from too long time (the robot is running inside the wire we start state_peri_find again)
//if-Schleife endet mit return -> braucht setMotorPWM
if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {
Console.println(F("Error: tracking error"));
addErrorCounter(ERR_TRACKING);
leftSpeedperi=rightSpeedperi=motorSpeedMaxRpm / 1.5;
setMotorPWM( leftSpeedperi, rightSpeedperi, false);
//send to motor
setNextState(STATE_PERI_FIND, 0);
return;
}
}
setMotorPWM( leftSpeedperi, rightSpeedperi, false); --> besser hier //FR:SCHLEIFE-1
} else { // (!perimeterrightInside) //FR:SCHLEIFE-2
rightSpeedperi = -MaxSpeedperiPwm / 1.5;
leftSpeedperi = -MaxSpeedperiPwm / 3;
setMotorMowPWM(0,true);
// we record The time at which the last wire loss occurred
lastTimeForgetWire = millis();
// if we have lost the wire from too long time (the robot is running outside the wire we stop everything)
//if-Schleife endet mit return -> braucht setMotorPWM
if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {
Console.println(F("Error: tracking error"));
addErrorCounter(ERR_TRACKING);
setNextState(STATE_ERROR,0);
return;
}
//send to motor
setMotorPWM( leftSpeedperi, rightSpeedperi, false); //FR:CHLEIFE-2
//End second condition
}
} else { //FR:CHLEIFE-3
//we are in straight line the pid is total and not/2
rightSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5 - perimeterPID.y));
leftSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm/1.5 + perimeterPID.y));
setMotorPWM( leftSpeedperi, rightSpeedperi, false); //FR:SCHLEIFE-3
}
//if the mower move in perfect straight line the transition between in and out is longuer so you need to reset the perimeterLastTransitionTime
if (abs(perimeterMagleft ) < perimeterMagleftMaxValue/4) {
perimeterLastTransitionTime = millis(); //initialise perimeterLastTransitionTime in perfect sthraith line
}
} //4WD
 
Oben