Go Down

Topic: Controlling two servos through serial (Read 5699 times) previous topic - next topic

n00b234

I'm trying to control two servos through serial to controll a nerf gun, and its gonna be awesome. im gonna put a camera on it and have it go to my ipod touch, and controll it all with OSCemote on my ipod touch. Does anyone have any good code like this, but for two servos instead of one:
/*
* NewSerialServo
* --------------
* Servo control from the Serial port
*
* Alteration of the control interface to use < and > keys
* to slew the servo horn left and right.  Works best with
* the Linux/Mac terminal "screen" program.
*
* Created 10 December 2007
* copyleft 2007 Brian D. Wendt
*/

/** Adjust these values for your servo and setup, if necessary **/
int servoPin     =  2;    // control pin for servo motor
int minPulse     =  600;  // minimum servo position
int maxPulse     =  2400; // maximum servo position
int turnRate     =  100;  // servo turn rate increment (larger value, faster rate)
int refreshTime  =  20;   // time (ms) between pulses (50Hz)

/** The Arduino will calculate these values for you **/
int centerServo;         // center servo position
int pulseWidth;          // servo pulse width
int moveServo;           // raw user input
long lastPulse   = 0;    // recorded time (ms) of the last pulse


void setup() {
 pinMode(servoPin, OUTPUT);  // Set servo pin as an output pin
 centerServo = maxPulse - ((maxPulse - minPulse)/2);
 pulseWidth = centerServo;   // Give the servo a starting point (or it floats)
 Serial.begin(9600);
 Serial.println("      Arduino Serial Servo Control");
 Serial.println("Press < or > to move, spacebar to center");
 Serial.println();
}

void loop() {
 // wait for serial input
 if (Serial.available() > 0) {
   // read the incoming byte:
   moveServo = Serial.read();

   // ASCII '<' is 44, ASCII '>' is 46 (comma and period, really)
   if (moveServo == 44) { pulseWidth = pulseWidth - turnRate; }
   if (moveServo == 46) { pulseWidth = pulseWidth + turnRate; }
   if (moveServo == 32) { pulseWidth = centerServo; }

   // stop servo pulse at min and max
   if (pulseWidth > maxPulse) { pulseWidth = maxPulse; }
   if (pulseWidth < minPulse) { pulseWidth = minPulse; }

   // print pulseWidth back to the Serial Monitor (uncomment to debug)
   // Serial.print("Pulse Width: ");
   // Serial.print(pulseWidth);
   // Serial.println("us");   // microseconds
 }

 // pulse the servo every 20 ms (refreshTime) with current pulseWidth
 // this will hold the servo's position if unchanged, or move it if changed
 if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servoPin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth);  // pulse width
   digitalWrite(servoPin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
}


AWOL

#1
May 27, 2009, 08:43 pm Last Edit: May 27, 2009, 08:53 pm by AWOL Reason: 1
Quote
Does anyone have any good code like this, but for two servos instead of one

Have you tried a search?

Code: [Select]
// ASCII '<' is 44, ASCII '>' is 46 (comma and period, really)
  if (moveServo == 44) { pulseWidth = pulseWidth - turnRate; }
  if (moveServo == 46) { pulseWidth = pulseWidth + turnRate; }
  if (moveServo == 32) { pulseWidth = centerServo; }

This section and comment just cracks me up.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

n00b234

ive searched for a while, and i havent found anything(that worked). Could someone who actualy knows what there doing edit this code and make it for two servos. u should probably assign them to other keys, like up be w, left be a, down be s, and right be d. im gonna put a fire button on it too, so could you make f be an I/O thing. the trigger is just a standard I/O switch, but i dont know how to control it with an arduino.

im a noob, so plz help

n00b234

I have figured some stuff out and i have some code, but it doesnt work quite rite yet can someone fix it? the left and right(a and d) work, but the up and down(w and s) are kinda funky. it tries to catch up to the other servo, and doesnt listen to the terminal commands i give it. here is my code:
Code: [Select]
#include <Servo.h>

Servo servo1;
Servo servo2;

/** Adjust these values for your servo and setup, if necessary **/
int servo1Pin     =  10;    // control pin for servo motor
int servo2Pin     =  11;    // control pin for servo motor
int minPulse     =  900;  // minimum servo position
int maxPulse     =  2100; // maximum servo position
int turnRate     =  100;  // servo turn rate increment (larger value, faster rate)
int refreshTime  =  20;   // time (ms) between pulses (50Hz)

