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
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
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/MasterWriterMaria 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
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
charEvGesture=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
charEvGesture=Wire.read();// receive byte as a character
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! :)
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.
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!