Go Down

Topic: Better Serial library? & Why we have to make delay after sending info. in Serial (Read 3113 times) previous topic - next topic

PaulS

Serial data transmission is generally bidirectional. Asynchronous, yes, but bidirectional. I don't see anywhere in your code where you care what the motor might be saying in response to your commands, if it responds at all.

The command pages I looked at indicate that each command causes a reply. Why aren't you concerned about the responses?

Gfast

Quote

The command pages I looked at indicate that each command causes a reply. Why aren't you concerned about the responses?

Yeh, Pauls. You are almost right. I don't need much bidirectional communication between arduino and step motor. 99% command is "single directional". I'm not sure in really professional area how many motor will be controlled by his own build-in microcontroller and in my motor (Nanotec PD4-N) there is even a "shaft encoder" that can record the absolutely position of the motor. In my project I have to read the value through Serial port. So I have to do care about if the command is correctly be gotten by motors. And I think my still works not great function that read this value should be enhanced.
Code: [Select]

/*****
* Purpose: get the actual drehzahl of the motor. (Right-rotation add the Drehzahl, left reduce it)
* Argument: void
* Return: void
* input: void
* output: the position value "drehWert" read from the integrated circuit of the motor
*****/
void Drehgeber() {
char signAscii;
int sign; //Here can not be "byte", that can't save negative value.
int  length;

Serial2.println("#1I"); //"ask" motor for the position value.
if (Serial2.available()) {
length = Serial2.available(); //if a bit is readed, than it doesn't exist in the serial buffer anymore.
if (Serial2.read() == 49){ //wenn erste Stelle eine '1' ist (Motoradresse),(this part should be refactoringed to let the other motor also work)
if (Serial2.read() == 73){ //wenn nächste Stelle ein 'I' ist (Drehgeberposition)
drehwert = 0;
signAscii = Serial2.read(); //Ascii '+' or '-'
if (signAscii == '+') //wenn Ascii Wert = 43 dann positiv
sign = 1; //store the polarity of the absolute position value from shaft encoder.
else if (signAscii == '-') //wenn Ascii Wert = 45 dann negativ
sign = -1;
for (int i=(length-5); i>=0; i--){
int Wert = Serial2.read();
drehwert = drehwert + ((Wert - 48) * pow(10,i)); //calculate the read value
}
drehwert = drehwert * sign; //here set the direction of the absolute positioin value.
}
Serial.print(" position:");
Serial.println(drehwert);
}
else Serial.println("ERROR, Drehgeber crashed!");
while(Serial2.read()>0); //clear the Serial2's buffer
}
}


Protocol:
Ask command format:
"#1I\r" -- '#'-command start, '1'-motor address,'I'-command asking for shaft encoder read value, '\r'-CR end symbol
Answer command format:
"1I00000000\r" -- '1'-motor address, 'I"-command asking for shaft encoder read value, "00000000"-read value,'\r'-CR end symbol
The read value don't have fixed bits. I thought the parsing method is very poor... And I can't make it better any further.

BTW: In 2011, Pauls you helped me this year to build a perfect working Xbee communication. I appreciate your kindly help. Here I'd like to thank you once more.  :)

PaulS

Quote
I don't need much bidirectional communication between arduino and step motor.

Once it's working, you probably don't need any. Until then, it's a good idea to understand what the stepper motor is getting and what it is accepting or rejecting, in case some input you are giving it is not quite right.

Code: [Select]
if (Serial2.available()) {
length = Serial2.available(); //if a bit is readed, than it doesn't exist in the serial buffer anymore.
if (Serial2.read() == 49){ //wenn erste Stelle eine '1' ist (Motoradresse),(this part should be refactoringed to let the other motor also work)
if (Serial2.read() == 73){ //wenn nächste Stelle ein 'I' ist (Drehgeberposition)
drehwert = 0;
signAscii = Serial2.read(); //Ascii '+' or '-'
if (signAscii == '+') //wenn Ascii Wert = 43 dann positiv
sign = 1; //store the polarity of the absolute position value from shaft encoder.
else if (signAscii == '-') //wenn Ascii Wert = 45 dann negativ
sign = -1;
for (int i=(length-5); i>=0; i--){
int Wert = Serial2.read();

If there is at least one byte available to read, that does not mean that you can then read as many as you want.

Nick Gammon


And I did it with:
Code: [Select]

        while(Serial2.available())
Serial.write(Serial2.read());
while(Serial2.read()>0); //".flush();" don't work for Serial2

...
My thought: I send command too fast, that the serial port of some side or even both sides of the serial communication overload.


I don't see what that code usefully achieves. Rather than explaining at great length, read this:

http://www.gammon.com.au/serial
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Gfast

Gammon, It works!
I used your last example to parse from Serial coming Data. Bravo!

But I do did a tiny modification on it:
in the "void loop(){}" I changed "if (Serial.available())" to "while (Serial.available())". If I don't, the Serial buffer will be overflowed (But I'm not pretty clear about this point.)

Thank you again!

P.S. The function that works perfectly now is:
Code: [Select]

const char startOfNumberDelimiter = 'I';
const char endOfNumberDelimiter   = '\r';

void shaftEncoder(){
Serial2.print("#1I\r");
while (Serial2.available())
processInput();
}

void processNumber (const long n)
{
Serial.println (n);
}  // end of processNumber

void processInput ()
{
static long receivedNumber = 0;
static boolean negative = false;

byte c = Serial2.read ();

switch (c)
{
case endOfNumberDelimiter:
if (negative)
processNumber (- receivedNumber);
else
processNumber (receivedNumber);

// fall through to start a new number
case startOfNumberDelimiter:
receivedNumber = 0;
negative = false;
break;

case '0' ... '9':
receivedNumber *= 10;
receivedNumber += c - '0';
break;

case '-':
negative = true;
break;

case '+':
negative = false;
break;

default:
Serial.println("!");
break;

} // end of switch
}  // end of processInput


Gfast

update:

A few days before, I tried to Email the engeneers of the motor's company (Nanotec). Today I got the answer from them: (German)
Quote
Die Steuerung senden ein Echo des Befehls, wenn dieser Befehl erkannt und verarbeitet wurde.


z.B.



-> #1A\r                              Befehl vom Anwender



Etwa 10-40ms



<- 1A\r                                 Antwort der Steuerung



Nach dieser Antwort ist die Steuerung bereit einen neuen Befehl entgegen zu nehmen.

Ist es nicht möglich, die Antwort auszuwerten, sollte ein Detail von 50ms gewählt werden,

um sicher zu sein.

The motor have to process the command and then after done the command it feeds the echo. And till now I can actually send the new one. If I send it "too early", The motor won't buffer it at all...
Really pain in the ass. But anyway I got the point. That means I can really handle it now!

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy