Forum: Mikrocontroller und Digitale Elektronik Roboterarm mit Gestensteuerung HILFE I2C


von Mäggy (Gast)


Angehängte Dateien:

Lesenswert?

Hallo :)

Ich bin in der 4.und letzten Klasse in der Berufsschule. Jeder muss ein 
Abschlussprojekt machen. Eigentlich wollte ich eher ein hardwarelastiges 
Projekt machen, da meine Programmierkenntnisse nicht so groß sind. Aber 
dann habe ich doch von meinem Chef ein Projekt zugeteilt bekommen... :/ 
Es fällt mir wirklich schwer etwas zu programmieren, und ich hoffe ihr 
nehmt es mir nicht all zu übel wenn ich dumme Fragen stelle..

Mein Projekt kurz zusammengefasst:

Ich habe einen Roboterarm (von Arexx-Robot-Arm V3 
http://www.arexx.com/robot_arm/html/de/software.htm ), welcher mit einem 
3D Pad von Ootsidebox 
(http://3dpadbyootsidebox.blogspot.fr/2014/09/3dpad-getting-started-guide.html) 
gesteuert werden soll.
Das 3D Pad ist ein Arduino Shield (Arduino Uno) und deshalb muss ich das 
Arduino Uno Board verwenden!
Das Problem ist nun, dass das 3D Pad fast alle Pins vom Arduino Uno 
verwendet, und deshalb kann ich die 6 Servos vom Roboterarm nicht am 
Arduino direkt anschließen.
Der Roboterarm hatte eine fertige Elektonik (Atmega64A-au), aber die ist 
mir abgeraucht.. Ich habe keine Zeit mehr um diese Leiterplatte zu 
reparieren, und außerdem hat es nie wirklich funktioniert..
Deshalb habe ich mir ein Adafruit Servo Shield gekauft um meine 6 Servos 
anzusteuern. 
https://learn.adafruit.com/adafruit-16-channel-pwm-slash-servo-shield?view=all

Dieses Shield funktioniert über die I2C Schnittstelle vom Arduino, mehr 
brauch ich nicht. Also perfekt, da ich quasi nur diese Pins frei habe..
Mit diesem Shield hab ich es jetzt immerhin geschafft die 6 Servos des 
Roboterarmes anzusteuern.
Da der Code vom 3D Pad ziemlich groß ist, und fast den ganzen Speicher 
vom Arduino Uno verwendet, habe ich mir gedacht dass das 3D Pad (Arduino 
1) der Master ist, und das Servoshield (Arduino 2) der Slave.

Jetzt sollte ich die Daten vom 3D Pad, zur Arduino I2C Schnittstelle 
bekommen, damit ich diese weiter zum ServoShield schicken kann.

Ich habe schon viel ausprobiert, aber leider hat nichts bis jetzt 
funktioniert. Ich hoffe ihr könnt mir helfen.
Vielleicht weiß ja jemand von euch ein Master/Slave Code um die Gesten 
1:1 weiter zu leiten. :)
Das wäre der Link zur Lib. vom 3D Pad. Es sind zu viele Dateien, um sie 
im Anhang einzufügen. https://github.com/OotSideBox/3DpadArduinoSketch

Im Anhang befindet sich der Servocode und der Beispielcode vom 3D Pad.


Vielen Dank im Vorraus, und es tut mir leid falls ich euch zu wenig 
Infos gegeben habe - ist mein erster Beitrag in einem Forum.


Liebe Grüße Mäggy :D

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Es gibt bei
http://www.arduino.cc
eine I2C Master/Slave Library, die du für deine Zwecke umschnurzeln 
könntest:
https://www.arduino.cc/en/Reference/Wire

Dabei sind anscheinend auch Beispiele zur Master/Slave Kommunikation.

von Michael O. (Gast)


Angehängte Dateien:

Lesenswert?

Danke für die Antwort :)

