Sonntag, 21. Januar 2018

Motor Treiber für den Rover



Sicherlich hat jemand schon etwas geschrieben, dass die Ansteuern des Motor Shields vereinfacht. Dennoch möchte ich genau die Funktionsmöglichkeiten kennenlernen sowie auch den Schaltplan.

Seit Jahren liegt mein Rover unbenutzt in der Kiste und das möchte ich ändern. Aber damit dieser Betrieben werden kann, wird ein Motor Treiber benötigt. In diesem Fall ist es ein Motor Shield für Arduino. 
  • Arduino UNO / Duemilanove
  • Motor Shield
  • Externe Spannungsversorgung mit dem 9V oder einen zwei Zellen Lipo
  • DAGU Rover 5 Chassis 4WD

Antrieb
Der Rover von DAGU hat vier Motoren die unabhängig voneinander betrieben werden können. Allerdings werden die Gummi Ketten eingesetzt womit die Motoren zur einen Seite immer gleichzeitig laufen müssen.
Leider verfügt der verwendete Arduino nicht Ausreichend Pins für die Interrupt Funktion mit denen sich die vier Encoder vom Rover einlesen ließen. Die Umsetzung für das einlesen der Encoders würde besser mit einem Arduino MKR1000 funktionieren, wenn alle vier Encoder eingelesen werden sollen. Alternativ bei Verwendung mit den Gummi Ketten, reichen zwei Encoders aus und könnte mit einem Arduino Mega eingelesen werden.

Motor Treiber und Motor Shield
Eigentlich existiert für den Rover ein passender Motor Treiber, den ich jedoch nicht finden konnte. Daher kommt ein Motor Shield zum Einsatz, der genau alle Motoren Ansteuern kann. Für die Externe Spannungsversorgung wird ein zwei Zellen Lipo Akku verwendet. Auf dem Shield sollte der Jumper für PWR nicht gesteckt sein, solange der Arduino am USB mit dem PC Verbunden ist.
Die Anschlüsse für den Betrieb der zwei Servos werden aktuell für dieses Beispiel nicht verwendet. Somit bleiben Pin 9 und 10 offen.

Steuerung des Motor Shields
Für die Ansteuerung der Ausgänge M1, M2, M3 und M4 auf dem Motor Shield, werden insgesamt acht Pins benötigt. Zwei mehr, wenn man die Servo Ausgänge mit zählt, die jedoch nur weitergeleitete Pins sind.
Der Ausgang M1 besteht aus zwei Ausgängen die in diesem Beispiel immer mit M1_A und M1_B Bezeichnet werden. Daraus schließt sich, dass insgesamt acht Ausgänge geschaltet werden. Alle Ausgänge können jedoch mit einem PWM reguliert werden, aber es stehen nur vier zu Verfügung. Daher steht z.B. für M1 ein PWM Ausgang zur Verfügung. Aber rechnet man dies wieder hoch, kommen wir auf zwölf benötigte Pins.
Auf dem Shield wird ein 74HC595 Shiftregister verwendet, der selbst acht schaltbare Ausgänge hat. Dieser wird vom Arduino mit vier Pins beschaltet. Grundsätzlich reichen drei Pins, um einen Shiftregister anzusteuern. Der Vierte jedoch ermöglicht das explizite Abschalten aller Ausgänge.


Programmcode
Im folgenden Code Beispiel sind die wesentlichen Methoden aufgeführt. Geschaltet werden die Ausgänge M3 und M4 und maximalen PWM Signal Ausgang. Den gesamten Programmcode mit Kommentaren findet ihr wieder auf dem Github Repository.

 #define PIN_595_LATCH 12       // Pin connected to ST_CP of 74HC595  
 #define PIN_595_CLOCK 4        // Pin connected to SH_CP of 74HC595  
 #define PIN_595_DATA 8        // Pin connected to DS of 74HC595  
 #define PIN_595_SHIFT_REG_EN 7    // enable the Shiftregister  
 #define PIN_OUTPUT_M1 11       // pwm pin to control M1 output  
 #define PIN_OUTPUT_M2 3        // pwm pin to control M2 output  
 #define PIN_OUTPUT_M3 6        // pwm pin to control M3 output  
 #define PIN_OUTPUT_M4 5        // pwm pin to control M4 output  
 void setup() {  
  MotorShieldInitialize();  
 }  
 void loop() {  
  int motorsOn = 33; // schaltet M3 A und M4 A ein  
  int speedValue = 255; // Der Wert kann von 0 bis 255 gesetzt werden  
  SetRunMotors(motorsOn, speedValue, speedValue);  
  digitalWrite(PIN_595_SHIFT_REG_EN, LOW);  
  delay(2000);  
  digitalWrite(PIN_595_SHIFT_REG_EN, HIGH);  
  delay(1000);  
 }  
 void MotorShieldInitialize() {  
  pinMode(PIN_OUTPUT_M1, OUTPUT);  
  pinMode(PIN_OUTPUT_M2, OUTPUT);  
  pinMode(PIN_OUTPUT_M3, OUTPUT);  
  pinMode(PIN_OUTPUT_M4, OUTPUT);  
  pinMode(PIN_595_LATCH, OUTPUT);  
  pinMode(PIN_595_CLOCK, OUTPUT);  
  pinMode(PIN_595_DATA, OUTPUT);  
  pinMode(PIN_595_SHIFT_REG_EN, OUTPUT);  
  digitalWrite(PIN_595_LATCH, LOW);  
  digitalWrite(PIN_595_CLOCK, LOW);  
  digitalWrite(PIN_595_DATA, LOW);  
  digitalWrite(PIN_595_SHIFT_REG_EN, LOW);  
 }  
 void SetRunMotors(int motorsOn, int speedValueLeft, int speedValueRight) {  
  SetOutputValue(speedValueLeft, speedValueRight);  
  digitalWrite(PIN_595_LATCH, LOW);  
  shiftOut(PIN_595_DATA, PIN_595_CLOCK, MSBFIRST, motorsOn); //GetShiftValue(m));  
  digitalWrite(PIN_595_LATCH, HIGH);  
 }  
 void SetOutputValue(int speedValueLeft, int speedValueRight) {  
  analogWrite(PIN_OUTPUT_M1, speedValueRight); // right  
  analogWrite(PIN_OUTPUT_M2, speedValueRight);  
  analogWrite(PIN_OUTPUT_M3, speedValueLeft); // left  
  analogWrite(PIN_OUTPUT_M4, speedValueLeft);  
 }  

