Go Down

Topic: Sending Multiple Values to Arduino Through Serial (Read 101325 times) previous topic - next topic

Hunter235711

I just got my arduino and have really been enjoying it. However, I would like to control two servos through serial commands sent from Processing. I was wondering what the best way to send multiple values through a serial port to the arduino is. I would like to know if there is a "correct" or "proper" serial format for sending this type of data while avoiding errors. Thanks for your help and Merry Christmas!

MikMo

There really is no "one correct way" of doing it.

One often used way to do it is to prefix the values with a letter or something so your Arduino code can distinguish the commands to each servo. something like:

S1data for servo1 here, S2data for servo 2 here.

S1 and S2 are just examples you could use any chars that would uniquely identify your commands for instance A and B.

This requires a bit of string fiddeling on the Arduino side, but i you snoop around the forums here you should be able to find almost exactly what you are after.

PaulS

To expand on what MikMo said, there are two ways to send data through the serial port - as strings and as bytes.

For a servo, where the position is an angle in the range 0 to 179, the values fit in a byte. so you could send two bytes, and not have to do int to string conversion in Processing. You would also not have to collect the characters into an array on the Arduino, keeping it NULL terminated, and convert the string back to an int.

Sending one value this way requires 1 byte. Sending it as a string requires 1, 2, or 3 bytes ("9", "19", "109").

If the data being sent can not fit in a byte, then conversion to string and back is generally easier to understand than sending the value as multiple bytes and reassembling them on the Arduino.

Some things to keep in mind. Serial transmission is relatively slow. Expecting, in one pass through loop, to collect an entire packet is not a reasonable assumption to make. Therefore, start and end of packet markers make it a lot easier to know where in the byte stream a packet starts and ends.

Also, serial data delivery follows the same guarantee model that the US postal service uses. The system guarantees that it will try to deliver each and every byte. It does not guarantee that it will deliver each and every byte.

So, you must prepare to deal with content loss.

Do you need to send data for both servos every time you send data for one servo? If so, one approach will work (servo 1 data followed by servo 2 data, with, possibly, a delimiter in between). If not, a different approach is needed (which servo is the data for?).

Hunter235711

Thank you so much for your helpful replies! What you two said makes sense to me. However, there are still a few things I am unsure about.

1. What is the difference between sending a string and a byte over serial? Are they both sent in the same format with the string just being several bytes followed by a linefeed ('\n')? Also, would the arduino be able to tell whether it was being sent a string or just a series of bytes over serial by Processing?

2. The first thing I thought of doing was having Processing write 'A', then servo A value, then servo B value.

  while (Serial.available() > 2){
  serialRead = Serial.read();
   if (serialRead == 'A'){
     servoAVal = Serial.read();
     servoBVal = Serial.read();
      }
   }
   

But since PaulS said that it is not reasonable to expect to collect an entire packet in one loop, would it be better to have Processing write 'A', then servo A value, then 'B', then servo B value and use the following code?

  while (Serial.available() > 0){
  serialRead = Serial.read();
   if (serialRead == 'A'){
     servoAVal = Serial.read();
   }
   if (serialRead == 'B'){
     servoBVal = Serial.read();
   }
}

3. Lastly, if the data for servo A or B was an integer, would I need to convert it to a byte using byte(data for servo A or B) before sending it to the arduino over serial?

Thank you so much!
   

PaulS

Quote
1. What is the difference between sending a string and a byte over serial? Are they both sent in the same format with the string just being several bytes followed by a linefeed ('\n')? Also, would the arduino be able to tell whether it was being sent a string or just a series of bytes over serial by Processing?

If you send a value like 129 as a byte, 8 bits of data are sent. If you send it as a string, 8 bits of data are sent to send the '1', then another 8 bits to send the '2', and, finally, 8 more bits to send the '9'.

No linefeed is sent, unless you explicitly send one.

No, the Arduino can not tell whether the data is a string or a byte. That is the purpose of a protocol. A protocol is an agreement as to how two computers will communicate - using bytes or using strings is a small part of the protocol.

Quote
2. The first thing I thought of doing was having Processing write 'A', then servo A value, then servo B value.

If you are always going to write two bytes for the two servos, the 'A' is unnecessary.

Quote
3. Lastly, if the data for servo A or B was an integer, would I need to convert it to a byte using byte(data for servo A or B) before sending it to the arduino over serial?

Convert isn't really the correct term. Cast is. You need to cast the int to a byte in order to have Processing NOT convert the value to a string.

Code: [Select]
myPort.write([glow](byte)[/glow]servoAval);

zoomkat

Some simple code I use for testing two servos using the serial monitor.

Code: [Select]