Ich hab es mit den Beispielcodes schon versucht. (im Anhang wären die 
Codes Master/Slave)
Hab einiges ausprobiert, hat aber leider nicht geklappt.
Im Terminal vom Slave zeigt es mir auch keine Daten vom Master , welche 
gesendet werden sollten, an.
Ich denke das Problem ist, dass die Gesten, welche zur SPI Schnittstelle 
gesendet werden, nicht von der I2C Schnittstelle gelesen werden können. 
Und deshalb sendet es nichts. Aber ist nur eine Vermutung..
Hab auch nichts gefunden ob und wie man SPI Daten ausliest, und zum I2C 
weiterleitet.


Liebe Grüße

von void (Gast)


Lesenswert?

Matthias S. schrieb:
  > Dabei sind anscheinend auch Beispiele zur
  > Master/Slave Kommunikation.

Maria du solltest dich an das Beispiel welches Matthias erwähnt halten.
Probiere zunächst erstmal den Beispielcode aus ohne ihn zu verändern.
Dann weißt du auch gleich, ob die Hardware funktioniert.
https://www.arduino.cc/en/Tutorial/MasterWriter


  Maria K. schrieb:
  > Ich hab es mit den Beispielcodes schon versucht.
  > (im Anhang wären die Codes Master/Slave)

Auszug aus deinem Code.
1
Wire.beginTransmission(0x41); // transmit to device #8
2
SPIsendForDac(VCOMAX); //signal indiquant arrete regulation
3
for(BoucleScrut=0; BoucleScrut<NODE;BoucleScrut++)   //boucle de scrutation

Deine Fremdsprachenkenntnisse sind zwar verblüffend, leider funktioniert 
es aber selten wenn man Code aus mehreren Quellen zusammenkopiert (ohne 
ihn vorher komplett verstanden zu haben). ;-(
Deshalb nochmals der Hinweis probiere erstmal das Beispiel zur Wire 
Bibliothek ohne es zu verändern und versuche zu verstehen was da 
passieren soll.


  Maria K. schrieb:
  > Im Terminal vom Slave zeigt es mir auch keine Daten vom Master
  > , welche gesendet werden sollten, an.
  > Ich denke das Problem ist, dass die Gesten, welche zur SPI
  > Schnittstelle gesendet werden, nicht von der
  > I2C Schnittstelle gelesen werden können.

Die SPI und I2C Schnittstellen (wie auch jede andere Schnittstelle) 
interessieren sich überhaupt nicht für die Bedeutung der übertragenen 
Daten. Schnittstellen kennen nur Daten. Nur du interpretierst diese mit 
einer Bedeutung z.B. als "Gesten". Das solltest du dir selber 
klarmachen.
Deshalb gibt es auch prinzipiell kein Problem bei der Übergabe von Daten 
von SPI zum I2C oder umgekehrt.


  > Und deshalb sendet es nichts. Aber ist nur eine Vermutung..
  > Hab auch nichts gefunden ob und wie man SPI Daten ausliest,
  > und zum I2C weiterleitet.

Und jetzt nochmal etwas Konstruktives. Eigentlich ist dein 
zusammengewürfelter Code garnicht so schlecht.
In deinem Code liest schon Daten von Irgendwo und sendest sie per UART 
an das Terminal. Beispielsweise in setServoPulse() sendest du 'pulse' 
per Serial.println(pulse) also dem UART an das Terminal. Nichts anderes 
ist das Senden und Empfangen der Gesten per I2C.
Und das (I2C senden/empfangen) hast du eigentlich gut geschrieben und 
entspricht auch fast dem Beispiel. Das Beispiel stellt beim Empfangen 
durch pollen von Wire.available() (while schleife) aber noch sicher, 
dass auch alle gesendeten Bytes gelesen werden bevor die Funktion 
receiveEvent() beendet wird.

Das Problem liegt sehr wahrscheinlich an einem anderen Teil des codes,
oder aber an der I2C Hardware.

Und noch etwas zu Kommentaren. Kommentare sollten zusätzliche 
Dokumentation liefern und nicht nochmal erklären was sowieso der Code 
schon aussagt. Bei deinem untenstehenden Code, weiß doch jeder sofort 
dass an device (addresse) #8 gesendet werden soll. Der Kommentar ist 
sozusagen doppelt und hust Einundvierzig oder 8! ;-)
1
Wire.beginTransmission(0x41); // transmit to device #8


