Arduino to Arduino Serial Servo control

Greetings Arduino Community.
I've been struggling with communication between my 2 arduinos.
The end goal is to have 1 arduino with a number of potentiometers to send the values to another arduino with servos attached, and to have the servos move acording to the potentiometer values.
I would like to accomplish this with bluetooth, however while waiting for the bluetooth modules to arrive I would like to accomplish this by connecting the TX/RX of the 2 arduinos. As I understand that the bluetooth modules will be communicated to with the same TX/RX ports.

I have had no luck in getting this communication to work.
I am aware that the TX on one arduino connects to the RX of the other, and vice-versa.
The potentiometers I am using are flex sensors through a voltage divider, which produce values in the range of 0-1023.

I have spent hours, if not days trying to find a tutorial or example that can accomplish this.
I am very new to the arduino world, however I do have experience with electronics and computing in general, as well as some rudimentary coding skills. Unfortunately I feel like I am missing a key component to achieving this.

I am using pinA0 on arduino1 for the flex sensor, and pin9 on Arduino2 for the PWM signal to the servo. While I was attempting this previously using softwareSerial, I have found an external Power supply so I can use the standard TX/RX pins. (I am aware that with the USB connected to the computer, the normal TX/RX pins cannot be used, hence my attempt with softwareSerial)

Any assistance in this would be greatly appreciated. :slight_smile:

Unfortunately I feel like I am missing a key component to achieving this.

You might have some code ofr us to look at. If you do, you forgot to post it.

You did connect the grounds, too, right?

I’m hoping that this is going to post the code, I couldn’t find a “code” button on here.
This is part of my initial code which operates the flex sensor and the servo connected to one arduino.
There is also a calibration portion to set the high and low values of the flex sensor.

To separate them I was attempting to split the code up and use the serial.read / serial.write to communicate it.

I’m afraid my code will show just how much of a rookie I am at this.

Also yes, I did have the grounds connected

calibrate-flex-glove.ino (1.54 KB)

servo-serial-move-NEW.ino (1.58 KB)

calibrate-flex-to-serial-NEW.ino (1.2 KB)

found the code button :confused:
This is the arduino with the flex sensor

//initialize flex sensor input
int flexPin1 = A0;
//set contraints for high and low flex sensor values
int sensorValue;
//variable for low calibration value
int sensorLow = 1023;
//variable for high calibration value
int sensorHigh = 0;
//intialize Calibration Active LED
const int ledPin = 12;


void setup()
  // calibrate for the first five seconds after program runs
 {
   
     pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  
  while (millis() < 5000) {
    // record the maximum sensor value
    sensorValue = analogRead(A0);
    if (sensorValue > sensorHigh) {
      sensorHigh = sensorValue;
    }
    // record the minimum sensor value
    if (sensorValue < sensorLow) {
      sensorLow = sensorValue;
    }
  }
    digitalWrite(ledPin, LOW);
  // Open serial communications and wait for port to open:
  Serial.begin(4800);   //data rate for softserial port
  //Set each flex sensor pin to input: this is necessary
  pinMode(flexPin1, INPUT);
}

void loop()
{
  //Defines analog input variables
  int sensorValue = analogRead(flexPin1);
    Serial.println(analogRead(sensorValue));
 
}

This is the arduino with the servo

#include <Servo.h> //Includes servo library

Servo finger1;

int servoPin1 = 9;
int sensorLow = 1023;
int sensorHigh = 0;
int flexPin1 = A0;
int sensorValue;

void setup()
  // calibrate for the first five seconds after program runs
 {
   
  //Attach the servo objects to their respective pins
  finger1.attach(servoPin1);
  
  /* set each servo pin to output; I'm not acutally sure if this is
  even necessary, but I did just in case it is */
  pinMode(servoPin1, OUTPUT);
 
  Serial.begin(4800);
  
  int sensorValue; // = serialRead(flexPin1);
}

void loop()
{

 // int mySerial;
  //int pos1 = 0;
  //Defines analog input variables

  if (Serial.available()>0) 
    sensorValue = Serial.read();
      
  int pos1 = map(sensorValue, sensorLow, sensorHigh, 10, 170);
  pos1 = constrain(pos1, 10, 170);
  
  //Tells servos to move by the amount specified in the "pos" variables
  finger1.write(pos1);
}

Your problem is that print and println send out things in ascii. SO a value of 345 would be sent as three characters, a 3, a 4 and then a 5. And they'll be ascii, so what you'll receive will be the numbers 51, 52 and 53.

There are three options. You can scale the 10 bit value you get from analogRead to 0 - 255 so it fits in a byte so you can send the raw value with Serial.write. You could break the 10 bit value you get from analogRead into two bytes and send them both as raw values with Serial.write and then reassemble them on the receiver back into a two byte number. Or you can continue to send them as ascii, read all of them and use atoi to turn them back into an integer value.

You may be interested in the examples in Serial Input Basics - simple and reliable ways to receive data. The 3rd example will be the most reliable.

...R

  //Set each flex sensor pin to input: this is necessary
  pinMode(flexPin1, INPUT);

Not for analog pins. They are input only. This is diddling with stuff you don’t want diddled with.

int sensorLow = 1023;
int sensorHigh = 0;

On the receiver, those are useless values. They are not at all what the sender uses as the limits.

  // calibrate for the first five seconds after program runs

Useless comments really do need to relate to the code that the comment is near.

  /* set each servo pin to output; I'm not acutally sure if this is
  even necessary, but I did just in case it is */
  pinMode(servoPin1, OUTPUT);

If it is necessary (it is), don’t you think that the Servo library would handle that?

  if (Serial.available()>0)
    sensorValue = Serial.read();
     
  int pos1 = map(sensorValue, sensorLow, sensorHigh, 10, 170);

As the others have pointed out, this is not reading all of what you sent. Serial.parseInt() would.

You may want to design your receiving code first, then make the sending code to fit the receiving code. Below is some sending test code for a future wireless servo arm project. The sending code gets the pot value, converts to a servo command value, adds a servo identifier, and finishes with an end of data marker. The packet is sent out the serial tx and can be observed using the serial monitor. The code also has a dead band component to only send the data when there has been a significant change. Servos can be be controlled using the sending arduino for testing. The receiving code captures a data packet, looks for the servo identifier, and converts the numeric value into an integer for use as a servo command. The serial monitor can be used to do testing with the receiving code. This is just one approach, so YMMV.

//zoomkat multi pot/servo test 3-23-13
//includes dead band for testing and limit servo hunting
//view output using the serial monitor

#include <Servo.h> 
Servo myservo1;  //declare servos
Servo myservo2;
Servo myservo3;
Servo myservo4;
Servo myservo5;

int potpin1 = 0;  //analog input pin A0
int potpin2 = 1;
int potpin3 = 2;
int potpin4 = 3;
int potpin5 = 4;

int newval1, oldval1;  //pot input values
int newval2, oldval2;
int newval3, oldval3;
int newval4, oldval4;
int newval5, oldval5;

void setup() 
{
  Serial.begin(9600);  
  myservo1.attach(2);  
  myservo2.attach(3);
  myservo3.attach(4);
  myservo4.attach(5);
  myservo5.attach(6);
  Serial.println("testing multi pot servo");  
}

void loop()
{ 
  newval1 = analogRead(potpin1);           
  newval1 = map(newval1, 0, 1023, 0, 179); 
  if (newval1 < (oldval1-2) || newval1 > (oldval1+2)){ //dead band 
    myservo1.write(newval1); //position the servo
    Serial.print(newval1); //print the new value for testing 
    Serial.print("a,");
    oldval1=newval1; //set the current old value
  }

  newval2 = analogRead(potpin2);
  newval2 = map(newval2, 0, 1023, 0, 179);
  if (newval2 < (oldval2-2) || newval2 > (oldval2+2)){  
    myservo2.write(newval2);
    Serial.print(newval2);
    Serial.print("b,");
    oldval2=newval2;
  }

  newval3 = analogRead(potpin3);           
  newval3 = map(newval3, 0, 1023, 0, 179); 
  if (newval1 < (oldval3-2) || newval3 > (oldval3+2)){  
    myservo1.write(newval3);
    Serial.print(newval3);
    Serial.print("c,");
    oldval3=newval3;
  }

  newval4 = analogRead(potpin4);           
  newval4 = map(newval4, 0, 1023, 0, 179); 
  if (newval1 < (oldval4-2) || newval4 > (oldval4+2)){  
    myservo1.write(newval4);
    Serial.print(newval4);
    Serial.print("d,");
    oldval4=newval4;
  }

  newval5 = analogRead(potpin5);           
  newval5 = map(newval5, 0, 1023, 0, 179); 
  if (newval5 < (oldval5-2) || newval5 > (oldval5+2)){  
    myservo1.write(newval5);
    Serial.print(newval5);
    Serial.print("e,");
    oldval5=newval5;
  } 
  delay(50);  //to slow loop for testing, adjust as needed
}

rx

//zoomkat 11-22-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
//multi servos added 
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h> 
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);

  //myservoa.writeMicroseconds(1500); //set initial servo position if desired

  myservoa.attach(6);  //the pin for the servoa control
  myservob.attach(7);  //the pin for the servob control
  myservoc.attach(8);  //the pin for the servoc control
  myservod.attach(9);  //the pin for the servod control 
  Serial.println("multi-servo-delimit-test-dual-input-11-22-12"); // so I can keep track of what is loaded
}

