Created Sat, 25 Jan 2014 14:36:41 +0000 by vertigo5
Sat, 25 Jan 2014 14:36:41 +0000
hi Everybody!
I'm trying to get my UNO32 to receive three values (integers between 0-100) from processing, around 20 times a second (possibly faster).
The values are formatted in messages like this, each ending with a new line: 34,59,99\n 55,19,86\n 12,52,25\n
I previously used this piece of code with my Arduino Uno, however, this doesn't compile anymore because of the parseInt() method:
while (Serial.available() > 0) {
// look for the next valid integer
int stepperGoal1 = Serial.parseInt);
int stepperGoal2 = Serial.parseInt();
int stepperGoal3 = Serial.parseInt();
// look for the newline.
if (Serial.read() == '\n') {
// do stuff with values here
} }
I already found out from an old post here that I need to:
"read your data into a character array and then use atoi() to convert it into an integer".
But I'm not sure exactly how to implement that, so I was hoping I can get a bit more details. (I only have experience with programming in Processing).
I'm also open for tips or ideas about re-structuring this whole communication protocol, including the message format sent from Processing.
Thanks!
Sat, 25 Jan 2014 22:57:02 +0000
The proper method is all detailed here:
[url]http://hacking.majenko.co.uk/reading-serial-on-the-arduino[/url]
You just need to then pass the buffer into atoi to get an integer out of it - or use something like sscanf() to parse the string into values.
Sun, 26 Jan 2014 16:19:21 +0000
Thanks! That's exactly the kind of information I was looking for.
However, I'm still trying to solve two problems:
I used the same readline() function as in the tutorial, and adapted the code to my three comma seperated values:
static char buffer[80];
if (readline(Serial.read(), buffer, 80) > 0) {
// for debugging
Serial.print("received message: <");
Serial.print(buffer);
Serial.println(">");
// parse values
sscanf(buffer, "%d,%d,%d", &stepperGoal1, &stepperGoal2, &stepperGoal3);
// for debugging
Serial.println("parsed values: ");
Serial.println(stepperGoal1);
Serial.println(stepperGoal2);
Serial.println(stepperGoal3);
// do stuff with values here
}
When I open the serial monitor and type in three integers formatted like this (with both "NL" and "CR" mode selected) - Everything works as expected:
"11,22,33"
The two problems are:
The UNO32 responds to the messages only after around 20 secs, and after attempting to send messages 4-5 times with no reaction first.
When sending the exact same (I think) message from Processing, I get no response. LD1 blinks whenever I send information, so it seems the Serial connection is working.
This is the code on the Processing side, running 1 time a second:
myPort.write(str(stepperBack));
myPort.write(",");
myPort.write(str(stepperFrontLeft));
myPort.write(",");
myPort.write(str(stepperFrontRight));
myPort.write("\n");
myPort.write("\r");
Any tips or hints would be very appreciated!
Thanks, Eran.
Sun, 26 Jan 2014 21:52:17 +0000
Eran,
I'm not certain, but your first problem (UNO32 only responding after 20s) may be caused by your terminal emulator not sending out any bytes until either a line ending has been typed on the keyboard, or a timeout (no characters have been typed) occurs (and thus the 20 seconds). Can you confirm that the same behavior occurs when you use this same code on the Arduino? My guess is that it will.
If you are using TeraTerm (as I do) then there is a setting called EnableLineMode=off and you want to make sure it is set to off. (It's in the TERATERM.INI file)
As far as why your processing code doesn't seem to work the same as typing, you will need to do some further debugging. Does it work properly (with the same code) on Arduino? Is there a way you can monitor the serial data as it's going between the PC and the UNO32? (Like using a serial sniffer or logic analyzer)? Is there a simpler way you can set up your code just to prove functionality? For example, have processing send just one character. Then on the UNO32, have it light an LED when it gets any character. Once that works, then start building up your strings and string processing and see where things stop working. That will tell you where the problem is.
*Brian
Sun, 26 Jan 2014 23:08:53 +0000
Is there a way you can monitor the serial data as it's going between the PC and the UNO32? (Like using a serial sniffer or logic analyzer)?
Cool! Already found (at least the first) big error I made. I found a free serial sniffer on (http://freeserialanalyzer.com/). This tool really makes the whole difference in debugging serial communication. I found out that when I thought processing was sending out "67,67,67\n\r" what it actually sent was this:
2C 43 2C 43 0A 0D
Which I discovered is indeed "67,67,67\n\r" in Hexadecimal ASCII code. So I think that explains why I got no response. Tomorrow I will dig deeper into the correct translation and communication protocol I need for this. These two links look promising:
http://arduinobasics.blogspot.de/2012/07/arduino-basics-simple-arduino-serial.html
http://www.fiz-ix.com/2012/11/arduino-serial-communication-bytes-bases-and-ascii-characters/
Is there a simpler way you can set up your code just to prove functionality? For example, have processing send just one character. Then on the UNO32, have it light an LED when it gets any character. Once that works, then start building up your strings and string processing and see where things stop working. That will tell you where the problem is.
That will definitely be my strategy for tomorrow...
Great stuff! Thanks for all your help!
Mon, 27 Jan 2014 18:49:22 +0000
Eran & Brian -- I'm not trying to hijack this thread, but is there a way, or can any of the serial sniffers "see" comms between the chipKIT/Arduino's RX/TX and a device connected to them?
E.g. is there any way to see that serial communication, which isn't the serial over USB between the µproc and the computer?
I'm using an LCD from 4D Systems, with their adapter shield, which (for most boards) needs to use 0/1 for serial comms. I'd like to "see" what's going over that connection between the µproc and LCD, from my computer's USB port, but so far I haven't been able to find a way. The normal terminal window can't be opened because it also uses 0/1.
--Jon
Mon, 27 Jan 2014 19:49:50 +0000
Get a pair of el-cheapo USB to TTL serial adapters. Connect the RX of one to the RX line of the chipKIT. Connect the RX line of the other to the TX line of the chipKIT. You don't use the TX lines of either adapter.
Open two serial terminals, one for each adapter, and you have yourself a cheap full duplex serial sniffer.
Mon, 27 Jan 2014 22:00:56 +0000
Soooooooo... here's an update about what I've got so far:
After following Brian's suggestion to build things from the ground up, I managed to get the UNO32 to receive one value consistently :D . I used a call & response protocol with Processing (based on the example from the Arduino IDE).
I then went on to try and send three values to the UNO32 (my goal for this project). I managed to get the values to be correctly received about 80% of the time, but I'm still getting some non-valid values. I'm aware that it is hard to get a perfectly consistent serial communication, but I would be happy to get some tips about improving this code and making it more efficient and reliable.
I'm especially unsure about the use of Serial.flush() in the UNO32 code and the myPort.clear() in the Processing code.
UNO32 Code:
char controlChar;
int inValue1 = 0;
int inValue2 = 0;
int inValue3 = 0;
void setup()
{ Serial.begin(9600);
// send a byte to establish contact until receiver responds
establishContact();
}
void loop()
{
if (Serial.available() > 0) {
controlChar = Serial.read();
if (controlChar == 'X') {
inValue1 = Serial.read();
inValue2 = Serial.read();
inValue3 = Serial.read();
//for debugging
Serial.print(inValue1);
Serial.print(inValue2);
Serial.print(inValue3);
}
else Serial.flush();
delay(30);
}
Serial.print('B'); // send a capital B to get more values
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.print('A'); // send a capital A
delay(300);
}
}
Processing Code:
import processing.serial.*;
// serial port to arduino
Serial myPort;
boolean firstContact = false;
// randoms values for testing
int value1 = 11;
int value2 = 22;
int value3 = 33;
char controlChar = 'X';
void setup() {
size(100, 100);
background(255);
println(Serial.list());
myPort = new Serial(this, Serial.list()[1], 9600);
}
void draw() {
}
void serialEvent(Serial myPort) {
// read a byte from the serial port:
int inByte = myPort.read();
// if it's A it's the first contact from the microcontroller
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
// send first batch of values
myPort.write(controlChar);
myPort.write(value1);
myPort.write(value2);
myPort.write(value3);
}
}
// if it's B, send more values
else if (inByte == 'B') {
myPort.write(controlChar);
myPort.write(value1);
myPort.write(value2);
myPort.write(value3);
}
// if it's anything else, ignore
else myPort.clear();
}
and finally, here is a sample of what the UNO32 is printing out: (I have no idea where those -1 values are coming from)
B112233 B112233 B112233 B112233 B112233 B112233 BB BBBBBBBBBB-1-1-1 B112233 B112233
Thanks!!! Eran.
Mon, 27 Jan 2014 22:08:44 +0000
-1 is returned by read() when there is nothing to read.
if (Serial.available() > 0) {
controlChar = Serial.read();
if (controlChar == 'X') {
inValue1 = Serial.read();
inValue2 = Serial.read();
inValue3 = Serial.read();
If there is 1 or more character available(>0) then read 4 characters. What if there's only 3 characters in the buffer, or 2, or more than likely, just the one? The three inValueX read's will return -1.
Mon, 27 Jan 2014 22:32:12 +0000
Aha! That makes things much more clear.
I changed the UNO32 loop code to this, and the non-valid values are gone :)
void loop()
{
if (Serial.available() == 4) {
controlChar = Serial.read();
if (controlChar == 'X') {
inValue1 = Serial.read();
inValue2 = Serial.read();
inValue3 = Serial.read();
//for debugging
Serial.print(inValue1);
Serial.print(inValue2);
Serial.print(inValue3);
}
else Serial.flush();
}
// send a capital B to get more values
Serial.print('B');
delay(50);
}
Thanks!!!! Now I'm one step closer to getting my project working. Will update when I have more results... Eran.
Mon, 27 Jan 2014 22:47:51 +0000
Close...
if (Serial.available() == 4) {
What if there are 5? You can still read 4 and leave one behind for the next time...
Tue, 28 Jan 2014 08:59:14 +0000
Oh yeah, true. That if (Serial.available() == 4) did seem too specific to me, but I wasn't sure what to do with the other bytes if I get more than 4 in the buffer. Didn't realize that they'll still be there waiting by the next loop... Thanks for the correction!
Sun, 09 Feb 2014 18:48:30 +0000
Aha! That makes things much more clear. I changed the UNO32 loop code to this, and the non-valid values are gone :)
void loop()
{
if (Serial.available() == 4) {
controlChar = Serial.read();
It's probably not a great idea to check for exactly 4 characters either. If something in your loop slows it down there could be a chance that you skip right over the Serial.available() == 4 and then you never parse again until you overflow the serial buffer. Instead, check for Serial.available() >= 4.
Also, if you send the values from Processing as zero padded hex values then you will know the exact length of the string you are sending for example:
B012345\r\n
Then you can check for Serial.available() >= 9. When at least 9 characters are in the serial buffer then you can parse your data with little fear.
Jacob