/** The Arduino will calculate these values for you **/
int centerServo;         // center servo position
int pulseWidth;          // servo pulse width
int moveServo1;           // raw user input
int moveServo2;           // raw user input
long lastPulse   = 0;    // recorded time (ms) of the last pulse


void setup() {
 pinMode(servo1Pin, OUTPUT);  // Set servo pin as an output pin
 pinMode(servo2Pin, OUTPUT);  // Set servo pin as an output pin
 centerServo = maxPulse - ((maxPulse - minPulse)/2);
 pulseWidth = centerServo;   // Give the servo a starting point (or it floats)
 Serial.begin(9600);
 Serial.println("      Arduino Serial Servo Control");
 Serial.println("Press < or > to move, spacebar to center");
 Serial.println();
}

void loop() {
 // wait for serial input
 if (Serial.available() > 0) {
   // read the incoming byte:
   moveServo1 = Serial.read();
   moveServo2 = Serial.read();

   // ASCII 'a' is 44, ASCII 'd' is 46
   if (moveServo1 == 97) { pulseWidth = pulseWidth - turnRate; }
   if (moveServo1 == 100) { pulseWidth = pulseWidth + turnRate; }
   if (moveServo1 == 32) { pulseWidth = centerServo; }
 
   // ASCII 's' is 44, ASCII 'w' is 46
   if (moveServo2 == 115) { pulseWidth = pulseWidth - turnRate; }
   if (moveServo2 == 119) { pulseWidth = pulseWidth + turnRate; }
   if (moveServo2 == 32) { pulseWidth = centerServo; }

   // stop servo pulse at min and max
   if (pulseWidth > maxPulse) { pulseWidth = maxPulse; }
   if (pulseWidth < minPulse) { pulseWidth = minPulse; }

   // print pulseWidth back to the Serial Monitor (uncomment to debug)
   // Serial.print("Pulse Width: ");
   // Serial.print(pulseWidth);
   // Serial.println("us");   // microseconds
 }

 // pulse the servo every 20 ms (refreshTime) with current pulseWidth
 // this will hold the servo's position if unchanged, or move it if changed
 if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servo1Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth);  // pulse width
   digitalWrite(servo1Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
 if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servo2Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth);  // pulse width
   digitalWrite(servo2Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
}


AWOL

#4
May 28, 2009, 08:22 am Last Edit: May 28, 2009, 08:46 am by AWOL Reason: 1
Quote
it tries to catch up to the other servo, and doesnt listen to the terminal commands i give it. here is my code


How are you powering the servos?
From a separate supply, I hope.

Code: [Select]
if (moveServo1 == 97) { pulseWidth = pulseWidth - turnRate; }

Is easier to read if :
Code: [Select]
if (moveServo1 == 'a') { pulseWidth = pulseWidth - turnRate; }


