Robot hand - Connecting three servo motors to three separate flex sensors

Hi, I'm a third year mech eng student with little experience with programming. My project involves making a robotic hand with each finger (just index, middle and thumb) controlled by a servo motor (a HS-5585MH). Each motor needs to respond to the flex of a bend sensor (a 2.2 flex sensor), one sensor per finger. I plan on making the motor start from an open hand position, move to a half-closed position following a slight twitch and move to fully closed when sensor fully bent. This also needs to work in reverse (closed to open). I am sure this can be all done on one arduino uno and have built a circuit using a 22k resistor for each sensor, but I do not know how to code this control system. Searching through topics, I have seen guides on one sensor moving one motor or one sensor to multiple motors but nothing on three sensors to three motors. Could anyone help me with a code I could use?

I'm not familiar with a 2.2 flex sensor (is it a variable resistor setup?), but you might start experimenting with the "knob" servo example.

Ok, simple.

  1. Do a serial print of the flex sensors, and record the data for when they are fully flexed, (to where you want it) and not flexed.(Hint, use the analog inputs).
  2. Use the Knob example to see the angles of which the fingers are fully open and closed.
  3. Once you have the data for each, use the map function to map the flex data to the required range for the servos.

Easy as 1,2,3.

looks like this is currently a popular project.

Thanks for all your help. I’m pretty sure ‘Lobby’ is on my course at the same uni doing this project. He seemed to be further ahead than me on the coding so I’ve essentially copied it - it seems to be along the same lines as the serial print of sensors and knob example combination previously suggested

// (set the Serial Monitor to 9600 baud)
#include <Servo.h> 
 
Servo middle,index,thumb;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
int posm = 0;    // variable to store the servo position 
int errorm = 0;
int esvm = 0;
int posi = 0;    // variable to store the servo position 
int errori = 0;
int esvi = 0;
int post = 0;    // variable to store the servo position 
int errort = 0;
int esvt = 0;


void setup()
{
  // initialize serial communications
  Serial.begin(9600); 

  middle.attach(7);  // attaches the servo on pin 9 to the servo object 
  index.attach(12);
  thumb.attach(8);  // attaches the servo on pin 9 to the servo object 
}

void loop()
{
  int sensor_index, degrees_index;
  int sensor_middle, degrees_middle;
  int sensor_thumb, degrees_thumb;
  
  
  // read the voltage from the voltage divider (sensor plus resistor)
  sensor_index= analogRead(1);
  sensor_index= analogRead(1);
  sensor_middle= analogRead(0);
  sensor_middle= analogRead(0);
  sensor_thumb= analogRead(2);
  sensor_thumb= analogRead(2);
  
  // convert the voltage reading to inches
  // the first two numbers are the sensor values for straight (768) and bent (853)
  // the second two numbers are the degree readings we'll map that to (0 to 90 degrees)
  degrees_index= map(sensor_index, 568,748, 0, 179);
  degrees_middle = map(sensor_middle, 568,748, 0, 179);
  degrees_thumb = map(sensor_thumb, 577,757, 0, 179);
  // note that the above numbers are ideal, your sensor's values will vary
  // to improve the accuracy, run the program, note your sensor's analog values
  // when it's straight and bent, and insert those values into the above function.
   
  // print out the result
  Serial.print("analog input0: ");
  Serial.print(sensor_middle,DEC);
  Serial.print("   degrees_middle: ");
  Serial.println(degrees_middle,DEC);
  Serial.print("   position_middle: ");
  Serial.println(posm,DEC);
  
  Serial.print("analog input1: ");
  Serial.print(sensor_index,DEC);
  Serial.print("   degrees_index: ");
  Serial.println(degrees_index,DEC);
  Serial.print("   position_index: ");
  Serial.println(posi,DEC);
  
  Serial.print("analog input2: ");
  Serial.print(sensor_thumb,DEC);
  Serial.print("   degrees_thumb: ");
  Serial.println(degrees_thumb,DEC);
  Serial.print("   position_thumb: ");
  Serial.println(post,DEC);
  
  // pause before taking the next reading
  delay(50);  
  
  int esvm=posm;
  int errorm= constrain(degrees_middle,0,180)-esvm;
  
   int esvi=posi;
  int errori= constrain(degrees_index,0,180)-esvi;
  
   int esvt=post;
  int errort= constrain(degrees_thumb,0,180)-esvt;
  
   
 if(errorm >=5)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree
 
    posm += 10; 
   } 
 
   else if(errorm <=-5)     // goes from 180 degrees to 0 degrees 
  {                                
    posm -= 10;
  } 
  
   else 
   
 {
   posm=posm;
 }
 

  if(errori >=5)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree
 
    posi += 10; 
   } 
 
   else if(errori <=-5)     // goes from 180 degrees to 0 degrees 
  {                                
    posi -= 10;
  } 
  
   else 
   
 {
   posi=posi;
 }
 
 
 if(errort >=5)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree
 
    post += 10; 
   } 
 
   else if(errort <=-5)     // goes from 180 degrees to 0 degrees 
  {                                
    post -= 10;
  } 
  
   else 
   
 {
   post=post;
 }
  
         // waits 15ms for the servo to reach the position 
    middle.write(posm);              // tell servo to go to position in variable 'pos' 
    delay(15);
    
    index.write(posi);              // tell servo to go to position in variable 'pos' 
    delay(15);       // waits 15ms for the servo to reach the position 
    
    thumb.write(post);              // tell servo to go to position in variable 'pos' 
    delay(15);       // waits 15ms for the servo to reach the position 
}

