Go Down

Topic: PWM Servo Control (Read 5617 times) previous topic - next topic

alesauskas

I have been working on a project that uses the Arduino to drive servo motors based on bytes it receives over the serial port from Processing. The prototype I had going was working well with 12 motors and 1 Arduino Uno, but the complete project is supposed to contain 30 servos. So I got a Mega, wired everything up, but the breadboards I was using to distribute the power started smoking when I hooked up the supply  :smiley-eek:. So I went for 2 Adafruit 16 Channel PWM/Servo shields to do the power distribution (I now have a 5V 10A supply for each shield with a capacitor added as well), but I have been running into a problem with the transfer of information. I remapped all the values coming from Processing to fall within the PWM range of the servos since the Adafruit library drives them in this way, but when I watch the values come in on the Serial monitor on the Arduino side, they do not match up at all to what is coming out of Processing. I realized that this may be a data type issue, as the numbers coming from Processing are floating point, but I am having difficulty understanding the problem since I did not run into this before trying the shields. Wondering if anyone can shed some light on this in any way? I am at a bit of a dead end.

The motors are Hextronik HTX900's. I already posted on the Adafruit forum, but since it is a code issue rather than hardware I am not getting much help. I am using the pasted code to test one of the shields. The first attached screenshot are the values coming out of Processing, the second screenshot are the values coming into the Arduino.


Code: [Select]
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm0 = Adafruit_PWMServoDriver(0x40);
//Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x41);
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);

#define SERVOMIN  150
#define SERVOMAX  600
#define SERVOCENTER 375


int nextServo = 0;
int servoAngles[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

void setup() {
 
  pwm0.begin();
  pwm0.setPWMFreq(50);  // Analog servos run at ~60 Hz updates
 
  for (int i = 0; i < 15; i++)
  {
    pwm0.setPWM(i, 0, SERVOCENTER);
  }
 
  Serial.begin(9600);
}


void loop() {
 
 

  if(Serial.available()){
   
    int servoAngle = Serial.read();
    servoAngles[nextServo] = servoAngle;
    nextServo++;
   
    if(nextServo > 15){
      nextServo = 0;
     
    }
   
   


    pwm0.setPWM(0, 0, servoAngles[0]);
    pwm0.setPWM(1, 0, servoAngles[1]);
    pwm0.setPWM(2, 0, servoAngles[2]);
    pwm0.setPWM(3, 0, servoAngles[3]);
    pwm0.setPWM(4, 0, servoAngles[4]);
    pwm0.setPWM(5, 0, servoAngles[5]);
    pwm0.setPWM(6, 0, servoAngles[6]);
    pwm0.setPWM(7, 0, servoAngles[7]);
    pwm0.setPWM(8, 0, servoAngles[8]);
    pwm0.setPWM(9, 0, servoAngles[9]);
    pwm0.setPWM(10, 0, servoAngles[10]);
    pwm0.setPWM(11, 0, servoAngles[11]);
    pwm0.setPWM(12, 0, servoAngles[12]);
    pwm0.setPWM(13, 0, servoAngles[13]);
    pwm0.setPWM(14, 0, servoAngles[14]);
    pwm0.setPWM(15, 0, servoAngles[15]);
   
   
    }

   
   
 
}

o_lampe

If possible dont send float variables from Processing, when your arduino expects integer.
Either you have to rewrite the " if Serial.available" Routine to ignore the floatingponit-part of the message ( ignore Bytes with value "0" coming from Serial ) or add a float-buffer variable and then convert it to integer.

Robin2

Those seem to be standard servos. Why are you using PWM instead of servo.write() which would seem to be much simpler.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

alesauskas

@o_lampe
I suspected this was the case, and I did try converting the float to an int in Processing, but the Arduino serial monitor was still displaying some wildly different values. I haven't tried it with the motors yet though, so I will give it a shot and report back.

@Robin2
I am attempting it this way since I am using the Adafruit PWM/Servo shields, I originally wanted to use servo.write with a Mega to control all 30 servos at once, but I couldn't figure out a way to distribute power to all of them through a breadboard without it frying (I am using 2 5V 10A supplies).

alesauskas

Also it still seems weird to me that I am only running into this float v int problem using the shields... Before when I was using just the Arduino to run 12 servos it was working just fine with the code below, inheriting floats from Processing serial. It now also seems relevant to state that Processing is sending out the floats via a byte array (byte out[] = new byte[n], with n being the number of bytes I am sending), which seems to further complicate things in the data type realm from what I can tell.

Code: [Select]


#include <Servo.h>

//declare servos
Servo Column2;
Servo F7;
Servo F8;
Servo F9;
Servo Column3;
Servo F12;
Servo F13;
Servo F14;
Servo Column4;
Servo F17;
Servo F18;
Servo F19;

//setup the array of servo positions
int nextServo = 0;
int servoAngles[] = {0,0,0,0,0,0,0,0,0,0,0,0};

void setup() {
  //attach servos to their pins
  Column2.attach(2);
  F7.attach(3);
  F8.attach(4);
  F9.attach(5);
  Column3.attach(6);
  F12.attach(7);
  F13.attach(8);
  F14.attach(9);
  Column4.attach(10);
  F17.attach(11);
  F18.attach(12);
  F19.attach(13);
 
  Serial.begin(9600);
}

void loop() {
  if(Serial.available()){
    int servoAngle = Serial.read();
   
    servoAngles[nextServo] = servoAngle;
    nextServo++;
    if(nextServo > 11){
      nextServo = 0;
    }
   
    Column2.write(servoAngles[0]);
    F7.write(servoAngles[1]);
    F8.write(servoAngles[2]);
    F9.write(servoAngles[3]);
    Column3.write(servoAngles[4]);
    F12.write(servoAngles[5]);
    F13.write(servoAngles[6]);
    F14.write(servoAngles[7]);
    Column4.write(servoAngles[8]);
    F17.write(servoAngles[9]);
    F18.write(servoAngles[10]);
    F19.write(servoAngles[11]);
   
  }
}



zoomkat

Quote
I am attempting it this way since I am using the Adafruit PWM/Servo shields, I originally wanted to use servo.write with a Mega to control all 30 servos at once, but I couldn't figure out a way to distribute power to all of them through a breadboard without it frying (I am using 2 5V 10A supplies).


Then don't use a breadboard. Instead make a simple power bus to supply the + and - power to the servos. I've used terminal strips like below to make a power bus for multiple servos.

http://www.radioshack.com/product/index.jsp?productId=2103986&filterName=Cable+type&filterValue=Terminal+strip
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

frankswd


(I am using 2 5V 10A supplies).


One thing i would suggest is to up your voltage, thus lowering your current draw for the same action requirements so get a 5V power supply, like old computer one, and google how to use it to feed your project, assuming its not mobile platform.  Then use as suggested a power bus, or make your own by just soldering the power leads to a big piece of wire.  For 10amps you would need like 16AWG wire assuming near continuous current draw, all servos at once.

JimboZA



(I am using 2 5V 10A supplies).


One thing i would suggest is to up your voltage, thus lowering your current draw for the same action requirements so get a 5V power supply, like old computer one


I'm confused by that suggestion: he says he's using 5V supplies already, and you suggest he up his voltage by going for a 5V supply? Go from 5V to 5V?

(I agree that upping the voltage would lower the current, and the HXT900 can handle 6V anyway, and going for 6V rather than 5V is a 20% difference.)
Johannesburg hams call me: ZS6JMB on Highveld rep 145.7875 (-600 & 88.5 tone)
Dr Perry Cox: "Help me to help you, help me to help you...."
Your answer may already be here: https://forum.arduino.cc/index.php?topic=384198.0

o_lampe

Just another clueless guess:
Did you try to use a higher baud-rate for the Serial-port? Maybe youre missing some data,sent by processing?


alesauskas


Quote
I am attempting it this way since I am using the Adafruit PWM/Servo shields, I originally wanted to use servo.write with a Mega to control all 30 servos at once, but I couldn't figure out a way to distribute power to all of them through a breadboard without it frying (I am using 2 5V 10A supplies).


Then don't use a breadboard. Instead make a simple power bus to supply the + and - power to the servos. I've used terminal strips like below to make a power bus for multiple servos.

http://www.radioshack.com/product/index.jsp?productId=2103986&filterName=Cable+type&filterValue=Terminal+strip



Awesome suggestion, never seen one of these, will definitely keep it in mind.

I also realize the servos can take up to 6V, but the 5V supply was easier to get in a pinch and the two of them together was plenty of power as there was hardly any load on the servos at all. I ended up going back to the Mega, ditched the PWM shields since I still could not overcome the data type issue, and used a couple breadboards to distribute the power. For whatever reason, the Mega could only handle 22 motors at once... It says it can control up to 48 servos simultaneously, but every time I added a 23rd motor, regardless of what kind it was, where it was in the system, or what pin it was attached to, it would cause all the motors to spaz out. Pretty strange, I would be very interested in looking into this as well as trying to get the PWM shields to work with the code, both of which seem very possible. Anyway 18 motors was enough to get 3 out of 5 columns working, which was plenty to achieve the effect desired. Thanks for the input!

Go Up