// zoomkat 11-22-10 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 0019 and later
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550

#include <Servo.h>
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo
Servo myservo2;

void setup() {
 Serial.begin(9600);
 myservo1.attach(6);  //the pin for the servo control
 myservo2.attach(7);
 Serial.println("servo-test-21"); // so I can keep track of what is loaded
}

void loop() {

 while (Serial.available()) {
   delay(10);  
   if (Serial.available() >0) {
     char c = Serial.read();  //gets one byte from serial buffer
     readString += c; //makes the string readString
   }
 }

 if (readString.length() >0) {
     Serial.println(readString); //see what was received
     
     // expect a string like 07002100 containing the two servo positions      
     servo1 = readString.substring(0, 4); //get the first four characters
     servo2 = readString.substring(4, 8); //get the next four characters
     
     Serial.println(servo1);  //print ot serial monitor to see results
     Serial.println(servo2);
     
     int n1; //declare as number  
     int n2;
     
     char carray1[6]; //magic needed to convert string to a number
     servo1.toCharArray(carray1, sizeof(carray1));
     n1 = atoi(carray1);
     
     char carray2[6];
     servo2.toCharArray(carray2, sizeof(carray2));
     n2 = atoi(carray2);
     
     myservo1.writeMicroseconds(n1); //set servo position
     myservo2.writeMicroseconds(n2);
   readString="";
 }
}
Google forum search: Use Google Search box in upper right side of this page.
Why I like my 2005 Rio Yellow Honda S2000  https://www.youtube.com/watch?v=pWjMvrkUqX0

Hunter235711

Thank you for your help! I don't think that I have a really good understanding of how this all works. I tried to use the code provided by zoomkat and I thought that I could use the following program in Processing to try it out.
Code: [Select]


import processing.serial.*;
Serial port;
String n1;
String n2;
String sending;

void setup() {
 size(256, 256);
 
 println("Available serial ports:");
 println(Serial.list());
 port = new Serial(this, Serial.list()[1], 9600);
 
}

void draw(){
 //draw black to white gradient
 
 for (int i=0; i < 256; i++) {
   stroke(i);
   line(i, 0, i, 256);
 }
 
 // write x-position and y-position of the mouse
 n1 = Integer.toString(mouseX);
 n2 = Integer.toString(mouseY);
 
 // if n1 or n2 is less than 4 digits add a zero to the front of them.
  while (n1.length() < 4){
    n1 = '0' + n1;
  }
  while (n2.length() < 4){
    n2 = '0' + n2;
  }
 
  //combine the two 4 digit long strings into one 8 digit long one
 
  sending = n1 + n2;
 
  //write this to the serial port.
  port.write(sending);

}


I tried to make the program get the x and y position of the mouse, add on any needed 0's to make the string the right length, and then send it to the arduino. However, this did not seem to work.

PaulS

#7
Dec 30, 2010, 01:36 am Last Edit: Dec 30, 2010, 01:37 am by PaulS Reason: 1
Quote
However, this did not seem to work.

What did the string look like in Processing before it was written to the serial port?

There is a method, serialEvent, that can be overwritten in the Processing application. It gets called whenever serial data arrives. Put something like this in your Processing application:
Code: [Select]
void serialEvent(Serial myPort)
{
 // read the serial buffer:
 String myString = myPort.readStringUntil('\n');
 println(myString);
}


Then, add Serial.println() statements in the Arduino code, to send data back to the processing application, to echo what the Arduino received.

What do you see shown in the Processing IDE window?

By the way, that Arduino code is not expecting angle values. If that is what you are sending, you need to modify the Arduino code to expect angles, or modify the Processing application to send microSecond values.

Hunter235711

Thank you all! I finally got it working! I added the serialEvent method like PaulS said and no values that made any sense were being returned. I played around with it a bit and realized that if I added a 250 millisecond delay to the processing code it seemed to work correctly. I guess that the data was being sent to the arduino faster than the time it took for the arduino code to be executed. In any case it is now working great. I taped two servos together and attached a laser pointer. The Processing code takes the x and y position of the mouse pointer and sends it to the arduino to point the laser.

PaulS

Quote
The Processing code takes the x and y position of the mouse pointer and sends it to the arduino to point the laser.

Cool. So, now you can draw pictures? Draw the Arduino logo and take a picture, please.

Hunter235711

Well, it is sort of tough to draw anything with it, even though it does have a super sturdy duct tape mount! Since I put in that quarter second delay it is a little bit jumpy as it tries to follow the mouse pointer. Here is a picture of the servos, the breadboard I used to connect them to a 5v power supply, and the arduino.



Happy New Year!

Go Up