Not sure why you've written this section as two separate clauses:
Code: [Select]
if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servo1Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth);  // pulse width
   digitalWrite(servo1Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
 if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servo2Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth);  // pulse width
   digitalWrite(servo2Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

n00b234

#5
May 28, 2009, 08:47 am Last Edit: May 28, 2009, 08:48 am by thenewdoctorwho Reason: 1
should i be? im just powering them off the arduino board. whats the voltage on servos anyway, because i dont really have any available power supplies. is it just like 1.5V, so i could just put on a AA?

AWOL

No, it's more like 5 or 6V (4 x AA).

Code: [Select]
 if (Serial.available() > 0) {
   // read the incoming byte:
   moveServo1 = Serial.read();
   moveServo2 = Serial.read();

I wouldn't count on this always working.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

n00b234

what could i replace this with? im not a coder yet, i just combined a couple of code examples that didnt work for various reasons. im still just a noob. my mac hasnt told me that im consuming too much power from the servos, which it does if i do too much. but i could use my arduino power supply and my usb port. would that be ok?

AWOL

#8
May 28, 2009, 09:08 am Last Edit: May 28, 2009, 09:13 am by AWOL Reason: 1
http://arduino.cc/en/Serial/Read

How many times do you calculate "pulseWidth"?
How many times do you use it?  ;)
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

n00b234

Im not exactly sure what it even is, but i think that is used a lot. i posted all the code, so u can check for urself

n00b234

how do you even recalculate it. can you rewrite the code a bit so that its correct. I'm not good at coding.

n00b234

ok, i have made a few revisions. i gave the servos seperate pulseWidths, but servo2 doesnt work at all now. it doesnt try to catch up, but it doesnt move when i tell it to.I cant get the second pulsewidth to change

Code: [Select]
#include <Servo.h>

Servo servo1;
Servo servo2;

/** Adjust these values for your servo and setup, if necessary **/
int servo1Pin     =  10;    // control pin for servo motor
int servo2Pin     =  11;    // control pin for servo motor 2
int minPulse     =  900;  // minimum servo position
int maxPulse     =  2100; // maximum servo position
int turnRate     =  100;  // servo turn rate increment (larger value, faster rate)
int refreshTime  =  20;   // time (ms) between pulses (50Hz)

/** The Arduino will calculate these values for you **/
int centerServo;         // center servo position
int pulseWidth1;          // servo pulse width
int pulseWidth2;          // servo pulse width
int moveServo1;           // raw user input
int moveServo2;           // raw user input
long lastPulse   = 0;    // recorded time (ms) of the last pulse


void setup() {
 pinMode(servo1Pin, OUTPUT);  // Set servo pin as an output pin
 pinMode(servo2Pin, OUTPUT);  // Set servo pin as an output pin
 centerServo = maxPulse - ((maxPulse - minPulse)/2);
 pulseWidth1, pulseWidth2 = centerServo;   // Give the servo a starting point (or it floats)
 Serial.begin(9600);
 Serial.println("      Arduino Serial Servo Control");
 Serial.println("Press a, s, d, or w to move, spacebar to center");
 Serial.println();
}

void loop() {
 // wait for serial input
 if (Serial.available() > 0) {
           // read the incoming byte:
           moveServo1 = Serial.read();
           moveServo2 = Serial.read();

   // ASCII 'a' is 97, ASCII 'd' is 100
   if (moveServo1 == 97) { pulseWidth1 = pulseWidth1 - turnRate; }
   if (moveServo1 == 100) { pulseWidth1 = pulseWidth1 + turnRate; }
   if (moveServo1 == 32) { pulseWidth1 = centerServo; }
 
   // ASCII 's' is 115, ASCII 'w' is 119
   if (moveServo2 == 115) { pulseWidth2 = pulseWidth2 - turnRate; }
   if (moveServo2 == 119) { pulseWidth2 = pulseWidth2 + turnRate; }
   if (moveServo2 == 32) { pulseWidth2 = centerServo; }

   // stop servo pulse at min and max
   if (pulseWidth1 > maxPulse) { pulseWidth1 = maxPulse; }
   if (pulseWidth1 < minPulse) { pulseWidth1 = minPulse; }
   
     // stop servo pulse at min and max
   if (pulseWidth2 > maxPulse) { pulseWidth2 = maxPulse; }
   if (pulseWidth2 < minPulse) { pulseWidth2 = minPulse; }

   // print pulseWidth back to the Serial Monitor (uncomment to debug)
   Serial.print("Pulse Width: ");
   Serial.print(pulseWidth1, pulseWidth2);
   Serial.println("us");   // microseconds
 }

 // pulse the servo every 20 ms (refreshTime) with current pulseWidth
 // this will hold the servo's position if unchanged, or move it if changed
 if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servo1Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth1);  // pulse width
   digitalWrite(servo1Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
 if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servo2Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth2);  // pulse width
   digitalWrite(servo2Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
}

the servos also make these noises like there trying to move, and it doesnt sound good. i also set it to print in the pulsewidths on both.

AWOL

Code: [Select]
 if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servo1Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth1);  // pulse width
   digitalWrite(servo1Pin, LOW);    // stop the pulse

   digitalWrite(servo2Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth2);  // pulse width
   digitalWrite(servo2Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }

Might do the trick.
As I said earlier.

Code: [Select]
#include <Servo.h>

Servo servo1;
Servo servo2;

Is redundant.

Code: [Select]
pulseWidth1, pulseWidth2 = centerServo;
Would be more legible as:
Code: [Select]
pulseWidth1 = pulseWidth2 = centerServo;
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

n00b234

