Sheep Sheep

Slatkow11,
bei mir hat das funktioniert.
Bisher läuft die Version ca. 3 Stunden bestens.

@Chris,
tolle Optimierung der Software.
Ich habe jetzt auch mein Perimeterempfänger weiter nach vorne gelegt. Dadurch konnte ich mit dem smag-Wert weiter nach unten gehen und der Mäher verliert so nicht mehr das Schleifensignal. Ach das Abfahrten der Schleife läuft jetzt wesentlich besser.
Was bedeutet denn unter Settings Batterie Temperaturdes Akkus?
Hast du da noch ein TemperaturSensor angeschlossen?
 
Besten Dank,

mega diese Software. Nur die max Forward Time muss ich noch hochsetzen, er bricht sonst die Spiralen immer nach 80 Sekunden ab. Eventuell wär die Verlagerung in eine neue Mow-Pattern auch keine schlecht Idee?
Hat irgendwer in dieser Version die Messermodulation schon zum laufen bekommen? In der 1.6er gings ohne Probleme nur in der 1.7er mit einem Mega geht gar nix mehr. Naja morgen sollte mein DUE eintrudeln, vielleicht passt es da.

Aber nochmals vielen Dank für die tolle Umsetzung.

Gruß Volker
 
@Stefan: ja ich habe ein LM35 Temperatursensor im Akku verbaut. Braucht nur 5V und gibt am Ausgang die Temperatur in 10mV/°C aus. Kostet auch weniger als 1 Euro...
Ich denke alle Litium Akkus sollten einen Temperaturensor verwenden. Die meisten kommerziellen Geräte haben einen verbaut und schalten die Ladung aus oder gar nicht ein, wenn die Akkutemperatur zu hoch ist. (Ist im SheepSheep code allerdings noch nicht drinn)
Man sieht, wenn es den Zellen nicht mehr gut geht. Mit meinem 1sten Akku hatte ich vor der UnderVoltage protection mal eine Tiefentladung (kleiner 3V fürs ganze Akkupack). Der Akku hat danach noch ein halbes Jahr gehalten ,danach war eine der Zellen tot. Geäussert hat sich das u.a. in einem massiven Temperaturanstieg beim Laden.
Danach habe ich ein BMS ( von Ebay ) und die Undervoltage protection installiert. Und habe beides beim testen auch schon benötigt.
Ich wollte nicht, dass SheepSheep irgendwann ausbrennt, nur wegen des Akkus.

@Slatkow11: den Odo-test habe ich noch nicht getestet. SheepSheep fährt gerade aus...

@ Volker: Messermodulation habe ich auch nicht installiert. Da braucht es glaub einen Magneten und Hallsensor. Ist bei mir (noch) nicht installiert. Der Code hat sich viel verändert seit 1.06a und da tut sich im Moment auch weiterhin viel. Ich habe allerdings da auch nicht den vollen Überblick.

Gruess

Chris
 
Holoratte schrieb:
@Stefan: ja ich habe ein LM35 Temperatursensor im Akku verbaut. Braucht nur 5V und gibt am Ausgang die Temperatur in 10mV/°C aus. Kostet auch weniger als 1 Euro...
Ich denke alle Litium Akkus sollten einen Temperaturensor verwenden.

Gruess

Chris

Gute Idee!

Hi zusammen,
Ich habe gestern und heute Abend auch den Genuss der Spiralfahrten genossen. Allerdings habe ich den Motorstrom in der Öffentlichkeit Abfrage durch den Userswitch2 ersetzt. Bei Interesse kann ich das gerne mal posten.
Mir ist allerdings aufgefallen, dass alle Userswitche kurz bei Manuellen Eingaben einschalten.
Bin mir nicht sicher, ob das durch meine Änderungen im Code passiert... Kann das jmd bitte verifizieren?
(Background: Habe einen Lüfter für die Motortreiber auf Userswitch1, welcher bei Robo::Setup kurz auf High und danach wieder auf Low geschaltet wird, quasi als Funktionstest.)
Mein Mähmotor ist auch etwas eigenwillig, v.a. wenn ich im Manual Mode unterwegs bin. Bei jedem Fahrtrichtungbefehl wird Mow auf on gesetzt. Wäre nett, wenn jemand dieses Verhalten bei seinem Mower mit dem Clone von Sonntag prüfen könnte.
Spiralfahrten haben 1A funktioniert, musste aber beim Intervall (erinnere mich gerade nicht 100%ig?) Relativ hoch gehen, da ich relativ kleine Räder verwende und meine Motoren etwas wenig Drehmoment liefern. Einer knirscht auch schon etwas.
Es handelt sich aber nicht um die Kit-Motoren.
Wäre eine höhere Belastung denkbar?
Ich bin auf jeden Fall sehr begeistert von deiner Schöpfung ?