It works and I don’t seem to have the interference problem Lobby has but it does go a full 180 when I first twitch the sensor. It works perfectly after and then when I return the sensor to flat, the motor sweeps back again. Any idea why this is? And if there’s any other suggestions that might make it smoother that would also be appreciated but you have all been helpful so far

Did you do this part?

  // note that the above numbers are ideal, your sensor's values will vary
  // to improve the accuracy, run the program, note your sensor's analog values
  // when it's straight and bent, and insert those values into the above function.

I didn't write those actual words but I have followed what it says and calibrated my sensors - the numbers I have put in I believe are correct

I don't quite follow what esvm, errorm etc are for - you have more variables than I would expect to be needed for this problem and it's not clear from your variable names or your use of the variables what they are intended to represent.

You calculate degrees_middle etc as the target servo position, and that's fine. I assume your intent is to compare that to the servo's actual position, and move it in the right direction at regular intervals. You could achieve that just by reading the servo's current position and comparing it to your new target position - you don't need all those other intermediate variables.

Given that you are running essentially three copies of the same logic, it would be sensible to store your servos, pin numbers and state variables in arrays and use the same code to manage all three servos. This would reduce your development effort by a factor of three. If you aren't comfortable dealing with arrays and FOR loops yet, pull the code for a single servo out into a separate function and pass in the sensor pin number and the servo object. (All the other state information you currently keep can be replaced with temporary local variables - none of it needs to be global.) If you don't like either of those approaches to avoid code duplication and decide to stick with the current duplicated code I suggest you delete the code for two servos and get the first one working before you add the other two copies back in, otherwise you're going to spend three times as long editing the code as you need to, and risk introducing bugs at every change.

You initialise posm etc to zero but you don't actually move the servo to angle zero during setup. If it starts off a long way away from zero, you'd get a big transient at startup. Also, if the initial sensor input doesn't map to angle zero, you'll get a big transient when the servo jumps to the initial position of the sensor. You have print statements that ought to tell you whether this was happening, but we can't see what the output tells you or how this relates to the glitches you describe.

I'm pretty sure 'Lobby' is on my course at the same uni doing this project. He seemed to be further ahead than me on the coding so I've essentially copied it

So you won't be putting the usual own unaided work declaration at the front then?

Just curious if code like below would work with your flex sensors.

//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);
  myservo2.attach(4);
  myservo2.attach(5);
  myservo2.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("1- ");
    Serial.println(newval1); //print the new value for testing 
    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("2- ");    
    Serial.println(newval2);
    oldval2=newval2;
  }

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

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

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

Hi. I'm using the flex sensor and servo motor too, but the thing is that when I bend the flex sensor the servo motor turn anticlockwise instead of turn clockwise which I want it to be. I wondering is that the circuit problem or coding problem? If is coding problem, does it related to the map of the flex sensor?