I have figured out the problem, but i dont know what a solution would be. and thanks AWOL, its exactly what you said.this is it:
Code: [Select]
 if (Serial.available() > 0) {
   // read the incoming byte:
   moveServo1 = Serial.read();
   moveServo2 = Serial.read();

and only servo1 works. but if i change it to this:
Code: [Select]
if (Serial.available() > 0) {
           // read the incoming byte:
           moveServo1, moveServo2 = Serial.read();

only servo2 works. what do i need to change to make this work?
i also made some more adjustments, just to be sure. i made two of almost everything, for each servo. Here is my current code:
Code: [Select]
#include <Servo.h>

Servo servo1;
Servo servo2;

/** Adjust these values for your servo and setup, if necessary **/
int servo1Pin     =  10;    // control pin for servo motor
int minPulse1     =  900;  // minimum servo position
int maxPulse1     =  2100; // maximum servo position
int turnRate1     =  100;  // servo turn rate increment (larger value, faster rate)
int refreshTime1  =  20;   // time (ms) between pulses (50Hz)
int servo2Pin     =  11;    // control pin for servo motor 2
int minPulse2     =  900;  // minimum servo position
int maxPulse2     =  2100; // maximum servo position
int turnRate2     =  100;  // servo turn rate increment (larger value, faster rate)
int refreshTime2  =  20;   // time (ms) between pulses (50Hz)
int centerServo1   =  1500;         // center servo position
int centerServo2   =  1500;         // center servo position

/** The Arduino will calculate these values for you **/
int centerServo;         // center servo position
int pulseWidth1;          // servo pulse width
int pulseWidth2;          // servo pulse width
int moveServo1;           // raw user input
int moveServo2;           // raw user input
long lastPulse   = 0;    // recorded time (ms) of the last pulse


void setup() {
 pinMode(servo1Pin, OUTPUT);  // Set servo pin as an output pin
 pinMode(servo2Pin, OUTPUT);  // Set servo pin as an output pin
 centerServo1 = maxPulse1 - ((maxPulse1 - minPulse1)/2);
 centerServo1 = maxPulse2 - ((maxPulse2 - minPulse2)/2);
 pulseWidth1 = centerServo;   // Give the servo a starting point (or it floats)
 pulseWidth2 = centerServo;   // Give the servo a starting point (or it floats)
 Serial.begin(9600);
 Serial.println("      Arduino Serial Servo Control");
 Serial.println("Press a, s, d, or w to move, spacebar to center");
 Serial.println();
}

void loop() {
 // wait for serial input
 if (Serial.available() > 0) {
           // read the incoming byte:
           moveServo1, moveServo2 = Serial.read();

   // ASCII 'a' is 97, ASCII 'd' is 100
   if (moveServo1 == 97) { pulseWidth1 = pulseWidth1 - turnRate1; }
   if (moveServo1 == 100) { pulseWidth1 = pulseWidth1 + turnRate1; }
   if (moveServo1 == 32) { pulseWidth1 = centerServo1; }
 
   // ASCII 's' is 115, ASCII 'w' is 119
   if (moveServo2 == 115) { pulseWidth2 = pulseWidth2 - turnRate2; }
   if (moveServo2 == 119) { pulseWidth2 = pulseWidth2 + turnRate2; }
   if (moveServo2 == 32) { pulseWidth2 = centerServo2; }

   // stop servo pulse at min and max
   if (pulseWidth1 > maxPulse1) { pulseWidth1 = maxPulse1; }
   if (pulseWidth1 < minPulse1) { pulseWidth1 = minPulse1; }
   
     // stop servo pulse at min and max
   if (pulseWidth2 > maxPulse2) { pulseWidth2 = maxPulse2; }
   if (pulseWidth2 < minPulse2) { pulseWidth2 = minPulse2; }

   // print pulseWidth back to the Serial Monitor (uncomment to debug)
   Serial.print("Servo 1: ");
   Serial.print(pulseWidth1);
   Serial.print(" Servo 2: ");
   Serial.print(pulseWidth2);
   Serial.println("us");   // microseconds
 }

 // pulse the servo every 20 ms (refreshTime) with current pulseWidth
 // this will hold the servo's position if unchanged, or move it if changed
 if (millis() - lastPulse >= refreshTime1) {
   digitalWrite(servo1Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth1);  // pulse width
   digitalWrite(servo1Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
 if (millis() - lastPulse >= refreshTime2) {
   digitalWrite(servo2Pin, HIGH);   // start the pulse
   delayMicroseconds(pulseWidth2);  // pulse width
   digitalWrite(servo2Pin, LOW);    // stop the pulse
   lastPulse = millis();           // save the time of the last pulse
 }
}

AWOL

Please, please, don't use this:
Code: [Select]
moveServo1, moveServo2 = Serial.read();

I don't want to write this for you but I'll try to nudge you in the right direction:
Code: [Select]
if (Serial.available() > 0) {

Looks at the incoming character buffer, and if any are available, returns how many there are in the buffer.

So what does your code do if "Serial.available" returns just "1"?
The first time you call "Serial.read", you get that character.
The second time you call "Serial.read", you get ... -1.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Go Up