Hat eigentlich schon jemand versucht, die Sw für den stm32f103 zu portieren?

Grüße, Stephan

@markus... Ich erhalte immer wieder
Fehler
Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation '='.
wenn ich per Android antworten will...Per zitieren gings dann irgendwann mal...
 
Zuletzt bearbeitet von einem Moderator:
@Volker: Messermodulation wird wohl auch mit dem Due nicht funktionieren.
In der Interruptroutine wird nur noch Odo ausgewertet. im mower.cpp:

Code:
/ odometry signal change interrupt
// mower motor speed sensor interrupt
// NOTE: when choosing a higher perimeter sample rate (38 kHz) and using odometry interrupts, 
// the Arduino Mega cannot handle all ADC interrupts anymore - the result will be a 'noisy'
// perimeter filter output (mag value) which disappears when disabling odometry interrupts.
// SOLUTION: allow odometry interrupt handler nesting (see odometry interrupt function)
// [URL]http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html[/URL] #ifdef __AVR__

  volatile byte oldOdoPins = 0;
  //ISR(PCINT2_vect, ISR_NOBLOCK)
  ISR(PCINT2_vect)
  {
    const byte actPins = PINK;                				// read register PINK
    const byte setPins = (oldOdoPins ^ actPins);
    if (setPins & 0b00010000)                 				// pin left has changed 
    {
      if (robot.motorLeftPWMCurr >= 0)						// forward
        robot.odometryLeft++;
      else
        robot.odometryLeft--;									// backward
    }


    if (setPins & 0b01000000)                  				// pin right has changed
    {
      if (robot.motorRightPWMCurr >= 0)
        robot.odometryRight++;								// forward
      else
        robot.odometryRight--;								// backward
    }  
    oldOdoPins = actPins;
  }

#else

  volatile long oldOdoPins_A = 0;
  volatile long oldOdoPins_B = 0;
  ISR(PCINT2_vect)
  {
    const long actPins_A = REG_PIOA_PDSR;       			// read PIO A
    const long actPins_B = REG_PIOB_PDSR;                               // read PIO B
    const long setPins_A = (oldOdoPins_A ^ actPins_A);
    const long setPins_B = (oldOdoPins_B ^ actPins_B);
    
    //Right
    if (setPins_A & 0b00000000000000000000000000000010)			// pin left has changed 
    {
      if (robot.motorRightPWMCurr >= 0)					// forward
        robot.odometryRight++;
      else
        robot.odometryRight--;	
        								// backward
      oldOdoPins_A = actPins_A;
    }

    //Left
    if (setPins_B & 0b00000000000000001000000000000000)         	// pin right has changed
    {
      if (robot.motorLeftPWMCurr >= 0)
        robot.odometryLeft++;						// forward
      else
        robot.odometryLeft--;						// backward

      oldOdoPins_B = actPins_B;
    }  
  }





#endif

// mower motor speed sensor interrupt
//void rpm_interrupt(){
//}

vielleicht müsste man aber anderswo suchen.... wie gesagt, hat sich viel verändert...

Gruess
Chris
 
Hallo Chris,
danke für die Info zur Temperaturmessung des Akkus. An welchem Pin ist der angeschlossen?
Ich nutze zwar noch Bleiakkus aber für die Zukunft ist das bestimmt super.
Hier noch ein kurzes Video vom Abfahren der Schleife aktueller Stand deiner Softwareversion und meiner nach vorne gelegten Empfänderspule.
[video width=425 height=344 type=youtube]CBgGMrMwewU[/video]

