Wie versprochen hier die Anpassungen an der Software (1.0a5Azurit)


In der mower.cpp habe ich kleine Anpasungen vorgenommen.

motorAccel auf 500 reduziert. Mir hat es viel zu lange gedauert, bis der Mäher stillsteht.
Hierzu gibt es noch eine Anpassung in der pfod.cpp

Mower::Mower(){
  name = "Ardumower";
  // ------- wheel motors -----------------------------
  motorAccel       = 500;  // motor wheel acceleration - only functional when odometry is not in use (warning: do not set too low)
  motorSpeedMaxRpm       = 25;   // motor wheel max RPM (WARNING: do not set too high, so there's still speed control when battery is low!)

Zudem habe ich die motorZeroSettleTime von 3000 auf 1000 geändert. Damit steht der Mäher schnell still und schiebt keine Hindernisse vor sich her, nachdem der Bumper aktiviert wurde (mower.cpp, Zeile 140)

motorZeroSettleTime   = 1000 ; // how long (ms) to wait for motors to settle at zero speed

Der verbaute Regensensor besteht aus zwei Messingkontakten. Durch Wasser werden diese leitend verbunden. Im Code musste ich den Pullup Widerstand des Pins aktivieren (mower.cpp, Zeile 387)

// rain
  pinMode(pinRain, INPUT);
  pinMode(pinRain, INPUT_PULLUP);

Anpassungen robot.cpp
In der Methode checkBumpers wird geprüft, ob ein Bumper ausgelöst wurde. Wenn der Bumper ausgelöst hat, wird zunächst die Geschwindigkeit langsam reduziert (motorAccel und motorZeroSettleTime) und dann zurück gesetzt. Dadurch werden Hindernisse weiter geschoben bzw. der Mower schiebt sich auf das Hindernis auf. Durch die zwei eingefügten Zeilen steht der Mower sofort still

// check bumpers
void Robot::checkBumpers(){
  if ((mowPatternCurr == MOW_BIDIR) && (millis() < stateStartTime + 4000)) return;

  if ((bumperLeft || bumperRight)) {   
    motorLeftRpmCurr = motorRightRpmCurr = 0 ;  // eingefügt zum direkten Stop
    setMotorPWM( 0, 0, false );                 // eingefügt zum direkten Stop
      if (bumperLeft) {
        reverseOrBidir(RIGHT);          
      } else {
        reverseOrBidir(LEFT);
      }    
  }  
}

Ich bewege den Mower oft im Manuellen Modus per BT (Schleife ist noch nicht verlegt). Wenn man manuell fährt und an ein Hindernis stößt, schiebt der Mower einfach weiter. Mir ist der Mäher dabei einmal an einem Hindernis hoch gestiegen und umgestürzt, die Messer liefen natürlich weiter. Durch diese kleine Anpasung steht der Mower auch bei manueller Fahrt still (robot.cpp, Zeile 2733)

    case STATE_MANUAL:
      if ((bumperLeft || bumperRight)) {    
         motorLeftRpmCurr = motorRightRpmCurr = 0;   
         motorLeftSpeedRpmSet = motorRightSpeedRpmSet = 0;
         setMotorPWM(0 ,0, false); 
      }
      break;

Anpassungen pfod.cpp
Wie in der mower.cpp zu sehen, habe ich motorAccel auf 500 reduziert. Daher ist es auch nötig, in der pfod.cpp die Untergrenze des Sliders anzupassen (pfod.cpp, Zeile 300). Ich habe diese auf 100 gesetzt.

  sendSlider("a11", F("Accel"), robot->motorAccel, "", 1, 2000, 100);

Wie erwähnt fahre ich oft manuell. Dabei hat mich immer gestört, dass der Mäher stets mit voller Geschwindigkeit unterwegs ist (mein Garten ist klein und verwinkelt). Zudem finde ich es störend, dass die „Stop“ Funktion abwechselnd bei dem Forward bzw Reverse Button erscheint, je nachdem wie schnell sich die Räder drehen. „Stop“ muss aus meiner Sicht immer möglich sein, egal wie schnell sich die Räder drehen. Durch meine Anpassungen an den Methoden sendManualMenu und processManualMenu ist der STOP Button jetzt nach unten gewandert und immer erreichbar.
Zudem kann man vorwärts wie rückwärts in zwei Geschwindigkeiten fahren:
– steht der Mäher still und man drückt Forward, geht es zunächst mit halber Geschwindigkeit los
– drückt man nochmal Forward, erhöht sich die Geschwindigkeit auf Max
– drückt man jetzt Reverse, reduziert sich die Geschwindigkeit wieder auf halbe Kraft.
– erneutes drücken auf Reverse verursacht einen Stop.

Rückwärts das gleiche Spiel. Wenn man eine Kurve gefahren ist und dann Forward oder Reverse drückt, geht es wieder mit halber Geschwindigkeit in die gewünschte Richtung

void RemoteControl::sendManualMenu(boolean update){
//  if (update) serialPort->print("{:"); else serialPort->println(F("{^Manual navigation`1000"));
//  serialPort->print(F("|nl~Left|nr~Right|nf~Forward"));
//  if (   ((robot->motorLeftSpeedRpmSet  < 5)  && (robot->motorLeftSpeedRpmSet  > -5))
//     &&  ((robot->motorRightSpeedRpmSet < 5)  && (robot->motorRightSpeedRpmSet > -5))  ){
//    serialPort->print(F("|nb~Reverse"));
//  } else serialPort->print(F("|ns~Stop"));
//  serialPort->print(F("|nm~Mow is "));
//  sendOnOff(robot->motorMowEnable);  
//  serialPort->println("}");

  if (update) serialPort->print("{:"); else serialPort->println(F("{^Manual navigation`1000"));
  serialPort->print(F("|nl~Left|nr~Right"));
  serialPort->print(F("|nf~Forward"));
  serialPort->print(F("|nb~Reverse"));
  serialPort->print(F("|nm~Mow is "));
  sendOnOff(robot->motorMowEnable);  
  serialPort->print(F("|ns~Stop"));
  serialPort->println("}");  
}

void RemoteControl::processManualMenu(String pfodCmd){
//  if (pfodCmd == "nl"){
//    // manual: left
//    robot->setNextState(STATE_MANUAL, 0);          
//    float sign = 1.0;
//    if (robot->motorLeftSpeedRpmSet < 0) sign = -1.0;      
//    if (sign*robot->motorLeftSpeedRpmSet >= sign*robot->motorRightSpeedRpmSet) robot->motorLeftSpeedRpmSet  = sign * robot->motorSpeedMaxRpm/2;      
//        else robot->motorLeftSpeedRpmSet /= 2; 
//    robot->motorRightSpeedRpmSet = sign * robot->motorSpeedMaxRpm;
//    sendManualMenu(true);
//  } else if (pfodCmd == "nr"){      
//    // manual: right
//    robot->setNextState(STATE_MANUAL, 0);          
//    float sign = 1.0;
//    if (robot->motorRightSpeedRpmSet < 0) sign = -1.0;
//    if (sign*robot->motorRightSpeedRpmSet >= sign*robot->motorLeftSpeedRpmSet) robot->motorRightSpeedRpmSet  = sign* robot->motorSpeedMaxRpm/2;
//        else robot->motorRightSpeedRpmSet /= 2;            
//    robot->motorLeftSpeedRpmSet  = sign * robot->motorSpeedMaxRpm;
//    sendManualMenu(true);
//  } else if (pfodCmd == "nf"){
//    // manual: forward
//    robot->setNextState(STATE_MANUAL, 0);          
//    robot->motorLeftSpeedRpmSet  = robot->motorSpeedMaxRpm;
//    robot->motorRightSpeedRpmSet = robot->motorSpeedMaxRpm;
//    sendManualMenu(true);
//  } else if (pfodCmd == "nb"){
//    // manual: reverse
//    robot->setNextState(STATE_MANUAL, 0);          
//    robot->motorLeftSpeedRpmSet  = -robot->motorSpeedMaxRpm;
//    robot->motorRightSpeedRpmSet = -robot->motorSpeedMaxRpm;
//    sendManualMenu(true);
//  } else if (pfodCmd == "nm"){
//    // manual: mower ON/OFF
//    robot->motorMowEnable = !robot->motorMowEnable;            
//    sendManualMenu(true);
//  } else if (pfodCmd == "ns"){
//    // manual: stop
//    //setNextState(STATE_OFF, 0);          
//    robot->motorLeftSpeedRpmSet  =  robot->motorRightSpeedRpmSet = 0;      
//    sendManualMenu(true);
//  }  
  if (pfodCmd == "nl"){
    // manual: left
    robot->setNextState(STATE_MANUAL, 0);          
    float sign = 1.0;
    if (robot->motorLeftSpeedRpmSet < 0) sign = -1.0;      
    if (sign*robot->motorLeftSpeedRpmSet >= sign*robot->motorRightSpeedRpmSet) robot->motorLeftSpeedRpmSet  = sign * robot->motorSpeedMaxRpm/2;      
        else robot->motorLeftSpeedRpmSet /= 2; 
    robot->motorRightSpeedRpmSet = sign * robot->motorSpeedMaxRpm;
    sendManualMenu(true);
  } else if (pfodCmd == "nr"){      
    // manual: right
    robot->setNextState(STATE_MANUAL, 0);          
    float sign = 1.0;
    if (robot->motorRightSpeedRpmSet < 0) sign = -1.0;
    if (sign*robot->motorRightSpeedRpmSet >= sign*robot->motorLeftSpeedRpmSet) robot->motorRightSpeedRpmSet  = sign* robot->motorSpeedMaxRpm/2;
        else robot->motorRightSpeedRpmSet /= 2;            
    robot->motorLeftSpeedRpmSet  = sign * robot->motorSpeedMaxRpm;
    sendManualMenu(true);
    
  } else if (pfodCmd == "nf"){
    // manual: forward
    robot->setNextState(STATE_MANUAL, 0);
    if (robot->motorLeftSpeedRpmSet == 0 ||
        robot->motorRightSpeedRpmSet == 0) // Mower steht still, vorwärts mit halber Geschwindigkeit
    {
        robot->motorLeftSpeedRpmSet  = robot->motorSpeedMaxRpm/2;
        robot->motorRightSpeedRpmSet = robot->motorSpeedMaxRpm/2;
    }
    else if  (robot->motorLeftSpeedRpmSet == -robot->motorSpeedMaxRpm &&
             robot->motorRightSpeedRpmSet == -robot->motorSpeedMaxRpm )     // Mower fährt mit voller Geschwindigkeit rückwärts, Geschwindigkeit reduzieren
             
    {
        robot->motorLeftSpeedRpmSet  = -(robot->motorSpeedMaxRpm/2);
        robot->motorRightSpeedRpmSet = -(robot->motorSpeedMaxRpm/2);
    }
    else if (robot->motorLeftSpeedRpmSet != robot->motorRightSpeedRpmSet  && // Kurvenfahrt vorwärts
             robot->motorLeftSpeedRpmSet > 0 &&
             robot->motorRightSpeedRpmSet > 0 ) // Kurvenfahrt
             {
                   robot->motorLeftSpeedRpmSet  = robot->motorSpeedMaxRpm/2;
                   robot->motorRightSpeedRpmSet = robot->motorSpeedMaxRpm/2;
             }
             
    else if (robot->motorLeftSpeedRpmSet > 0 ||
             robot->motorLeftSpeedRpmSet > 0)// Mower fährt bereits halbe Geschwindigkeit vorwärts, Geschwindigkeit erhöhen
    {          
        robot->motorLeftSpeedRpmSet  = robot->motorSpeedMaxRpm;
        robot->motorRightSpeedRpmSet = robot->motorSpeedMaxRpm;
    }
    else  // Stop
    {
          robot->motorLeftSpeedRpmSet  =  robot->motorRightSpeedRpmSet = 0;      
    }
    sendManualMenu(true);
    
  } else if (pfodCmd == "nb"){
    // manual: reverse
    robot->setNextState(STATE_MANUAL, 0);          
    if (robot->motorLeftSpeedRpmSet == 0 ||
        robot->motorRightSpeedRpmSet == 0) // Mower steht still, rückwärts mit halber Geschwindigkeit
    {
      robot->motorLeftSpeedRpmSet  = -(robot->motorSpeedMaxRpm/2);
      robot->motorRightSpeedRpmSet = -(robot->motorSpeedMaxRpm/2);
    }
    else if  (robot->motorLeftSpeedRpmSet == robot->motorSpeedMaxRpm &&
              robot->motorRightSpeedRpmSet == robot->motorSpeedMaxRpm )      // Mower fährt mit voller Geschwindigkeit vorwärts, Geschwindigkeit reduzieren              
    {
        robot->motorLeftSpeedRpmSet  = robot->motorSpeedMaxRpm/2;
        robot->motorRightSpeedRpmSet = robot->motorSpeedMaxRpm/2;
    } 
    
    else if (robot->motorLeftSpeedRpmSet != robot->motorRightSpeedRpmSet  && // Kurvenfahrt rückwärts
             robot->motorLeftSpeedRpmSet < 0 &&
             robot->motorRightSpeedRpmSet < 0 ) // Kurvenfahrt
    {
        robot->motorLeftSpeedRpmSet  = -(robot->motorSpeedMaxRpm/2);
        robot->motorRightSpeedRpmSet = -(robot->motorSpeedMaxRpm/2);
    }
    else if (robot->motorLeftSpeedRpmSet < 0 ||
             robot->motorRightSpeedRpmSet < 0) // Mower fährt bereits halbe Geschwindigkeit, Geschindigkeit erhöhen
    {
         robot->motorLeftSpeedRpmSet  = -robot->motorSpeedMaxRpm;
         robot->motorRightSpeedRpmSet = -robot->motorSpeedMaxRpm;
    }
    else  // Stop
    {
          robot->motorLeftSpeedRpmSet  =  robot->motorRightSpeedRpmSet = 0;      
    }  
    sendManualMenu(true);
  
  } else if (pfodCmd == "nm"){
    // manual: mower ON/OFF
    robot->motorMowEnable = !robot->motorMowEnable;            
    sendManualMenu(true);
  } else if (pfodCmd == "ns"){
    // manual: stop
    //setNextState(STATE_OFF, 0);          
    robot->motorLeftSpeedRpmSet  =  robot->motorRightSpeedRpmSet = 0;      
    sendManualMenu(true);
  }  

}

Damit fährt es sich schon ganz gut. Wenn der Mäher im Manuellen Modus an ein Hindernis stößt, bleibt er stehen. Da er aber nicht zurück setzt, bleibt der Bumper aktiviert und man bekommt ihn nur mit viel Geduld (oder einfaches zurückziehen) wieder frei. Als nächstes werde ich mich darum kümmern, dass der Mäher ein Stück zurück setzt, dann aber stehen bleibt (und nicht in eine Richtung weg dreht).