void loop() {

  //expect single strings like 700a, or 1500c, or 2000d,
  //or like 30c, or 90a, or 180d,
  //or combined like 30c,180b,70a,120d,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >1) {
        Serial.println(readString); //prints string to serial port out

        int n = readString.toInt();  //convert readString into a number

        // auto select appropriate value, copied from someone elses code.
        if(n >= 500)
        {
          Serial.print("writing Microseconds: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf('b') >0) myservob.writeMicroseconds(n);
          if(readString.indexOf('c') >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf('d') >0) myservod.writeMicroseconds(n);
        }
        else
        {   
          Serial.print("writing Angle: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.write(n);
          if(readString.indexOf('b') >0) myservob.write(n);
          if(readString.indexOf('c') >0) myservoc.write(n);
          if(readString.indexOf('d') >0) myservod.write(n);
        }
         readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

Thank you so much everyone for your assistance, I just got it working.
I tried so many examples and bits of code.

Having had it working on a Mega with all inputs and outputs local, when I attempted to split up the code I feel I made a number of rookie mistakes.

Thanks to your assistance and a fair bit of trial and error, I came up with this code which seems to work for 2 inputs and 2 outputs
Tomorrow I will see if I can add the other 9 inputs and outputs as well.
After I get that working, Bluetooth communication will be next on the list :slight_smile:

P.S. I am building a Sensor Glove using Flex Sensors, and a robotic hand in the shape of a human hand, hence the higher number of inputs and outputs. The glove will be powerwed with a 9V battery, the robotic hand will be powered via an ATX power supply. 12V to the VIN for the arduino, and the 5V 26A rail to power the servos.

Glove Code

//Define sensors and calibrate on start up
//send to other arduino using serial com

//initialize flex sensor input
const int flexPin1 = A1;
const int flexPin2 = A2;

//set contraints for high and low flex sensor values
int sensorValue1;
int sensorValue2;

//variable for low calibration value
int sensorLow1 = 1023;
int sensorLow2 = 1023;

//variable for high calibration value
int sensorHigh1 = 0;
int sensorHigh2 = 0;

//intialize Calibration Active LED
const int ledPin = 12;

void setup()

 {
//Turn on Calibration LED
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  
// calibrate for the first five seconds after program runs
  while (millis() < 5000) {
    // record the maximum sensor value - duplicate for all sensors
    sensorValue1 = analogRead(flexPin1);
    if (sensorValue1 > sensorHigh1)    {
      sensorHigh1 = sensorValue1;    }
    // record the minimum sensor value - duplicate for all sensors
    if (sensorValue1 < sensorLow1)    {
      sensorLow1 = sensorValue1;    }
    
    sensorValue2 = analogRead(flexPin2);
    if (sensorValue2 > sensorHigh2)    {
      sensorHigh2 = sensorValue2;    }
    if (sensorValue2 < sensorLow2)    {
      sensorLow2 = sensorValue2;    }
  }

// turn off calibration LED
    digitalWrite(ledPin, LOW);

// Open serial communications and wait for port to open:
  Serial.begin(9600);   //data rate for serial port
  
}

void loop()
{
  // read the sensor 1:
  sensorValue1 = analogRead(flexPin1);
  // apply the calibration to the sensor reading
  sensorValue1 = map(sensorValue1, sensorLow1, sensorHigh1, 0, 255);
  // constrain sensor value to servo limits
  sensorValue1 = constrain(sensorValue1, 1, 179);   
  
  // read and calibrate sensor 2:
  sensorValue2 = analogRead(flexPin2);
  // apply the calibration to the sensor reading
  sensorValue2 = map(sensorValue2, sensorLow2, sensorHigh2, 0, 255);
  // constrain sensor value to servo limits
  sensorValue2 = constrain(sensorValue2, 1, 179);   
  

  //gets analog input value and prints to serial comm
  Serial.print(sensorValue1);
  Serial.print(",");              // value separator
  Serial.print(sensorValue2);     // gets analog input value and prints to serial comm
  Serial.println("M");            // M for Move, declares end of string on receiver

}

Robotic Hand Code - Adapted from the Read ASCII Tutorial

#include <Servo.h>  //Includes Servo Library

// declare servos
Servo finger1;
Servo finger2;

// Pins for Servos:
int servo1 = 9;
int servo2 = 10;

void setup() {

//attach servos  
finger1.attach(servo1);
finger2.attach(servo2);  

  // initialize serial:
  Serial.begin(9600);
  // make the pins outputs:
  pinMode(servo1, OUTPUT);
  pinMode(servo2, OUTPUT);
//  pinMode(bluePin, OUTPUT);

}

void loop() {
  // if there's any serial available, read it:
  while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:
    int red = Serial.parseInt();
    // do it again:
    int green = Serial.parseInt();

    // Look for "M" to end the string
    if (Serial.read() == 'M') {
      
      // constrain the values to 1 - 179 
      red = constrain(red, 1, 179);
      green = constrain(green, 1, 179);
//      blue = 255 - constrain(blue, 0, 255);

      finger1.write(red);
      finger2.write(green);

   // print the two numbers for debugging
//      Serial.print(red);
//      Serial.print(",");
//      Serial.println(green);
    }
  }
}

The glove will be powerwed with a 9V battery

It will last a lot longer between battery changes if you power it with 4 AA batteries.

PaulS:
It will last a lot longer between battery changes if you power it with 4 AA batteries.

Very good point, however the added weight and size of 4 AA batteries would necessitate an alternative method of mounting.

For the Glove I am using an Arduino Micro, with 2 custom circuit boards attached to the headers. The 9 volt battery fits very nicely in the space this provides.

This project is part of my final Technical Report, as such the whole unit only needs to operate for a period of less than 20 minutes, so power drain at this time is not a factor.

Very solid advice however for when I continue on past just the hand itself. Thank you! :slight_smile: