Robot hand using 16Channel Servo Shield

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
ms93
 
Posts: 3
Joined: Sat Mar 07, 2015 1:02 pm

Robot hand using 16Channel Servo Shield

Post by ms93 »

Hi,
I am currently working on a robot hand controlled wirelessly by flex sensors attached on a glove. I am using XBee Series 1 modules for communication. The other parts include:
Arduino UNO (x2)
Flex sensors (x21)
Sub Micro Servos (x15)
Standard torque servos (x3)
High torque servos (x3)
Adafruit 16 Channel servo shield (x2) (stacked)
Sparkfun Xbee Shield (x2)
Mux Shield II by Mayhew Labs (x1)
5V 10A Power Supply (x2) (one for each servo shield containing 10 & 11 servos each)

I have checked online but have found projects and solutions for robotic hand where each finger is actuated by one servo and hence, they are directly connected to the arduino. I am using individual servos for each joint and hence, my finger-to-shoulder robot arm contains 21 servos, 15 in the fingers itself. I am having trouble in controlling the servos as upto 5 can be controlled without much delay in transmission and actuation when connected directly to the board. But when i connect the same 5 motors using the servo shield, there is a considerable amount of delay and after working for about a minute or so, it suddenly stop responding just to work again few minutes later.

These are the codes I am using currently:

Flex sensors (transmission side):

Code: Select all

#include <MuxShield.h>
#define sfmin 680 //ShortFlex MIN
#define sfmax 830 //ShortFlex MAX
#define lfmin 485 //LongFlex MIN
#define lfmax 600 //LongFlex MAX

MuxShield muxShield;

void setup()
{
  // put your setup code here, to run once:
  muxShield.setMode(1, ANALOG_IN);
  // muxShield.setMode(2, ANALOG_IN);
  Serial.begin(9600);

}

int IO1AnalogVals[10];
int IO1servoposition[10];
//int IO2AnalogVals[16];
//int IO2servoposition[16];

void loop()
{
  for (int i = 0; i < 5; i++) //Analog read on all 5 inputs on IO1
  {
    IO1AnalogVals[i] = muxShield.analogReadMS(1, i);
    IO1servoposition[i] = map(IO1AnalogVals[i], sfmin, sfmax, 0, 180);
    IO1servoposition[i] = constrain(IO1servoposition[i], 0, 180);
  }
  /*for (int j = 6; j < 10; j++)
  {
    IO1AnalogVals[j] = muxShield.analogReadMS(1, j);
    IO1servoposition[j] = map(IO1AnalogVals[j], lfmin, lfmax, 0, 180);
    IO1servoposition[j] = constrain(IO1servoposition[j], 0, 180);
  }*/
  Serial.write("<");    // This character represent the beginning of the package of the five values
  for (int k = 0; k < 5; k++)
    Serial.write(IO1servoposition[k]);
  //for (int l = 0; l < 16; l++)
  //Serial.write(IO2servoposition[l]);
  delay(80);
}
5 Servos (receiving side):

Code: Select all

#include <Servo.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
//Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40);

#define SERVOMIN  175 // this is the 'minimum' pulse length count for sub micro servo (out of 4096)
#define SERVOMAX  595 // this is the 'maximum' pulse length count for sub micro servo (out of 4096)

byte startPackage;
double pulselen[5];
int angservo[5];

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

  pwm.begin();
  // pwm1.begin();

  pwm.setPWMFreq(60);
  //pwm1.setPWMFreq(120);

  delay(300);
}

void loop()
{
  if (Serial.available())
  {
    startPackage = Serial.read(); // The first value will be "<", the other are assigned to the finger
    for (int i = 0; i < 5; i++)
      angservo[i] = Serial.read(); //Read all values from 5 sensors

    if (startPackage == '<') // Verifying that the first value is "<"
    {
      for (int j = 0; j < 5; j++)
        pulselen[j] = map(angservo[j], 0, 180, SERVOMIN, SERVOMAX); //convert all values into pulse

      for (int k = 0; k < 5; k++) //send pulse to 5 motors on first board
      {
        pwm.setPWM(k, 0, pulselen[k]);
      }
    }
  }
  delay (80);
}
I have set both the Xbee Modules at 9600 baud using 'CoolRom' for Mac.

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Robot hand using 16Channel Servo Shield

Post by adafruit_support_bill »

You are going to have interrupt contention between the serial I/O and the i2c bus. That may result in dropped characters.

Having a fixed sync character '<' to mark the start of a packet is a good idea, but the implementation could be improved. As it is, you read 6 characters, and only use them if the first char is a '<'. If you do get out of sync, it may never be able to re-sync. A better approach is to read until you see the '<', then read the remaining 5 bytes.

User avatar
ms93
 
Posts: 3
Joined: Sat Mar 07, 2015 1:02 pm

Re: Robot hand using 16Channel Servo Shield

Post by ms93 »

I tried what you suggested and this is the code now for the receiving side (with the servos):

Code: Select all

#include <Servo.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41); // called this way, it uses the default address 0x40
//Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x40);

#define SERVOMIN  175 // this is the 'minimum' pulse length count for micro servo (out of 4096)
#define SERVOMAX  595 // this is the 'maximum' pulse length count for micro servo (out of 4096)

byte startPackage;
double pulselen[5];
int angservo[5];

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);

  pwm.begin();
  // pwm1.begin();

  pwm.setPWMFreq(60);
  //pwm1.setPWMFreq(120);

  delay(300);
}

void loop()
{
  if (Serial.available())
  {
    startPackage = Serial.read(); // The first value will be "<", the other are assigned to the finger
     //Read all values from 32 sensors

    if (startPackage == '<') // Verifying that the first value is "<"
    {
      for (int i = 0; i < 5; i++)
      angservo[i] = Serial.read();
      for (int j = 0; j < 5; j++)
        pulselen[j] = map(angservo[j], 0, 180, SERVOMIN, SERVOMAX); //convert all values into pulse

      for (int k = 0; k < 5; k++) //send pulse to 16 motors on first board
      {
        //if (angservo[k] != 255) // Sometimes the incoming value goes to 255, I couldn't discover yet the reason, so I simply excluded it when it happens. You can remove this line for every finger if you don't have this kind of problem
          pwm.setPWM(k, 0, pulselen[k]);
          Serial.println(k);
          Serial.print(" : ");
          Serial.print(pulselen[k]);
      }
      // for (int l = 16; l < 32; l++) //send pulse to 16 motors on second board
      //{
      //if (angservo[l] != 255)
      //pwm1.setPWM(l-16, 0, pulselen[l]);
      //}
    }
  }
  delay (80);
}
The problem we are facing now is that the servos do move properly though with some noticeable delay. Nevertheless, it works properly as long as we keep bending the flex sensors over and over again. If we do not move the sensors for about a minute i.e., if we keep the hand stable without any bends, the servos start behaving erratically. Then onwards, it takes approximately 10 seconds to respond to the sensors and the servo jitter increases as well.

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Robot hand using 16Channel Servo Shield

Post by adafruit_support_bill »

The problem we are facing now is that the servos do move properly though with some noticeable delay. Nevertheless, it works properly as long as we keep bending the flex sensors over and over again. If we do not move the sensors for about a minute i.e., if we keep the hand stable without any bends, the servos start behaving erratically. Then onwards, it takes approximately 10 seconds to respond to the sensors and the servo jitter increases as well.
Not sure what would cause that. What does the serial output look like when this occurs?

User avatar
ms93
 
Posts: 3
Joined: Sat Mar 07, 2015 1:02 pm

Re: Robot hand using 16Channel Servo Shield

Post by ms93 »

Like I mentioned before, this problem arises only when i connect the motors to the servo shield. If they are connected directly to the arduino, it works perfectly. Even the wireless communication works properly then. But since I have 21 servos to work with, I am forced to use the servo shield. Is there any way to use the digital.write() function we use normally to control the servos rather than using PWM signals? Or could you send me a sample code that will run atlas 5-10 servos on the servo shield at the same time? the example code I got with the servo shields runs the servos one after the other.

User avatar
adafruit_support_bill
 
Posts: 88097
Joined: Sat Feb 07, 2009 10:11 am

Re: Robot hand using 16Channel Servo Shield

Post by adafruit_support_bill »

Like I mentioned before, this problem arises only when i connect the motors to the servo shield.
Like I mentioned before, you are probably seeing interrupt contention between the serial I/O and the i2c bus. That may result in dropped characters.
What does the serial output look like when this occurs?

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”