Und hier noch zwei vielleicht zu offensichtliche Fehlermöglichkeiten für 
dein Problem.
1) Sender-Seite: _3DMasterRev01.ino
Du sendest immer die Geste mit dem Wert 0. EvGesture wird garnicht 
verändert.
1
  char EvGesture = 0;
2
  [...]
3
  Wire.write(EvGesture);  // sends one byte

2) Empfänger-Seite: ServoSlave.ino
Das Serial.println() steht außerhalb der case/break-Blöcke. Wird das 
überhaupt ausgeführt?
Zusatzfrage: Gibt es den Fall "EvGesture == 0" hier überhaupt?
1
     char EvGesture = Wire.read(); // receive byte as a character
2
     switch(EvGesture) {
3
         [...]
4
         case PUSH: //Gesture = PUSH
5
         break;
6
         Serial.println(EvGesture);
7
    }

von Michael O. (Gast)


Lesenswert?

Hey, danke für deine Antwort! - wirklich hilfreich, danke!

void schrieb:
> Maria du solltest dich an das Beispiel welches Matthias erwähnt halten.
> Probiere zunächst erstmal den Beispielcode aus ohne ihn zu verändern.
> Dann weißt du auch gleich, ob die Hardware funktioniert.

Das habe ich ganz am Anfang schon versucht.
Die zwei Arduino Boards kommunizieren über I2C einwandfrei!

Den "Master Code" also vom 3D Pad hab ich von Ootsidebox gedownloadet. 
Das ist der Code, welcher vom Hersteller zur Verfügung gestellt wird, 
damit das Pad überhaupt so funktioniert.
ootsidebox3DPad050315.ino
Dort hab ich nichts zusätzliches zusammengewürfelt.
Deshalb sollten im Rest vom Code eigentlich keine Fehler sein.

Nur diesen Teil hab ich selber dazu geschrieben (& werde ihn gleich 
wieder ändern)

   char EvGesture = 0;
   [...]
   Wire.write(EvGesture);  // sends one byte
   Wire.beginTransmission(0x41); // transmit to device #8
   Wire.write(EvGesture);              // sends one byte
   Wire.endTransmission();    // stop transmitting
   SendValues(ModeComSerie);   //siehe SendValueByUART.cpp



void schrieb:
> Und noch etwas zu Kommentaren. Kommentare sollten zusätzliche
> Dokumentation liefern und nicht nochmal erklären was sowieso der Code
> schon aussagt. Bei deinem untenstehenden Code, weiß doch jeder sofort
> dass an device (addresse) #8 gesendet werden soll. Der Kommentar ist
> sozusagen doppelt und hust Einundvierzig oder 8! ;-)

Ja stimmt..  Ich werde ab sofort darauf achten - danke! & auch die 
Fehler ausbessern.

void schrieb:
> Und hier noch zwei vielleicht zu offensichtliche Fehlermöglichkeiten für
> dein Problem.

Puh...iwie peinlich. werde es sofort ändern. Aber wie gesagt, noch kenn 
ich mich nicht wirklich aus... Ist eigentlich mein erstes Projekt mit 
einer Software...
- Gib allerdings mein Bestes.

Nochmals vielen Dank! :)

von void (Gast)


Lesenswert?

Maria K. schrieb:
  > Das habe ich ganz am Anfang schon versucht.
  > Die zwei Arduino Boards kommunizieren über I2C einwandfrei!

Ok. Super, dann funktioniert ja schonmal deine Hardware.
Und entschuldige, dass ich dir vorgeworfen hatte das nicht gemacht zu 
haben. ;-)


  Maria K. schrieb:
  > Nur diesen Teil hab ich selber dazu geschrieben
  > (& werde ihn gleich wieder ändern)