Steuerung
Das Beispiel stellt wieder eine Grundlage für weiteres. Der Spaß geht natürlich am besten weiter, wenn zur Steuerung des Rovers Sensoren eingesetzt werden oder über Funk die Steuerbefehle übermittelt werden.

Das selbe in .NET
Ein Codebeispiel mit C# und .NET Micro Framework beschreibe ich im Post "Motor Treiber für den Rover (.NETMF)"



Mittwoch, 17. Januar 2018

Zeichnen auf dem TFT mit dem XBox Controller

 
Im ersten Beispiel wurde beschrieben, wie man die Daten von einem Xbox Controller zu dem Arduino sendet und dabei einen Servo ansteuerte. Nachteil an der Code Konstellation war, dass nur ein Byte Wert übermittelt wurde und auch sehr instabil lief. Mit ein paar Anpassungen lässt sich dies einfach beheben. (siehe: Servo mit dem Xbox Controller steuern)

Hinweis
Das folgende Beispiel ist vom Aufbau relativ simple gehalten, so dass bei der Ausgabe Kompromisse eingegangen werden, wie z.B. die Daten Qualität über die Serielle Schnittstelle.

Mehr Daten Senden
Das MonoGame Projekt muss nur in der Update Methode angepasst werden. Zum einen wird geprüft, ob noch Bytes geschrieben werden. Dann können die Eingabewerte vom Xbox Controller eingelesen werden und über die Serielle Verbindung versendet werden.

 protected override void Update(GameTime gameTime)  
 {  
   GamePadState state = GamePad.GetState(PlayerIndex.One);  
   if (state.Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))  
   {  
     this.Exit();  
   }  
   if (this._serialPort.BytesToWrite == 0)  
   {  
     byte stickValueX = (byte)((state.ThumbSticks.Left.X + 1) * 90);  
     byte stickValueY = (byte)((state.ThumbSticks.Left.Y + 1) * 90);  
     byte buttonValuePaint = (byte)(state.Buttons.A == ButtonState.Pressed ? 10 : 0);  
     byte buttonValueReset = (byte)(state.Buttons.B == ButtonState.Pressed ? 10 : 0);  
     this._serialPort.Write(new byte[] { stickValueX, stickValueY, buttonValuePaint, buttonValueReset }, 0, 4);  
     this._serialPort.WriteLine(string.Empty);  
   }  
   Task.Delay(5);  
   base.Update(gameTime);  
 }  

Mehr Daten Empfangen
Die Lösung ist simple. Um mehrere Bytes einzulesen, müssen diese über einen Schleifen Vorgang vom Serial gelesen werden. Die Byte Werte werden dann zunächst in eine lokales Byte Array zugewiesen. Anschließend kann noch geprüft werden ob alle Bytes gelesen wurden. Die ersten zwei Werte sollten zumindest da sein, ansonsten kann der zu zeichnende Punkt (eigentlich ein Kreuz) nicht bewegt werden.

 bool ReadReceivedBytes() {  
  byte received[4];  
  int index = 0;  
  while(Serial.available() > 0) {  
   if(index < 5) {  
    received[index] = Serial.read();  
   }  
   index++;  
  }  
  if(index < 4) {  
   return false;  
  }  
  mReceivedStickX = received[0];  
  mReceivedStickY = received[1];  
  mReceivedButtonA = received[2];  
  mReceivedButtonB = received[3];  
  return true;  
 }  

Ausgabe und Fehler
Die Ausgabe erfolgt diesmal nicht an einem Servo, sondern an einem TFT Display mit einer Auflösung von 160x128 Pixeln, der auch für den Arduino Esplora ebenfalls verwendet wird.
Die Übertragung ist nicht immer Fehlerfrei, womit für genauere Ergebnisse eine Fehlerbehandlung notwendig wird. Aber das wird in einem anderen Blog Post beschrieben. :)



Claude für die Entiwcklung mit dem Arduino UNO Q verwenden

Ich habe vom ehemaligen Kollegen einen 7 Tage Gutscheint für Claude Pro erhalten und kann jetzt meine Neugier mit der Agenten Schnittstelle ...