Hello!
My Name is Lance and I am new to Arduino.
I am working on an open source 3D printed robotic arm project:
modeled after the uArm: http://store.ufactory.cc/complete-assembled-acrylic-kit/
Below is the code for some initial testing. I want the servos to move smoothly so the arm doesn't wobble when the high torque servos jerk from on position to the next. I'm looking for smooth natural movement.
Oh and don't assume I know anything about the code, I am a total newbe.
More on the Lite Arm
My goal for this arm is for it to read gcode from pronterface and move to correct x,y,z coordinates. If anyone can suggest how I can go about that I would be very grateful.
// Testing for Lite Arm Project
// http://www.thingiverse.com/thing:407800
#include <Servo.h>
Servo servobase;
Servo servoshoulder;
Servo servoforearm;
void setup() {
servobase.attach(9, 1000, 2000); // Set servo to digital pin 9, min, max
servoshoulder.attach(10, 1000, 2000); // Set servo to digital pin 10, min, max
servoforearm.attach(11, 1000, 2000); // Set servo to digital pin 11, min, max
}
void loop() { // Loop through motion tests
home1(); //go to start pos
delay(1000); // Wait 1000 milliseconds (1 seconds)
pos1();
delay(1000);
pos2();
delay(1000);
pos3();
delay(1000);
}
void home1() {
servobase.write(90);
servoshoulder.write(90);
servoforearm.write(90);
}
void pos1() { //pen to paper
servobase.write(90);
servoshoulder.write(42);
servoforearm.write(120);
}
void pos2() { //move forward (draw line)
servobase.write(90);
servoshoulder.write(37.5);
servoforearm.write(105);
}
void pos3() { //move forward (draw line)
servobase.write(90);
servoshoulder.write(28.5);
servoforearm.write(90);
}
steinie44:
See: Files, Examples, Servo, Sweep
To see how to step it slower with a for loop.
How do you sweep 3 servos at the same time?
Robin2:
You will get finer control if you use servo.writeMicroseconds()
...R
Yes I know, I kept it simple here
Also made a conversion calculator in google sheets that pretty cool
enter degree_____ ="enter degree"(1000/180)+1000 (<this mill give you microseconds)
Enter Microseconds______ = ("enter microseconds"-1000)(180/1000) (<this will give you the angle)
Blink without delay. This example blinks 2 LEDs at different rates.
// Blink without delay State Machine JDS
// Constants
const int Green = 7;
const int Red = 8;
//Variables
byte GreenState = 0;
byte RedState = 0;
long PrevMillisGreen = 0;
long PrevMillisRed = 0;
long GreenInterval = 900;
long RedInterval = 200;
unsigned long CurrentMillis = millis();
void setup() {
// put your setup code here, to run once:
pinMode(Green, OUTPUT);
pinMode(Red, OUTPUT);
Serial.begin(9600);
Serial.print(FILE " " DATE " " TIME);
Serial.print(" IDE "); Serial.println(ARDUINO);
}
void loop() {
// put your main code here, to run repeatedly:
CurrentMillis = millis();
if (CurrentMillis - PrevMillisGreen > GreenInterval)
{ GreenState = !GreenState;
digitalWrite(Green, GreenState);
PrevMillisGreen = CurrentMillis;
}
if (CurrentMillis - PrevMillisRed > RedInterval)
{ RedState = !RedState;
digitalWrite(Red, RedState);
PrevMillisRed = CurrentMillis;
}
}
Where would I place the other 2 servos in the code to execute a synchronized movement?
#include <Servo.h>
Servo servobase;
Servo servoshoulder;
Servo servoforearm;
int pos = 0; // variable to store the servo position
void setup()
{
servobase.attach(9, 1000, 2000); // Set servo to digital pin 9, min, max
servoshoulder.attach(10, 1000, 2000); // Set servo to digital pin 10, min, max
servoforearm.attach(11, 1000, 2000); // Set servo to digital pin 11, min, max
}
void loop()
{
for(pos = 90; pos < 37.5; pos += 1) // goes from 90 degrees to 37.5 degrees
{ // in steps of 1 degree
servoshoulder.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for(pos = 37.5; pos>=1; pos-=1) // goes from 37.5 degrees to 90 degrees
{
servoshoulder.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}
// "define global variables"
#include <Servo.h>
Servo servoBase;
Servo servoShoulder; //I assume that I add this the same way
Servo servoForearm;
int servoBasePos = 0;
int servoShoulderPos = 1;
int servoForearmPos = 2;
//int pos = 0; // variable to store the servo position
void setup()
{
servoBase.attach(9, 1000, 2000); // Set servo to digital pin 9, min, max
servoShoulder.attach(10, 1000, 2000); // Set servo to digital pin 10, min, max
servoForearm.attach(11, 1000, 2000); // Set servo to digital pin 11, min, max
}
void loop() {
updateLimbPositions();
moveLimbs();
}
void updateLimbPositions() {
// "this is just simple demo stuff"
servoBasePos += 5000; // microsecs
servoShoulderPos += 5000; // ??? How should this be written)
servoForearmPos += 5000; //
if (servoBasePos > 1500) {
servoBasePos = 1500;
}
if (servoShoulderPos > 1500) {
servoShoulderPos = 1233;
}
if (servoForearmPos > 1500) {
servoForearmPos = 1666;
}
}
void moveLimbs() {
servoBase.writeMicroseconds(servoBasePos);
servoShoulder.writeMicroseconds(servoShoulderPos);
servoForearm.writeMicroseconds(servoForearmPos);
}
When I run this it goes directly to the position and does not move
What I want is to go from "home position"
90(degrees). or 1500(microseconds) Base
1500 Shoulder
1500 Forearm
to "position 1"
1500 Base
1233 Shoulder
1666 Forearm
then to "position 2"
1500 Base
1158 Shoulder
1500 Forearm
moving in steps on 1 degree same as the stock sweep code delay.
Armatec:
I want the servos to move smoothly so the arm doesn't wobble when the high torque servos jerk from on position to the next. I'm looking for smooth natural movement.
That's a nice looking robot arm, btw.
Something you'll probably want to do is a "ramp-up...ramp-down" on the speed of the servos. So - each time thru the loop as you increase the servo speed, increase the "distance" between the amounts you set, until you reach a fixed upper bound.
The below is rough pseudo-code - but it should illustrate the idea I am meaning:
from = 10; // start position of servo
to = 120; // end position of servo
min = 1; // minimum acceleration
max = 10; // maximum acceleration
rdpos = 0; // ramp down position
pos = from; // start the servo at this position
ai = 1; // acceleration incrementor starting value
ac = 1; // acceleration constant
Loop:
servo.write(pos);
if pos >= to then exit loop; // reached the end of movement
pos = pos + ai; // accelerate the positioning of the servo
ai = ai + ac; // increment the acceleration incrementor by the acceleration constant (see note below)
if ai > max then
ai = max; // bounds check for max acceleration
rdpos = to - (pos - from); // position at which to start ramping down
if ai < min then ai = min; // bounds check for min acceleration
if pos >= rdpos then
ai = -ai; // invert acceleration to slow down servo until done
ac = -ac;
Ok - the above code is -completely- untested, and it also only allows for positive directional movement of the servo (that is, from a position smaller relative to the end position) - it will likely need to be debugged and then generalized to allow for movement in the opposite direction.
Note: You might want to only increment the incrementor every "n" times (where n is some integer) thru the loop, in order to make the ramp up and down less abrupt. Alternatively, one could imagine where most of these values are floats of some sort, and only when the servo.write() is performed do you cast the value to an integer.
However you perform the ramp-up/ramp-down for the acceleration curve - the point is to do something like this; ideally, doing so will make the movements smoother and more fluid, and allow the mass being moved to come up naturally to speed, instead of forcing it to move at full speed (which results in the jerkiness you have experienced).
Armatec:
When I run this it goes directly to the position and does not move
Why did you modify my code?
...R
It has to be completed to some degree correct?
Is this what it should look like with "all the usual stuff"?
// "define global variables"
#include <Servo.h>
Servo servoBase;
Servo servoShoulder; //I assume that I add this the same way
Servo servoForearm;
int servoBasePos = 0;
int servoShoulderPos = 1;// variable to store the servo position
int servoForearmPos = 2;//if i dont add the above i get thee error below
//sketch_aug23a:40: error: 'servoBasePos' was not declared in this scope
//sketch_aug23a:41: error: 'servoShoulderPos' was not declared in this scope
//sketch_aug23a:42: error: 'servoForearmPos' was not declared in this scope
void setup()
{
servoBase.attach(9, 1000, 2000); // Set servo to digital pin 9, min, max
servoShoulder.attach(10, 1000, 2000); // Set servo to digital pin 10, min, max
servoForearm.attach(11, 1000, 2000); // Set servo to digital pin 11, min, max
}
void loop() {
updateLimbPositions();
moveLimbs();
}
void updateLimbPositions() {
// this is just simple demo stuff
servoBasePos += 50; // microsecs
servoShoulderPos += 80;
servoForearmPos += 20;
if (servoBasePos > 1900) {
servoBasePos = 1900;
}
if (servoShoulderPos > 1900) {
servoShoulderPos = 1900;
}
if (servoForearmPos > 1900) {
servoForearmPos = 1900;
}
}
void moveLimbs() {
servoBase.writeMicroseconds(servoBasePos);
servoShoulder.writeMicroseconds(servoShoulderPos);
servoForearm.writeMicroseconds(servoForearmPos);
}
I can just post video of your code in my machine:)
Robin2's code (I think it's what he meant)
// "define global variables"
#include <Servo.h>
Servo servoBase;
Servo servoShoulder; //I assume that I add this the same way
Servo servoForearm;
int servoBasePos = 0;
int servoShoulderPos = 1;// variable to store the servo position
int servoForearmPos = 2;//if i dont add the above i get thee error below
//sketch_aug23a:40: error: 'servoBasePos' was not declared in this scope
//sketch_aug23a:41: error: 'servoShoulderPos' was not declared in this scope
//sketch_aug23a:42: error: 'servoForearmPos' was not declared in this scope
void setup()
{
servoBase.attach(9, 1000, 2000); // Set servo to digital pin 9, min, max
servoShoulder.attach(10, 1000, 2000); // Set servo to digital pin 10, min, max
servoForearm.attach(11, 1000, 2000); // Set servo to digital pin 11, min, max
}
void loop() {
updateLimbPositions();
moveLimbs();
}
void updateLimbPositions() {
// this is just simple demo stuff
servoBasePos += 50; // microsecs
servoShoulderPos += 80;
servoForearmPos += 20;
if (servoBasePos > 1900) {
servoBasePos = 1900;
}
if (servoShoulderPos > 1900) {
servoShoulderPos = 1900;
}
if (servoForearmPos > 1900) {
servoForearmPos = 1900;
}
}
void moveLimbs() {
servoBase.writeMicroseconds(servoBasePos);
servoShoulder.writeMicroseconds(servoShoulderPos);
servoForearm.writeMicroseconds(servoForearmPos);
}
My original code from the top of page 1
// Testing for Lite Arm Project
// http://www.thingiverse.com/thing:407800
#include <Servo.h>
Servo servobase;
Servo servoshoulder;
Servo servoforearm;
void setup() {
servobase.attach(9, 1000, 2000); // Set servo to digital pin 9, min, max
servoshoulder.attach(10, 1000, 2000); // Set servo to digital pin 10, min, max
servoforearm.attach(11, 1000, 2000); // Set servo to digital pin 11, min, max
}
void loop() { // Loop through motion tests
home1(); //go to start pos
delay(1000); // Wait 1000 milliseconds (1 seconds)
pos1();
delay(1000);
pos2();
delay(1000);
pos3();
delay(1000);
}
void home1() {
servobase.write(90);
servoshoulder.write(90);
servoforearm.write(90);
}
void pos1() { //pen to paper
servobase.write(90);
servoshoulder.write(42);
servoforearm.write(120);
}
void pos2() { //move forward (draw line)
servobase.write(90);
servoshoulder.write(37.5);
servoforearm.write(105);
}
void pos3() { //move forward (draw line)
servobase.write(90);
servoshoulder.write(28.5);
servoforearm.write(90);
}
Interesting project. Making code that controls servo movement speed would make for some interesting robotic arm and camera pan/tilt setups. I've tinkered with an arduino controlled ssc-32 servo controller which has speed control and the results were interesting. Basically a web page GUI to control the servo positioning.
edit: below are some web page GUIs I made for controlling the servos
zoomkat:
Interesting project. Making code that controls servo movement speed would make for some interesting robotic arm and camera pan/tilt setups. I've tinkered with an arduino controlled ssc-32 servo controller which has speed control and the results were interesting. Basically a web page GUI to control the servo positioning.
That's pretty cool.
I looked at the VaroSpeed link you posted and have not figured it out yet. I searched far and wide for a solution on the web and this forum before I posted anything, then I decided maybe it's time to make another post on this subject and find a definitive solution for everyone else with this issue.
I don't understand the purpose of the two videos. It looks like my code doesn't work. Have you examined it to see why? My earlier comment was about the huge increase in the increments.
Yes, you did correctly add the definitons for the variables - but they shouldn't start at 1. They should start at the minimum servo positions of about 1000 - I assumed you would figure that out from how they are used.
EDIT to add ...
I've now tried my code with one servo and the problem was immediately apparent - I had forgotten to include a delay to give the servo time to move so they all go to their end point so quickly that there only seems to be one move.
You need to add (say) delay(50); as the last thing in loop(). And you shouldn't use delay() in your real code - just for this demo.
Try this version
// "define global variables"
#include <Servo.h>
Servo servoBase;
Servo servoShoulder; //I assume that I add this the same way
Servo servoForearm;
int servoBasePos = 1000;
int servoShoulderPos = 1000;// variable to store the servo position
int servoForearmPos = 1000;//if i dont add the above i get thee error below
void setup()
{
servoBase.attach(9, 1000, 2000); // Set servo to digital pin 9, min, max
servoShoulder.attach(10, 1000, 2000); // Set servo to digital pin 10, min, max
servoForearm.attach(11, 1000, 2000); // Set servo to digital pin 11, min, max
moveLimbs(); // to the initial position
delay(1000); // so we can see the initial position
}
void loop() {
updateLimbPositions();
moveLimbs();
delay(50);
}
void updateLimbPositions() {
// this is just simple demo stuff
servoBasePos += 25; // microsecs
servoShoulderPos += 15;
servoForearmPos += 10;
if (servoBasePos > 1900) {
servoBasePos = 1900;
}
if (servoShoulderPos > 1900) {
servoShoulderPos = 1900;
}
if (servoForearmPos > 1900) {
servoForearmPos = 1900;
}
}
void moveLimbs() {
servoBase.writeMicroseconds(servoBasePos);
servoShoulder.writeMicroseconds(servoShoulderPos);
servoForearm.writeMicroseconds(servoForearmPos);
}
I note that you have set min and max limits for all of your servos. If these numbers suit your actual servos that is fine. The servo I used for testing seems to work between 400 and 2000 usecs.