Jetzt fällts mir auch hier auf. Das beschriebene Problem 2) gibt es auch 
auf der Sender-Seite.
Bei einem switch statement, wird nur der Code innerhalb der 
case/break-Blöcke ausgeführt wenn kein default case definiert wurde. 
Code außerhalb der case/break-Blöcke wird niemals ausgeführt wenn kein 
default case existiert. Das ist jedenfalls das Verhalten vom gcc 
Compiler. (Ob es offizell undefiniertes Verhalten ist, habe ich jetzt 
nicht geprüft.)
Sprich, dein Wire-Sendefunktionen werden auch nicht aufgerufen...

Du solltest die Wire-Sendefunktionen entweder ganz aus dem switch 
herausnehmen
oder in den jeweiligen case/break-Block aufnehmen.
Und guter Stil ist es einen default-block zu schreiben, auch wenn dieser 
leer ist. Weil dann ist klar definiert was passiert wenn kein case 
zutrifft.


  Maria K. schrieb:
  > Aber wie gesagt, noch kenn ich mich nicht wirklich aus...
  > Ist eigentlich mein erstes Projekt mit einer Software...
  > - Gib allerdings mein Bestes.

Keine Sorge, dass wird besser je mehr du dich damit beschäftigst.
So haben die meisten hier angefangen...


Habe gerade nochmal die Bibliothek angeschaut. Die Dokumentation zu der 
Library ist aber auch toll...
Also was du eigentlich machen möchtest ist Senden der jeweiligen Geste,
das ist exakt das was SendValues(char mode) aus SendValueByUART.cpp auch 
macht.
Die Daten müssen dabei einfach nur zum I2C umgeleitet werden.
Die Funktion GestureCompute(), welche passenderweise in 
AutomateGesture() schon aufgerufen wird, bereitet die Gesten-information 
schon passend in "EvGesture" auf. Dumm ist, dass es keine Funktion gibt 
um die EvGesture Variable aus der Bibliothek abzufragen. Alternative 
ist, dass du einfach direkt auf EvGesture in MAGesture.cpp zugreifst, 
dazu musst du wohl MAGesture.h in main.c includieren und per "extern int 
EvGesture;" dir Zugriff darauf verschaffen. Und dass nachdem 
AutomateGesture() aufgerufen wurde.
Bezogen auf den ursprünglichen Code könnte das so aussehen.
1
  extern int EvGesture;
2
  char GestureChar;
3
  [...]
4
  AutomateDeroulement(); //automate d'acquisition
5
  Filters();
6
  [...]  
7
  AutomateGesture(0,0); //automate coordonnées 3D/gesture
8
9
  if ((EvGesture == RIGHT) || (EvGesture == LEFT)  // alle Gesten welche per I2C gesendet werden sollen
10
      || (EvGesture == UP) || (EvGesture == DOWN)  // (kann man auch weglassen, aber dann werden 
11
      || (EvGesture == ROTATE_LEFT) || (EvGesture == ROTATE_RIGHT) // alle Gesten gesendet - siehe MGesture.h)
12
      || (EvGesture == PUSH))
13
  {
14
    // per I2C senden
15
    GestureChar = (char)EvGesture;  // casten nach char (weil Wire.write nur bytes oder byte arrays senden kann)
16
    Wire.beginTransmission(0x41); // transmit to device #65 (0x41)
17
    Wire.write(GestureChar);      // sends one byte
18
    Wire.endTransmission();    // stop transmitting
19
20
    // per UART (terminal) senden
21
    Serial.print("\n\r Eine Geste wurde gesendet ");
22
    Serial.print(GestureChar);
23
  }
24
  
25
  // envoi des donnees sur le port USC (virtual COM port)
26
  SendValues(ModeComSerie);

Im Prinzip sollte es das sein.
Fallstricke welche halt auftauchen sind
1) Zugriff auf die Variable EvGesture
2) Format von EvGesture (int) passt nicht zur Wire.write (char) funktion
3) Aussortieren der "echten" Gesten (INIT, VOID, DUMMY, MOVING, ..., 
sind ja nicht so interessant)
Könnte aber noch mehr sein, ist ungetester Code...

Empfangen geht dann analog genau so nur anders herum.

Viel Erfolg dabei!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.