Habe ich ja in Post #36 gemacht
Ist ohne while...
Dann mal hier was spannendes. ![]()
bool startProgramm = false;
char zeichenketteRecvBuffer[32] = {0};
char zeichenketteSendBuffer[32] = {0};
void setup()
{
Serial.begin(115200);
Serial.println(F("Start..."));
}
void loop()
{
serialReadCommand();
serialZwischenCommand();
}
void serialReadCommand()
{
static byte myCharPosition = 0;
if (Serial.available() > 0)
{
char zeichen = Serial.read();
if (isPrintable(zeichen))
{
zeichenketteRecvBuffer[myCharPosition] = zeichen;
myCharPosition++;
startProgramm = true;
}
}
if (myCharPosition >= 25 || zeichenketteRecvBuffer[myCharPosition - 1] == 'X')
{
memcpy(zeichenketteSendBuffer, zeichenketteRecvBuffer, sizeof(zeichenketteSendBuffer));
serialWriteCommand();
memset(zeichenketteRecvBuffer, 0, sizeof(zeichenketteRecvBuffer));
myCharPosition = 0;
startProgramm = false;
}
}
void serialWriteCommand()
{
Serial.println();
Serial.println(zeichenketteSendBuffer);
}
void serialZwischenCommand()
{
const unsigned long intervall = 100;
static unsigned long lastTime = 0;
static byte zeichen = 46;
if (startProgramm)
{
if (millis() - lastTime >= intervall)
{
lastTime += intervall;
Serial.println(char(zeichen));
zeichen++;
if (zeichen > 100) zeichen = 46;
}
}
}
Und ich erklär das mal:
Du schiebst das auf deinen Controller.
Dann kannst Du im seriellen Monitor 25 Zeichen, jedes einzeln, ODER X eingeben.
Mit dem ersten Zeichen, was Du eingibst, wird nacheinander aus dem ASCIIZeichensatz ein Zeichen ausgegeben.
Nur wenn Du genau 25 zeichen oder ein X eingibst, bekommst Du Deine eingegebenen Zeichen zurück und die Ausgabe bleibt stehen.
Gibts Du mehr als 25 Zeichen ein, werden die 25 zeichen ausgegeben und dwer Rest wartet bis wieder 25 voll sind oder ein X kommt.
Wie Du unschwer nachsehen kannst, sind da 100ms(!) zwischen jeder Ausgabe....
... blockadefrei
Na denne.
Nachtrag:
Achso - Du kannst natürlich auch Zeichenketten eingeben. Ich hab das nur zum Zeigen(!) auf 2 Grenzen festgelegt - entweder 25 Zeichen oder X macht eine Ausgabe. Du darfst auch gerne mehr... versuchs einfach und wenn Dir was fehlt, sag was Du gemacht hast und was Dir fehlt....
Das ist in der Tat spannend! Kann ich aber nicht in mein Sendeformat integrieren. Da kommt nicht ganz das selbe raus. Aber ist dies wirklich schneller als mein oben geposteter Sketch ohne while - mit if?
Und I2C ist ja kein Problem, den Motorcontroller kann ich im Empfangen nicht ändern/beeinflussen. Das ist fix drauf, da kann man nichts anpassen. Das Sendemuster ist gemäss Handbuch vorgegeben, dass von der Adresse, dem Befehl und dem Wert die Prüfsumme generiert werden muss und dies dann in dieser Reihenfolge mit Prüfsumme am Ende gesendet wird. Da kann ich nicht mehr viel ändern.
Die Werte vom Joystick die eingelesen werden sind allemal genug schnell da, da mag I2C ja auch alles weitergeben. Der Flaschenhals entsteht dann wirklich, weil die 10ms oder mehr sein müssen, weil der Motorcontroller sonst überläuft und blockiert.
Oh. Hab ich Dich überrascht? Dann habe ich genau erreicht, was Dir in der Ablauffolge fehlt. Und das ist nicht böse - sondern ganz bestimmt gut gemeint!
Doch. GENAU DAS!
Und GENAU SO!
Mein Beispiel hat genau zwei Ende-Kennungen. Entweder ein X oder die Füllmenge des Buffer.
Du kannst doch selbst festlegen, auf was Du reagieren willst.
Du darfst nur eines NICHT machen: Unvollständige Datensätze verarbeiten oder in das TimeOut des Empfängers laufen.
Und GENAU DAS(!) machst Du.
Und dann gibt s keinen Ausstieg mehr.
Nochmal: Baue einen Minimalsketch (!) mit while oder nicht funktionierendem if, sage wo es klemmt. Dann helfe ich gern.
Alles andere läuft derzeit nur darauf raus, das Dir jemand Deinen Code komplett neu schreibt.
Und nein. Ich bin dazu nicht bereit.
Na denn - Man liest sich.
Ja das glaube ich ja, aber ich sehe im Moment nicht was mir das hier jetzt genau hilft!?
Die Daten müssten ja zum Motorcontroller gesendet werden mit diesem Sketch, oder? Aber genau da sehe ich das Problem, dass der Motorcontroller ja ein gewisses Format empfangen muss mit der Prüfsumme am Ende. Wie soll ich denn da was ändern wollen/können? Ich kann den Motorcontroller nicht programmieren, ich kann nur Daten im vorgegebenen Format senden, dass er versteht was zu tun ist.
Sonst ist das wirklich ein super Programmcode! Was bei mir jetzt einfach nicht geht, wenn ich z.B. die Übertragung vom Xbee zum Mega, die ja auch seriell TX/RX ist. Habe da versucht ganz stink einfach z.B. 'a' und 12 mit dem Endzeichen \r oder < in ein Array zu packen, dieses dann mit Serial.write(Array, sizeof Array) zu senden, dann empfängt der Empfangsarduino nur willkürliche Zeichen. So habe ich versuch zu senden:
const byte bufferSize = 10;
char serialBuffer[bufferSize];
const byte DPangle = 158;
void setup()
{
Serial.begin(115200);
}
void loop() {
command('E', 10, Serial);
command('F', 5, Serial);
command('G', 147, Serial);
command('H', DPangle, Serial);
command('#', 33, Serial);
}
void command (const char command, const byte value, Stream& stream)
{
for(byte i = 0; i < sizeof bufferSize; i++){
serialBuffer[i] = '\0';
}
sprintf(serialBuffer, "%c%d<", command, value);
const size_t characters = strlen(serialBuffer);
stream.write(serialBuffer, characters);
}
Wie sendet der serielle Monitor denn, weil so kommts nicht richtig an?
Nur um das nochmal aufzunehmen.. 10ms sind Dein TimeOut. Alles was nicht in 10ms vollständig auswertbar drüben ankommt, wird verworfen. Dein Gedankengang ist falsch!
Wenn Du also mit dem initialen Ereignis anfängst zu übertragen und die EndeKennung nicht initialsEreignis+10ms übertragen wird, bist Du raus.
Der Empfänger schmeisst alles weg.
Ich hoffe Dich zu erreichen...
Das stimmt! Was ich aber nicht verstehe, warum funktioniert es mit den 15ms Pause zwischen dem Senden der Daten zum Motorcontroller und wenns weniger ist friert alles ein? Das ist mir ein Rätsel....
Die Baudratenerhöhung hat vermutlich, was ich feststellen konnte etwas geholfen, das einfrieren zu verzögern. Aber es ist definitiv der Motorcontroller der das gesamte System blockiert. Wenn ich diesen vom Arduino nehme, dann geht alles problemlos.
Weil die Daten unvollständig sind und eine Endekennung kommt und Du auf diese und/oder das TimeOut keine Reaktion hast?
Vielleicht hat sich der Motorcontroller auch gegen Dich verschworen ![]()
Ne im Ernst.
Mach mir was minimales was nicht geht und ich bau das um, bis es geht. Und ich habe bisher alle meine Zusagen gehalten.
Aber wenn ich den Arduino nur mit folgendem code ausrüste:
byte data[5];
uint16_t crc = 0;
void setup(){
Serial.begin(38400);
motor(0,0, 130, Serial); //Befehl, Wert, Adresse, Stream
}
void loop(){
motor(0,127, 130, Serial);
delay(1000);
motor(0,0, 130, Serial);
}
void motor(const byte command, const byte value, const byte address, Stream& stream){
data[0] = address;
data[1] = command;
data[2] = value;
for(byte index = 0; index < 3; index++){
crc16(data[index]);
}
data[3] = crc >> 8;
data[4] = crc;
stream.write(data, sizeof(data));
crc = 0;
}
void crc16(uint8_t data) {
int i;
crc = crc ^ ((uint16_t)data << 8);
for (i=0; i<8; i++){
if (crc & 0x8000){
crc = (crc << 1) ^ 0x1021;
}
else{
crc <<= 1;
}
}
}
und das auf einen Arduino Uno lade, den Motorcontroller an TX beim Arduino anschliesse, dann läuft das ohne Probleme. Also denke ich nicht, dass es ein Sende/Empfangsproblem sein kann, oder?
Gute Frage.
Ich würde erstmal sehen wollen, ob die Arduinos komplett einfrieren.
Wenn ich richtig durch die Codes geschaut habe, benutzt Du die PIN13 nicht.
Dann auf beiden Boards im setup die onboard-LED als Output nutzen und im loop einen Funktionsaufruf um die LED zum blinken zu bekommen.
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
}
void heartbeat()
{
static unsigned long lastmillis = 0;
if (millis() - lastmillis >= 500)
{
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
lastmillis = millis();
}
}
void loop()
{
heartbeat();
}
das auf beiden in den Code integrieren - und dann sehen, ob und wenn ja welcher aufhört zu blinken.
Ansonsten hab ich mir das manual mal angetan... schlauer bin ich auch nicht geworden.
Hab ich versucht, der Master der die I2C Signale sendet blockiert. Der Arduino Uno der den Motorcontroller steuert würde noch blinken.
Ich habe jetzt auch mal versucht, die Baudrate des Motorcontroller tiefer zu stellen, auf 9600 und 19200b/s. Das ist auch besser als 38400b/s. Und die Pause von 4ms noch mit der Baudrate von 19200b/s kombiniert machts auch bisschen besser, aber irgendwann friert der Mega Master wieder ein.
Eine Idee was das sein kann? Sonst muss ich wirklich mal ein Sabertooth einbauen und versuchen, obs besser ist? Ohne den Roboclaw Motorcontroller läuft alles.
Damit ist der raus.
Also gehts nur noch um den Mega.
Kannst Du mal nen Foto vom Aufbau zeigen?
Ich hab Deinen MEGA-Code mit einigen zusätzlichen Ausgaben für den SerMon versehen - las den laufen und sag mir die letzte Zahl, die der SerMon ausgibt.
Ob das dann passt, muss man sehen, denn der wird jetzt gefloodet.
/**SETTINGS**/
const unsigned long Baudrate = 38400; //starts serial port with a baudrate by 38400 b/s
const unsigned long BaudrateBT_TC = 19200; //starts serial port with a baudrate by 19200 b/s
const unsigned long BaudrateMP = 9600; //starts serial port wit ha baudrate by 9600 b/s
const byte ArduBody = 0x2A; //I2C address for the Arduino UNO, body
const byte ArduDome = 0x1A; //I2C address for the Arduino UNO, dome
const byte RSSIsensitivity = 90; //received signal strength from Xbee controls the range until signal is lost and the fail safe will stop the motors,
//the Xbee's standard edition will give a value between 0 and 92 and the pro version a value between 0 and 100
const byte DDstop = 0; //Dome drive, basic position joystick (stop position)
const byte FDLRstop = 0; //Foot drive left/right, basic position joystick (stop position)
const byte FDUDstop = 0; //Foot drive forward/backward, basic position joystick (stop position)
const byte DPangleMIN = 0; //set minimum angle for dome panels 1-10 to close the panels
const byte DP16angleMAX = 175; //set maximum angle for dome panels 1-6 to open the panels (lower panels) (when BUT16 is pressed four times)
const byte DP710angleMAX = 165; //set maximum angle for dome panels 7-10 to open the panels (upper panels) (when BUT16 is pressed four times)
const byte SpeedDP = 40; //set the speed for dome panels 1-10 (when BUT16 is pressed once or four times) (0=full speed, 1-255 slower to faster)
const byte DPangleRattle = 80; //set maximum angle for dome panels 1-10 to open the panels (rattle functions, BUT16 is pressed twice or three times)
const byte SpeedDPrattle = 0; //set the speed for dome panels 1-10 (rattle functions, BUT16 is pressed twice or three times)(0=full speed, 1-255 slower to faster)
const byte DPangleMAX = 170; //set maximum angle for dome panels 1-10 to open the panels (scream function, BUT16 is pressed once)
const unsigned long DPservoMin = 900; //set minimum pulse length in microseconds for dome panels
const unsigned long DPservoMax = 2100; //set maximum pulse length in microseconds for dome panels
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
//Definition of pinnumbers
const byte DomePanel1 = 2; //Dome panel 1 connected to pin D2
const byte DomePanel2 = 3; //Dome panel 2 connected to pin D3
const byte DomePanel3 = 4; //Dome panel 3 connected to pin D4
const byte DomePanel4 = 5; //Dome panel 4 connected to pin D5
const byte DomePanel5 = 6; //Dome panel 5 connected to pin D6
const byte DomePanel6 = 7; //Dome panel 6 connected to pin D7
const byte XbeeRSSI = 10; //Xbee RSSI pin connected to pin D10
//Definition of designations for reading signals (signals to be received)
byte DP1 = 0; //Domepanel 1
byte DP2 = 0; //Domepanel 2
byte DP3 = 0; //Domepanel 3
byte DP4 = 0; //Domepanel 4
byte DP5 = 0; //Domepanel 5
byte DP6 = 0; //Domepanel 6
byte DP7 = 0; //Domepanel 7
byte DP8 = 0; //Domepanel 8
byte DP9 = 0; //Domepanel 9
byte DP10 = 0; //Domepanel 10
byte BP1 = 0; //Bodypanel 1
byte BP2 = 0; //Bodypanel 2
byte BP3 = 0; //Bodypanel 3
byte BP4 = 0; //Bodypanel 4
byte BP5 = 0; //Bodypanel 5
byte UAL = 0; //arm left
byte UAR = 0; //arm right
byte DD = 0; //Dome drive
byte FDLR = 0; //Foot drive left/right
byte FDUD = 0; //Foot drive forward/backward
byte joybut = 0; //Foot drive joystick-button
byte BUT1 = 0; //Button 1
byte BUT2 = 0; //Button 2
byte BUT3 = 0; //Button 3
byte BUT4 = 0; //Button 4
byte BUT5 = 0; //Button 5
byte BUT6 = 0; //Button 6
byte BUT7 = 0; //Button 7
byte BUT8 = 0; //Button 8
byte BUT9 = 0; //Button 9
byte BUT10 = 0; //Button 10
byte BUT11 = 0; //Button 11
byte BUT12 = 0; //Button 12
byte BUT13 = 0; //Button 13
byte BUT14 = 0; //Button 14
byte BUT15 = 0; //Button 15
byte BUT16 = 0; //Button 16
byte BUT17 = 0; //Button 17
byte BUT18 = 0; //Button 18
byte BUT19 = 0; //Button 19
byte BUT20 = 0; //Button 20
byte BUT21 = 0; //Button 21
byte BUT22 = 0; //Button 22
byte BUT23 = 0; //Button 23
byte autobut = 0; //Automatic button
//Definition of designations for storing signals (cache)
char var = 0; //variable for reading incoming serial data
byte error = 0; //error from I2C
byte lastBUT21 = 1; //last status from button 21 to close all dome panels on power ON
byte step4 = 0; //counts steps when button 16 pressed 4 times
byte step3 = 0; //counts steps when button 16 pressed 3 times
byte step2 = 0; //counts steps when button 16 pressed twice
byte step1 = 0; //counts steps when button 16 pressed once
byte rssi = 0; //variable for RSSI value from Xbee, the standard edition will give a value between 0 and 92 and the pro version a value between 0 and 100
String BT_RX; //stores the letter from BT_var to BT_RX
char BT_var; //reads the letter from Bluetooth serial
unsigned long interval = 0; //waiting period in milliseconds (cache)
unsigned long previousMillis = 0; //stores past time
#include <VarSpeedServo.h> //adds library to control servos
#include <Wire.h> //adds library for I2C
//create servo object (maximum 8)
VarSpeedServo servoDP1; //create servo dome panel 1
VarSpeedServo servoDP2; //create servo dome panel 2
VarSpeedServo servoDP3; //create servo dome panel 3
VarSpeedServo servoDP4; //create servo dome panel 4
VarSpeedServo servoDP5; //create servo dome panel 5
VarSpeedServo servoDP6; //create servo dome panel 6
void setup()
{
Serial.begin(115200);
Serial1.begin(Baudrate); //starts serial port for Xbee with a baudrate by "Baudrate" (b/s)
Serial2.begin(BaudrateBT_TC); //starts serial port for Bluetooth module with a baudrate by "BaudrateBT_TC" (b/s)
Serial2.setTimeout(3); //sets the maximum milliseconds to wait for serial data
Serial3.begin(BaudrateMP); //starts serial port with a baudrate by "BaudrateMP" (b/s)
Wire.begin(); //starts I2C
//Wire.setClock(295000); //set the clock speed from I2C to 295kHz
//attach the servos
servoDP1.attach(DomePanel1, DPservoMin, DPservoMax); //servoDP1 is attached to pin DomePanel1 with pulse length DPservoMin and DPservoMax
servoDP2.attach(DomePanel2, DPservoMin, DPservoMax); //servoDP2 is attached to pin DomePanel2 with pulse length DPservoMin and DPservoMax
servoDP3.attach(DomePanel3, DPservoMin, DPservoMax); //servoDP3 is attached to pin DomePanel3 with pulse length DPservoMin and DPservoMax
servoDP4.attach(DomePanel4, DPservoMin, DPservoMax); //servoDP4 is attached to pin DomePanel4 with pulse length DPservoMin and DPservoMax
servoDP5.attach(DomePanel5, DPservoMin, DPservoMax); //servoDP5 is attached to pin DomePanel5 with pulse length DPservoMin and DPservoMax
servoDP6.attach(DomePanel6, DPservoMin, DPservoMax); //servoDP6 is attached to pin DomePanel6 with pulse length DPservoMin and DPservoMax
//definition of input/output pins
pinMode(XbeeRSSI, INPUT_PULLUP); //pin XbeeRSSI is an input
pinMode(LED_BUILTIN, OUTPUT);
}
void heartbeat()
{
static unsigned long lastmillis = 0;
if (millis() - lastmillis >= 500)
{
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
lastmillis = millis();
}
}
void loop()
{
heartbeat();
//RSSI value from the Xbee to detect when the signal is missing
rssi = pulseIn(XbeeRSSI, LOW, 200); //read the RSSI value from Xbee (the XBee’s RSSI PWM period is 200µs), the standard edition will give a value between 0 and 92 and the pro version a value between 0 and 100
if (rssi <= RSSIsensitivity) //if RSSI value is less or equal to RSSIsensitivity (inside controllable range), then make...
{
Serial.println(1);
//read serial and store it to designation
readCommand(Serial1);
}
else if (rssi > RSSIsensitivity) //if RSSI value is greater than RSSIsensitivity (out of controllable range), then make...
{
command('X', DDstop, ArduBody); //send the letter X (for dome drive) and dome movement stopped (left < 90 < right, 80 slow left, 0 full throttle resp. 100 slow right, 180 full throttle) to ArduBody
command('Y', FDLRstop, ArduBody); //send the letter Y (for foot drive left/right) travel stopped (right < 90 < left, 80 slow right, 0 full throttle resp. 100 slow left, 180 full throttle) to ArduBody
command('Z', FDUDstop, ArduBody); //send the letter Z (for foot drive forward/backward) and travel stopped (backwards < 90 < forwards, 80 slow backward, 0 full throttle resp. 100 slow forward, 180 full throttle) to ArduBody
}
//read serial and send it via serial xx to the device
while (Serial2.available() > 0) //while serial is available, make...
{
Serial.println(2);
BT_var = Serial2.read(); //store received string from serial to BT_var
BT_RX = BT_RX + BT_var; //add received string to BT_RX
if (BT_var == '\0') //if BT_var is equal to '\0', then make...
{
Serial3.print(BT_RX); //send string from BT_RX
Serial3.print('\r'); //send carriage return
Serial2.print(BT_RX); //send string from BT_RX
Serial2.print('\r'); //send carriage return
BT_RX = ""; //clear BT_RX
}
}
//Domefunctions:
//Button16 pressed once:
while (BUT16 == 1 || step1 > 0) //if BUT16 is equal to 1 (pressed once) or step1 is greater than 0, then make...
{
Serial.println(3);
if (millis() - previousMillis >= interval) //if millis minus previousMillis is greater or equal to interval, then make...
{
step1 ++; //step1 +1 (counts steps)
switch (step1) //switch step1
{
case 1: //if step1 is equal to 1
servoDP1.write(DPangleMAX, SpeedDP); //set servoDP1 with angle DPangleMAX and speed SpeedDP
servoDP2.write(DPangleMAX, SpeedDP); //set servoDP2 with angle DPangleMAX and speed SpeedDP
servoDP3.write(DPangleMAX, SpeedDP); //set servoDP3 with angle DPangleMAX and speed SpeedDP
servoDP4.write(DPangleMAX, SpeedDP); //set servoDP4 with angle DPangleMAX and speed SpeedDP
servoDP5.write(DPangleMAX, SpeedDP); //set servoDP5 with angle DPangleMAX and speed SpeedDP
servoDP6.write(DPangleMAX, SpeedDP); //set servoDP6 with angle DPangleMAX and speed SpeedDP
command('t', BUT16, ArduDome); //send the letter t (for BUT16) and the value of BUT16 (how often pressed to set the correct speed value for dome panels) by I2C
command('G', DPangleMAX, ArduDome); //send the letter G (for dome panel 7) and the value of DPangleMAX (opening angle for servo) by I2C
command('H', DPangleMAX, ArduDome); //send the letter H (for dome panel 8) and the value of DPangleMAX (opening angle for servo) by I2C
command('I', DPangleMAX, ArduDome); //send the letter I (for dome panel 9) and the value of DPangleMAX (opening angle for servo) by I2C
command('J', DPangleMAX, ArduDome); //send the letter J (for dome panel 10) and the value of DPangleMAX (opening angle for servo) by I2C
interval = 1000; //waiting time to open the panels (milliseconds)
break; //finish case and return
case 2: //if step1 is equal to 2
command('X', 75, ArduBody); //send the letter X (for dome drive) and dome movement slowly left, about 360 degrees (left < 90 < right, 80 slow left, 0 full throttle resp. 100 slow right, 180 full throttle) by I2C
interval = 3000; //waiting time to turn the dome (milliseconds)
break; //finish case and return
case 3: //if step1 is equal to 3
command('X', DDstop, ArduBody); //send the letter X (for dome drive) and dome movement stopped (left < 90 < right, 80 slow left, 0 full throttle resp. 100 slow right, 180 full throttle) by I2C
interval = 1500; //waiting time (milliseconds)
break; //finish case and return
case 4: //if step1 is equal to 4
servoDP1.write(DPangleMIN, SpeedDP); //set servoDP1 with angle DPangleMIN and speed SpeedDP
servoDP2.write(DPangleMIN, SpeedDP); //set servoDP2 with angle DPangleMIN and speed SpeedDP
servoDP3.write(DPangleMIN, SpeedDP); //set servoDP3 with angle DPangleMIN and speed SpeedDP
servoDP4.write(DPangleMIN, SpeedDP); //set servoDP4 with angle DPangleMIN and speed SpeedDP
servoDP5.write(DPangleMIN, SpeedDP); //set servoDP5 with angle DPangleMIN and speed SpeedDP
servoDP6.write(DPangleMIN, SpeedDP); //set servoDP6 with angle DPangleMIN and speed SpeedDP
command('G', DPangleMIN, ArduDome); //send the letter G (for dome panel 7) and the value of DPangleMIN (closing angle for servo) by I2C
command('H', DPangleMIN, ArduDome); //send the letter H (for dome panel 8) and the value of DPangleMIN (closing angle for servo) by I2C
command('I', DPangleMIN, ArduDome); //send the letter I (for dome panel 9) and the value of DPangleMIN (closing angle for servo) by I2C
command('J', DPangleMIN, ArduDome); //send the letter J (for dome panel 10) and the value of DPangleMIN (closing angle for servo) by I2C
interval = 1; //waiting time to close the panels (milliseconds)
break; //finish case and return
default:
step1 = 0; //put step1 back to 0
BUT16 = 0; //put BUT16 back to 0
interval = 0; //put interval back to 0
}
previousMillis = millis(); //previousMillis is millis
}
}
//Button16 pressed twice:
while (BUT16 == 2 || step2 > 0) //if BUT16 is equal to 2 (pressed twice) or step2 is greater than 0, then make...
{
Serial.println(4);
if (millis() - previousMillis >= interval) //if millis minus previousMillis is greater or equal to interval, then make...
{
step2 ++; //step2 +1 (counts steps)
switch (step2) //switch step2
{
case 1: //if step2 is equal to 1
servoDP1.write(DPangleRattle, SpeedDPrattle); //set servoDP1 with angle DPangleRattle and speed SpeedDPrattle
interval = 175; //waiting time to open the panel (milliseconds)
break; //finish case and return
case 2: //if step2 is equal to 2
servoDP1.write(DPangleMIN, SpeedDPrattle); //set servoDP1 with angle DPangleMIN and speed SpeedDPrattle
servoDP2.write(DPangleRattle, SpeedDPrattle); //set servoDP2 with angle DPangleRattle and speed SpeedDPrattle
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 3: //if step2 is equal to 3
servoDP2.write(DPangleMIN, SpeedDPrattle); //set servoDP2 with angle DPangleMIN and speed SpeedDPrattle
servoDP3.write(DPangleRattle, SpeedDPrattle); //set servoDP3 with angle DPangleRattle and speed SpeedDPrattle
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 4:
servoDP3.write(DPangleMIN, SpeedDPrattle); //set servoDP3 with angle DPangleMIN and speed SpeedDPrattle
servoDP4.write(DPangleRattle, SpeedDPrattle); //set servoDP4 with angle DPangleRattle and speed SpeedDPrattle
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 5:
servoDP4.write(DPangleMIN, SpeedDPrattle); //set servoDP4 with angle DPangleMIN and speed SpeedDPrattle
servoDP5.write(DPangleRattle, SpeedDPrattle); //set servoDP5 with angle DPangleRattle and speed SpeedDPrattle
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 6:
servoDP5.write(DPangleMIN, SpeedDPrattle); //set servoDP5 with angle DPangleMIN and speed SpeedDPrattle
servoDP6.write(DPangleRattle, SpeedDPrattle); //set servoDP6 with angle DPangleRattle and speed SpeedDPrattle
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 7:
servoDP6.write(DPangleMIN, SpeedDPrattle); //set servoDP6 with angle DPangleMIN and speed SpeedDPrattle
command('t', BUT16, ArduDome); //send the letter t (for BUT16) and the value of BUT16 (how often pressed to set the correct speed value for dome panels) by I2C
command('G', DPangleRattle, ArduDome); //send the letter G (for dome panel 7) and the value of DPangleRattle (opening angle for servo) by I2C
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 8:
command('G', DPangleMIN, ArduDome); //send the letter G (for dome panel 7) and the value of DPangleMIN (closing angle for servo) by I2C
command('H', DPangleRattle, ArduDome); //send the letter H (for dome panel 8) and the value of DPangleRattle (opening angle for servo) by I2C
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 9:
command('H', DPangleMIN, ArduDome); //send the letter H (for dome panel 8) and the value of DPangleMIN (closing angle for servo) by I2C
command('I', DPangleRattle, ArduDome); //send the letter I (for dome panel 9) and the value of DPangleRattle (opening angle for servo) by I2C
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 10:
command('I', DPangleMIN, ArduDome); //send the letter I (for dome panel 9) and the value of DPangleMIN (closing angle for servo) by I2C
command('J', DPangleRattle, ArduDome); //send the letter J (for dome panel 10) and the value of DPangleRattle (opening angle for servo) by I2C
interval = 175; //waiting time to open/close the panels (milliseconds)
break; //finish case and return
case 11:
command('J', DPangleMIN, ArduDome); //send the letter J (for dome panel 10) and the value of DPangleMIN (closing angle for servo) by I2C
interval = 1; //waiting time to close the panel (milliseconds)
break; //finish case and return
default:
step2 = 0; //put step2 back to 0
BUT16 = 0; //put BUT16 back to 0
interval = 0; //put interval back to 0
}
previousMillis = millis(); //previousMillis is millis
}
}
//Button21 pressed:
if (BUT21 == 1 && lastBUT21 != 1) //if BUT21 is equal to 1 (extended dome panels) and lastBUT21 not equal to 1, then make...
{
Serial.println(5);
servoDP1.write(DPangleMAX, SpeedDP); //set servoDP1 with angle DPangleMAX and speed SpeedDP
servoDP2.write(DPangleMAX, SpeedDP); //set servoDP2 with angle DPangleMAX and speed SpeedDP
servoDP3.write(DPangleMAX, SpeedDP); //set servoDP3 with angle DPangleMAX and speed SpeedDP
servoDP4.write(DPangleMAX, SpeedDP); //set servoDP4 with angle DPangleMAX and speed SpeedDP
servoDP5.write(DPangleMAX, SpeedDP); //set servoDP5 with angle DPangleMAX and speed SpeedDP
servoDP6.write(DPangleMAX, SpeedDP); //set servoDP6 with angle DPangleMAX and speed SpeedDP
command('y', BUT21, ArduDome); //send the letter y (for BUT21) and the value of BUT21 (how often pressed to set the correct speed value for dome panels) by I2C
command('G', DPangleMAX, ArduDome); //send the letter G (for dome panel 7) and the value of DPangleMAX (opening angle for servo) by I2C
command('H', DPangleMAX, ArduDome); //send the letter H (for dome panel 8) and the value of DPangleMAX (opening angle for servo) by I2C
command('I', DPangleMAX, ArduDome); //send the letter I (for dome panel 9) and the value of DPangleMAX (opening angle for servo) by I2C
command('J', DPangleMAX, ArduDome); //send the letter J (for dome panel 10) and the value of DPangleMAX (opening angle for servo) by I2C
lastBUT21 = BUT21; //set lastBUT21 to BUT21
}
else if (BUT21 == 0 && lastBUT21 != 0) //if BUT21 is equal to 0 (retracted dome panels) and lastBUT21 not equal to 0, then make...
{
Serial.println(6);
servoDP1.write(DPangleMIN, SpeedDP); //set servoDP1 with angle DPangleMIN and speed SpeedDP
servoDP2.write(DPangleMIN, SpeedDP); //set servoDP2 with angle DPangleMIN and speed SpeedDP
servoDP3.write(DPangleMIN, SpeedDP); //set servoDP3 with angle DPangleMIN and speed SpeedDP
servoDP4.write(DPangleMIN, SpeedDP); //set servoDP4 with angle DPangleMIN and speed SpeedDP
servoDP5.write(DPangleMIN, SpeedDP); //set servoDP5 with angle DPangleMIN and speed SpeedDP
servoDP6.write(DPangleMIN, SpeedDP); //set servoDP6 with angle DPangleMIN and speed SpeedDP
command('y', BUT21, ArduDome); //send the letter y (for BUT21) and the value of BUT21 (how often pressed to set the correct speed value for dome panels) by I2C
command('G', DPangleMIN, ArduDome); //send the letter G (for dome panel 7) and the value of DPangleMIN (closing angle for servo) by I2C
command('H', DPangleMIN, ArduDome); //send the letter H (for dome panel 8) and the value of DPangleMIN (closing angle for servo) by I2C
command('I', DPangleMIN, ArduDome); //send the letter I (for dome panel 9) and the value of DPangleMIN (closing angle for servo) by I2C
command('J', DPangleMIN, ArduDome); //send the letter J (for dome panel 10) and the value of DPangleMIN (closing angle for servo) by I2C
lastBUT21 = BUT21; //set lastBUT21 to BUT21
}
}
//Function for sending a command
void command(const char designation, const byte value, const byte address) //the function command contains the sending part inside the ( ) declared as a character and value and the I2C address where to send
{
Serial.println(7);
Wire.beginTransmission(address);
Wire.write(designation);
Wire.write(value);
error = Wire.endTransmission();
errorCode(error);
}
void errorCode(byte error)
{
if (error != 0)
{
switch (error)
{
case 1: Serial.print("Command error: ");
Serial.print(error);
Serial.println(" Data too long to fit in transmit buffer!");
break;
case 2: Serial.print("Command error: ");
Serial.print(error);
Serial.println(" Received NACK on transmit of address!");
break;
case 3: Serial.print("Command error: ");
Serial.print(error);
Serial.println(" Received NACK on transmit of data!");
break;
case 4: Serial.print("Command error: ");
Serial.print(error);
Serial.println(" Other error!");
break;
}
}
}
//Function for reading a command and store it to designation or send it via serial xx to the next Arduino
void readCommand(Stream &stream) //the function readCommand contains the serial port inside the ( ) where to read from
{
while (stream.available() > 0) //while serial is available, make...
{
Serial.println(8);
var = stream.read(); //store first character from serial to var
switch (var)
{
case 'A' : DP1 = stream.parseInt(); //if var is equal to A, then store second character from serial to DP1
break; //finish the command and return
case 'B' : DP2 = stream.parseInt();
break;
case 'C' : DP3 = stream.parseInt();
break;
case 'D' : DP4 = stream.parseInt();
break;
case 'E' : DP5 = stream.parseInt();
break;
case 'F' : DP6 = stream.parseInt();
break;
case 'G' : DP7 = stream.parseInt(); //if var is equal to G, then store second character from serial to DP7
command('G', DP7, ArduDome); //if var is equal to G, then send G + DP7 to I2C
break;
case 'H' : DP8 = stream.parseInt();
command('H', DP8, ArduDome);
break;
case 'I' : DP9 = stream.parseInt();
command('I', DP9, ArduDome);
break;
case 'J' : DP10 = stream.parseInt();
command('J', DP10, ArduDome);
break;
case 'Q' : BP1 = stream.parseInt();
command('Q', BP1, ArduBody);
break;
case 'R' : BP2 = stream.parseInt();
command('R', BP2, ArduBody);
break;
case 'S' : BP3 = stream.parseInt();
command('S', BP3, ArduBody);
break;
case 'T' : BP4 = stream.parseInt();
command('T', BP4, ArduBody);
break;
case 'U' : BP5 = stream.parseInt();
command('U', BP5, ArduBody);
break;
case 'V' : UAL = stream.parseInt();
command('V', UAL, ArduBody);
break;
case 'W' : UAR = stream.parseInt();
command('W', UAR, ArduBody);
break;
case 'X' : DD = stream.parseInt();
command('X', DD, ArduBody);
break;
case 'Y' : FDLR = stream.parseInt();
command('Y', FDLR, ArduBody);
break;
case 'Z' : FDUD = stream.parseInt();
command('Z', FDUD, ArduBody);
break;
case 'd' : joybut = stream.parseInt();
command('d', joybut, ArduBody);
break;
case 'h' : BUT4 = stream.parseInt();
command('h', BUT4, ArduBody);
break;
case 'l' : BUT8 = stream.parseInt();
command('l', BUT8, ArduBody);
break;
case 'p' : BUT12 = stream.parseInt();
command('p', BUT12, ArduBody);
break;
case 't' : BUT16 = stream.parseInt();
break;
case 'w' : BUT19 = stream.parseInt();
break;
case 'x' : BUT20 = stream.parseInt();
command('x', BUT20, ArduBody);
break;
case 'y' : BUT21 = stream.parseInt();
break;
case 'z' : autobut = stream.parseInt();
break;
case '@' : BUT22 = stream.parseInt();
break;
case '$' : BUT23 = stream.parseInt();
break;
}
}
}
Foto kann ich leider keines machen, Kamera ist kaputt. Aber ich kann Dir etwas aufzeichnen versuchen wenn das was hilft.
Was ich aber nicht verstehe, was hat der Mega mit dem Motorcontroller zu tun, wenn dieser gar nicht direkt damit verbunden ist? Dann muss ja auf der TX Leitung vom Uno irgendwas zurückfliessen das stört?
Am Mega ist ein Xbee für den Empfang dran, ein Bluetooth Modul, zwei Lampen per TX und 10 Servos. Die Servos sind nur mit GND und dem Signal verbunden. Die Stromversorgung kommt direkt vom Spannungswandler der auch die 5V für den Mega liefert.
Habe den modifizierten Sketch mal hochgeladen. Das ist die Ausgabe:
1
1
1
8
7
8
8
8
7
8
8
8
7
Command error: 3 Received NACK on transmit of data!
8
oder ein zweiter Versuch das:
8
8
8
7
8
8
8
7
Command error: 4 Other error!
8
8
8
7
Na schick.
Die Error-Ausgaben kommen vom I2C.
Da ist wohl der Bus anfällig.
Musste ändern. Das kann jetzt alles sein.
Ich würde als erstes auf die PULLUPS gehen.
Deine errechneten 5K reichen möglicherweise nicht.
Nachrechnen: Datenblatt Mega Tabelle 31.7
Und dann ist die Umgebung möglicherweise durch den Treiber vergiftet. Das würde erklären, warum das nur mit Treiber, aber auch ohne Motoren in die Hose geht.
Vielleicht haut Dir auch die lib irgendwo dazwischen - aber das kannst nur Du selbst rausfinden, da die Hardware eher keiner nachbauen wird.
Wie rechnet man die Pullups aus? Die Tabelle gibt ja nur die Spezifikationen raus.
Das ist vermutlich so. Ist das bei allen Motorcontrollern so, oder kann man da beim Kauf auf etwas achten? Was könnte man machen, um das zu unterdrücken, dass dieser solche Störungen abgibt?
Hier findest du Links:
Steht doch drin.
Mindestgröße (Vcc-0,4V)/3mA [edit: Formel geklammert, bevor jemand das für bare Münze nimmt /]
Maximalgröße ist abhängig von der Kapaziät der Leitung.
Wenn Du das maximale nicht ausrechnen kannst, weil Du die Kapazität der Leitung nicht kennst, könntest bis auf etwa 1,6 K runter.
Und dann nimm mal abgeschirmte Kabel.
Und den Treiber weit weg vom MEGA.
Mich würde schliesslich auch nicht wundern, wenn der XBEE da als Antenne wirkkt etc. pp. Da gibts unzählige Möglichkeiten.
Ja, wenn ich mit den Formeln rechne, komme ich auf RPmin = 1.6kOhm und RPmax = 3.0kOhm.
Hat der Mega wirklich 10kOhm, also kann man mit dem rechnen oder ist der stark schwankend?
Und es reicht ja nur beim Mega die Pullups zu setzen, oder? Der Uno braucht ja nicht auch noch.
Dann sollte ich Rges = 1/R1 + 1/R2 = 1/10kOhm + 1/2kOhm =~1.67kOhm mit 1x 2kOhm zu den internen 10kOhm vom Mega. Passt das so oder ist das schon zu nah an der Grenze?
Was kann man sonst noch machen um die "vergiftete" Umgebung des Motortreibers einzudämmen? Ein Metallgehäuse drumrum bauen?
Der Xbee als Antenne..... wie könnte man das verhindern, aber dass es trotzdem noch meine Daten empfängt?
Also was er hat: Nachsehen. ![]()
schwanken... selbst 2% würden 200Ohm ausmachen... Aber die sind wohl eher 1%...
Mein Ansatz wäre auf dem MEGA einen zusätzlichen PULLUP zu setzen.
das vergiss! Nichts mit den internen Widerständen machen!
Die sind irgendwo zwischen 20 und 50K.
Die aufgelöteten 10K sind Vorgabe.
Ich will erstmal runter und das untere Level nicht ganz kratzen.
Mit 3K am Mega habe ich einen vernünftigen Ansatz:
(10K*3K)/(10K+3K) = bin ich bei 2,3K
Das könnte gehen.
Wenn Du das untere Ende ausreizen willst, musst Du auf 2K runter.
Achte drauf: Es darf dann nichts weiter am I2C an Shields mit Widerstand dran hängen.
Ansonsten fehlt mir auch jede Idee, ohne den Aufbau zu kennen.