How to communicate 2 numbers to arduino from PC

I want to control two servo's in real time from my PC. So I need the PC to tell the arduino the two integers to use to drive the servo's. It will need to do this quickly and it will need to be able to do it repeatedly. What is the best way to do this?

It seems like I should be able to just send the 8 bytes that make up the 2 integers over and over. As long as the starting point is established so you know which bytes go with which servo.

Is this a good approach? Is there a better approach?

It seems like I should be able to just send the 8 bytes that make up the 2 integers over and over.

For one thing, the number of bytes that make up a data type on the PC and the Arduino are not the same. An int on the PC is 4 bytes. On the Arduino, it is 2.

The Arduino has a long type that is 4 bytes, and matches an int on the PC.

But, think about the VALUE that you are wanting to send. Unless you have a "servo" that isn't really a servo, the value that you want to send is in the range of 0 to 179. That fits in a single byte. So, instead of needing to send 8 bytes, you really need to send just 2.

Is this a good approach?

Read what I wrote above, and them think about this. Serial data delivery is NOT guaranteed, Bytes can be lost, if a bit gets mangled, due to timing issues, noise (servos are electric motors, and generate noise) (noise is not necessarily something you can hear), and other reasons.

If you are sending s1, s2, s1, s2, s1, s2,..., think about that happens if you receive s1, s2, s1, s1, s2, s1,...

So, you might want to send some known value, that is not a valid servo position value (200 to 255, for instance), before or after each set of values. If the first, or third, value is not that value, the previous servo values are not valid, and you can ignore them and re-sync.

Hey Greengiant, I did a similar project last year. I have included a link to my forum posts, hope this helps. If you would like, I can send you my entire code if you can't decipher it from the forum posts

I would also be interested in this. This is how I do it but I think it is SO sloooow:

#include <Servo.h>

Servo Servo01;
Servo Servo02;

int Servo01_Degree = 90;
int Servo02_Degree = 90;

void setup() {
  Servo01.attach(9);
  Servo02.attach(10);
  MoveServo(Servo01, Servo01_Degree);
  MoveServo(Servo02, Servo02_Degree);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available()) {
    String sIncomingString;
    while (Serial.available()) {
      delay(1);
      sIncomingString += String(char(Serial.read()));
    }

    int intCommaPosition = sIncomingString.indexOf(",");

    if(intCommaPosition > -1) {
      String strDegree01 = sIncomingString.substring(0, intCommaPosition);
      String strDegree02 = sIncomingString.substring(intCommaPosition + 1);

      char cDegree01[strDegree01.length() + 1];
      char cDegree02[strDegree02.length() + 1];

      strDegree01.toCharArray(cDegree01, strDegree01.length() + 1);
      strDegree02.toCharArray(cDegree02, strDegree02.length() + 1);

      Servo01_Degree = atoi(cDegree01);
      Servo02_Degree = atoi(cDegree02);

      MoveServo(Servo01, Servo01_Degree);
      MoveServo(Servo02, Servo02_Degree);
    }
  }
}

void MoveServo(Servo objServo, int Degree) {
  if((Degree >=0) && (Degree <= 180)) {
    objServo.write(Degree);
  }
}

A detail has caught my attention:

void MoveServo(Servo objServo, int Degree) {

Shouldn't the first argument be a reference (or a pointer) ?

void MoveServo(Servo& objServo, int Degree) {

I guess it works anyway because the function-local copy objServo will act on the same hardware pin, but what happens is that for the entire duration of the function we have two Servo objects which act on the same hw resource, which from a theoretical point of view is not correct.

Does this sound right or did I just drink too much ? :slight_smile:

You are correct. Being a C# developer I do get lazy with that stuff. :slight_smile:

C++ really shows its age sometimes... :wink:

Below is some simple test code for two servos being sent commands in one serial string.

// zoomkat 12-13-11 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 1.0
// 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("two-servo-test-1.0"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(3);  //delay to allow buffer to fill 
    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 to serial monitor to see results
      Serial.println(servo2);

      int n1 = servo1.toInt();
      int n2 = servo2.toInt();
      
      myservo1.writeMicroseconds(n1); //set servo position 
      myservo2.writeMicroseconds(n2);
    readString="";
  } 
}

I like that stream handler better, I'm going to use it. Thanks.

zoomkat:

while (Serial.available()) {

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

PaulS:
But, think about the VALUE that you are wanting to send. Unless you have a "servo" that isn't really a servo, the value that you want to send is in the range of 0 to 179. That fits in a single byte. So, instead of needing to send 8 bytes, you really need to send just 2.

Thank you for pointing out the size differences of int. The 0 to 179 would fit into one byte however, I believe using the write() method as opposed to the writeMicroseconds would sacrifice a lot of resolution. If you use writeMicroseconds you can use a range of 1000 to 1600 theoretical discrete steps instead of 180.

Using an extra byte as an end of line signal is a good idea, but if you have to use multiple bytes to comprise your values, I am not sure how you could reliably detect it.

I think you could use a similar strategy by having the arduino send a single byte to the PC to signal its ready for the data and then the arduino could just sit around and wait for the appropriate amount of bytes to be received before continuing.