Gruß Stephan
 
Hallo Stephan,


das ist der pinVoltageMeasurement. Ist hier definiert:mower.cpp

Code:
case SEN_BAT_VOLTAGE: return ADCMan.read(pinBatteryVoltage); break;
    case SEN_CHG_VOLTAGE: return ADCMan.read(pinChargeVoltage); break;
    case SEN_BAT_TEMPERATURE: return ADCMan.read(pinVoltageMeasurement); break;
    //case SEN_CHG_VOLTAGE: return((int)(((double)analogRead(pinChargeVoltage)) * batFactor)); break;
    case SEN_CHG_CURRENT: return ADCMan.read(pinChargeCurrent); break;


Ich schalte den UserSwitch1 bei jedem BEEP in der robot.cpp. Ist für meine LEDs...


Code:
void Robot::beep(int numberOfBeeps, boolean shortbeep = false){
  for (int i=0; i < numberOfBeeps; i++){
    setActuator(ACT_BUZZER, 4200); 
    setActuator(ACT_USER_SW1, 1); 

    if (shortbeep) delay(50);
      else delay(500);
    setActuator(ACT_BUZZER, 0);
    setActuator(ACT_USER_SW1, 0); 
    if (shortbeep) delay(250);
      else delay(500);
  }
}


Im manuellen Modus kann ich das Messer auch nicht dauerhaft ausschalten

Gruess

Chris
 
Odomessung geht jetzt.Ich hatte vergessen diese Einzuschlaten ;)

Messermodulation beim mega ist ein Problem, da in der
Original Software der selbe Interrupt für die Odomatrie und der Messer Drehzahl verwendet wurde.

Bei Due könnte man dafür einen anderen Interrupt wählen oder das auf einen Nano auslagern.

Die abarbeitung des Interrupts dürfte recht einfach sein, da ja der Pin nicht gelesen werden muss. Wenn der Interrupt auslöst zählt man einfach oder berechnet anhand der zeit die Drehzahl.


Die Idee mit der Temperaturmessung ist echt klasse, werde ich auch einbauen.
Aber erst mal will ich ans 1,3 Board setzen.
 
So Neuigkeiten zur Messermodulation. (Hallsensor und Magnet sind bei mir ja bereits verbaut)

Es funktioniert jetzt mit dem Mega, die passenden Register für den DUE konnte ich auf die Schnelle nix finden. Da ist sicher wer schaluer als ich, also ran!

Folgende Änderung in der mower.cpp ist nötig:

volatile byte oldOdoPins = 0;
//ISR(PCINT2_vect, ISR_NOBLOCK)
ISR(PCINT2_vect)
{
const byte actPins = PINK; // read register PINK
const byte setPins = (oldOdoPins ^ actPins);

if (0b00001000) // MowModulate
{

robot.motorMowRpmCounter++;


}

if (setPins & 0b00010000) // pin left has changed
{
if (robot.motorLeftPWMCurr >= 0) // forward
robot.odometryLeft++;
else
robot.odometryLeft--; // backward
}


if (setPins & 0b01000000) // pin right has changed
{
if (robot.motorRightPWMCurr >= 0)
robot.odometryRight++; // forward
else
robot.odometryRight--; // backward
}
oldOdoPins = actPins;
}

#else

Es werden aber die doppelte Anzahl Impulse gezählt, also wird in der robot.cpp etwas getrickst:

if ((millis() - lastMotorMowRpmTime) >= 500){
motorMowRpmCurr = readSensor(SEN_MOTOR_MOW_RPM);
if ((motorMowRpmCurr == 0) && (motorMowRpmCounter != 0)){
// rpm may be updated via interrupt
motorMowRpmCurr = (int) ((((double)motorMowRpmCounter) / ((double)(millis() - lastMotorMowRpmTime))) * 30000.0); // Statt 60000
motorMowRpmCounter = 0;

Probleme mit der Odometrie konnte ich nicht feststellen, welche ich aber momentan nicht benutze da mein Rotenbach-Umbau dabei rumeiert wie ein besoffener Seemann.

So, jetzt aber ab in den Keller. Er hat mal wieder einen Bumperschalter gekillt, die halten unseren Garten nicht lange aus. Da stehen eine Schaukel und ein riesen Trampolin also insgesamt 18 Hindernisse. Heavy. Werde versuchen alles auf kontaktlose Reedschalter umzubauen.

Gruß
Volker


P.S. Projektvorstellung inklusive Videos folgt demnächst.
 
SheepSheep hat die Perimeterbegrenzung 2mal eigenständig verlassen. Jeweils nachdem die Spirale beendet war ( motorForwTimeMax ). Rückwärts aus dem Perimeter raus , gedreht und dann noch bis zum Perimetertimeout vorwärts. Das Blumenbeet häts fast erwischt.....Glück gehabt. :unsure:

Änderung des Verhaltens bei motorForwTimeMax: geht direkt in die Drehung. ohne Rückwärts zu fahren :

Code:
void Robot::checkTimeout(){
  if (stateTime > motorForwTimeMax){ 
    // timeout 
    motorMowSenseErrorCounter = 0;
    if (rollDir == RIGHT) setNextState(STATE_ROLL, LEFT); // toggle roll dir
      else setNextState(STATE_ROLL, RIGHT);
  }
}


Mit dieser Änderung gabs dann Stand 14.6.2017 ein Pre-Release .
 
Bei uns sind die Blumenbeete auch nur durch den Perimeterdraht vom Rasen getrennt und meiner ist schon mehrfach im Beet gelandet. Das lag aber an STATE_PERI_OUT_FORW. Wenn der Adrumower bei STATE_ROLL zufällig mal außerhalb des Perimeterdrahts dreht, dann fährt er im original Azurit seltsamerweise nach vorn. Ich habe bei mir STATE_PERI_OUT_FORW durch STATE_PERI_OUT_REV ersetzt https://github.com/ainagtur/ardumower/commit/f8c28c1db2c1350744b7f0c1b2cac2a7408f11bf
wobei es noch mehr Sinn machen würde eine da gleich die Gegendrehung zu machen:


Code:
else if ((stateCurr == STATE_ROLL)) {
      if (perimeterTriggerTime != 0) {
        if (millis() >= perimeterTriggerTime){ 
          perimeterTriggerTime = 0;
          if (rotateLeft){    
          setNextState(STATE_PERI_OUT_ROLL, RIGHT);
          } else {
          setNextState(STATE_PERI_OUT_ROLL, LEFT);
          }  
        }
      }
    }


Ich schalte auch den Mähmotor aus wenn der Perimeter durchquert wurde und schalte diesen erst wieder ein wenn der Ardumower wieder innerhalb der Schleife ist. Sollte er doch wieder ins Blumenbeet geraten, dann hält sich der Schaden noch in Grenzen ...

https://github.com/ainagtur/ardumower/tree/PerimeterAsBoundryModifications
 
Hallo gimate,
ich habe STATE_PERI_OUT_FORW durch STATE_PERI_OUT_ROLL ersetzt und das scheint 1A zu funktionieren. Danke für den Hinweis. Das war ein grosser Teil des Problems.

Ferner hab ich noch den STATE_BUMPER_STUCK ergänzt durch eine Wartezeit. Der Error wird jetzt erst nach 60s ausgelöst.

Code:
case STATE_BUMPER_STUCK:
      if (bumperStuckTime == 0){
        bumperStuckTime = millis();
        Debug.println("Bumper is stuck");
      } 
      if ((millis() - bumperStuckTime)>= 60000){      //ERROR after 1 min bumperStuck
        Debug.println("error: bumper is stuck more than 1min");
        addErrorCounter(ERR_STUCK);
        setNextState(STATE_ERROR,0);
      }else if ((!bumperLeft) && (!bumperRight)){
        Debug.println("STATE_BUMPER_STUCK: Bumper is free again");
        setNextState(STATE_ROLL,rollDir);
        bumperStuckTime = 0;
      }

und das Messer sollte jetzt im Manuellen Modus auch ausgeschaltet bleiben, wenn man dies wünscht. Dazu muss man nur ein "if (!motorMowEnableOverride)" in checkCurrent() einfügen, sonst schaltet das Messer bei jedem loop-Durchlauf wieder ein :

Code:
else{ 
      errorCounterMax[ERR_MOW_SENSE] = 0;
      motorMowSenseCounter = 0;
      if (millis() >= lastTimeMotorMowStuck + 30000){ // wait 30 seconds before switching on again
        errorCounter[ERR_MOW_SENSE] = 0;
        if (!motorMowEnableOverride) motorMowEnable = true; //mowMotor should not start if mow is off
      }
  }

Letzteres ist noch nicht getestet, aber sollte funktionieren.
Ist schon auf Github im SheepSheep Branch...

Gruess

Chris
 
Sheep Sheep die Ausserirdische...

WP_20170915_0071.jpg

WP_20170915_0031.jpg

WP_20170915_0021.jpg

WP_20170915_0091.jpg

Attachment: https://forum.ardumower.de/data/media/kunena/attachments/2380/WP_20170915_0071.jpg/
 
Zuletzt bearbeitet von einem Moderator:
Hallo Chris,

deine Software funktioniert jetzt noch besser. DANKE Bleibt fü mich die beste Software für den Mower.

Die Idee von gimate, zwei spiralen zu fahren ist gar nicht schlecht, um die "Grass Inseln" zu mähen, man könnte aber auch einfach bei dem Inneren Rad, mit einem Negativen Wert anfangen, um diese zu Mähen.

Leider habe ich keine Ahnung wie das Umgesetzt werden könnte.

Slatkow
 
Hallo Slatkow,

Danke für den Rasen (ähm die Blumen, obwohl die Blumen haben nicht viel Chancen).
WARNUNG der SheepSheep- branch ist NICHT PCB1.3 tauglich! Da fehlen noch anpassungen.
Die Software-Driverprotektion ist noch grösstenteils aktiv. Das macht die Stops nicht ganz so hart (ausser wenn dies gewollt ist z.B bei Bumperkontakt. Beim Übergang zur Spirale bin ich nicht sicher.).

Wenn Du einen Divisor in der Spiralberechnung negativ machst müsste das Schaf dann eigenlich mit einem Rad rückwärts drehen:
UNGETESTET die ersten 5s (5000 mS) mit dem langsamen Rad rückwärts:
in robot .c

Code:
if (lastSetSpiralStartTime >= stateStartTime + motorSpiralStartTimeMin) {
		  if (rollDir == RIGHT){
		 motorRightSpeedRpmSet = motorSpeedMaxRpm*(1.0/(1.0+(float)motorSpiralFactor/(float)(millis()-lastSetSpiralStartTime -5000)));
		  }
		  else{motorLeftSpeedRpmSet = motorSpeedMaxRpm*(1.0/(1.0+(float)motorSpiralFactor/(float)(millis()-lastSetSpiralStartTime-5000)));
		  }


Gruess

Chris
 
Hallo Chris,

ich verwende hier auch noch das 1,2 Board.

Mit deiner Änderung habe ich es leider nicht hinbekommen.

Ich habe dann folgendes versucht :


Code:
if (lastSetSpiralStartTime >= stateStartTime + motorSpiralStartTimeMin) {
                  if (rr > 0) rr = rr-1
		  if (rollDir == RIGHT){
		 motorRightSpeedRpmSet = (motorSpeedMaxRpm*(1.0/(1.0+(float)motorSpiralFactor/(float)(millis()-lastSetSpiralStartTime)))- rr);
		  }
		  else{motorLeftSpeedRpmSet = (motorSpeedMaxRpm*(1.0/(1.0+(float)motorSpiralFactor/(float)(millis()-lastSetSpiralStartTime-5000)))-rr);


rr habe ich beim Auslösen der Schleife auf motorSpeedMaxRpm gesetzt.

Bringt aber auch nichts, da dieser Wert ja immer wieder ausgelöst wird und dann rr jedes mal wieder auf motorSpeedMaxRpm gesetzt wird.


Code:
if (lastSetSpiralStartTime >= stateStartTime + motorSpiralStartTimeMin) {
                  if (  millis() >=  motorSpiralStartTimeMin + 5000) rr = motorSpeedMaxRpm;
                      else rr = 0;
		  if (rollDir == RIGHT){
		 motorRightSpeedRpmSet = (motorSpeedMaxRpm*(1.0/(1.0+(float)motorSpiralFactor/(float)(millis()-lastSetSpiralStartTime)))- rr);
		  }
		  else{motorLeftSpeedRpmSet = (motorSpeedMaxRpm*(1.0/(1.0+(float)motorSpiralFactor/(float)(millis()-lastSetSpiralStartTime-5000)))-rr);


So werde ich es nochmal Probieren. Mal sehen ob es geht. Wenn es klappt sollte das innere Rad 5s lang Rückwärts laufen

Gruss Slatkow
 
So

ich habs hinbekommen. Damit wird die Insel in der Mitte auch gemäht :
Er fängt an die Spirale zu fahren, dreht sich 4 Sekunden im Kreis und fährt dann die Spirale weiter


Code:
if (stateTime > 4000) ratio = motorBiDirSpeedRatio2;
        if (rollDir == RIGHT) motorRightSpeedRpmSet = ((double)motorLeftSpeedRpmSet) * ratio;
          else motorLeftSpeedRpmSet = ((double)motorRightSpeedRpmSet) * ratio;                            
      }             
	   if (lastSetSpiralStartTime >= stateStartTime + motorSpiralStartTimeMin) {
                  if (millis() <  lastSetSpiralStartTime + 4000) rr = motorSpeedMaxRpm;
                      else rr = 0;
		  if (rollDir == RIGHT){
		 motorRightSpeedRpmSet = (motorSpeedMaxRpm*(1.0/(1.0+(float)motorSpiralFactor/(float)(millis()-lastSetSpiralStartTime)))- rr);
		  }
		  else{motorLeftSpeedRpmSet = (motorSpeedMaxRpm*(1.0/(1.0+(float)motorSpiralFactor/(float)(millis()-lastSetSpiralStartTime)))-rr);	  }
	  }


Vielleicht kannst ja jemand gebrauchen

Slatkow
 
Hallo Zusammen,

Sheep Sheep hat nach 3 Jahren Dienst einen Stall bekommen: diese Gargage . Das Dach ist hoch genug, dass ein Ardumower auch durchfahren kann.
WP_20180413_0071.jpg

Die Stromabnehmer kommen vom 3d Drucker. Die Gelenke sind kugelgelagert. Kontakt macht ein 10x2mm Messing-Flachprofil auf gebogene Hartkupfer-Rohre. Inspiriert durch diesen Thread von Jens aus Friedland .
Gehalten werden die Stromabnehmer von einem 30er Aluprofil. (nicht bei der Garage dabei).
Bei Bedarf kann ich die Freecad files vom Stromabnehmer auf Github laden.
WP_20180413_0091.jpg

WP_20180413_0051.jpg


Gruess

Chris
Attachment: https://forum.ardumower.de/data/media/kunena/attachments/2380/WP_20180413_0071.jpg/
 
Zuletzt bearbeitet von einem Moderator:
Hallo Chris,

das sieht ja super aus. Wo hast du denn die Ladekontakte der Station hat?
Gibt es sowas irgendwo zu kaufen oder ist das alles 3D Druck?
Die Idee finde ich auf jeden Fall gut.:)

Gruß
Roland
 
Hallo Roland,

ich habe nach sowas zu kaufen gesucht (zum Beispiel bei Modelleisenbahnen), aber nichts in den gewünschten Dimensionen gefunden.
Deshalb sind diese Teile in ASA-Filament gedruckt:
screenshot.JPG

Die Kugellager sind nur eingepresst.
Kontakt macht handelsübliches Messingflachprofil , am Rand etwas hochgebogen.

Gruess

Chris
Attachment: https://forum.ardumower.de/data/media/kunena/attachments/2380/screenshot.JPG/
 
Zuletzt bearbeitet von einem Moderator:
Oben