Robotic Arm, Arduino controlled

Hello everybody! (:

Welcome to my -first- project page! This project will focus on the beginning of my robotic arm.

Beginning; About 1 or 2 months ago I got introduced to Arduino by a friend of mine. Soon after I found the LMR website and I've been hooked ever since.

After finding about all the possibility's Arduino has I couldn't decide which way I would go for my first bot. I decided to skip the Start Here robot, no clue why really.

At first I wanted to go with a 2WD bot, then I changed my mind and went for a tracked bot.. but after finding out all the track prices I changed my mind again.. and I set my mind on a Robot Arm :)

My end goal for the arm is quite unknown really. I cant decide between maybe something like an object tracker, or a gripper at the top or even downsize it like 5 times and go with a Rover 5.

At this moment the bot got finished building yesterday, after HOURS of designing, cutting, redesigning etc. Right at this moment I am working on the code so I can control the arm with 3 potmeters.

 

And now, the arm itself: The arm is about 20-30CM in height. It has 3 servo's to control the arm itself, and 1 servo to make the arm spin around its axle. The arm is made of 5mm Pespex, all glued together with Chloroform. The servo's are DYS S9650. (Oh, funny story, I ordered 4 of them cheap 9g servo's and got these s9650's delivered, they are quite a bit more expensive so thats nice)

Well, tell me what you all think!

 

RMW~

Move his arm

  • Actuators / output devices: 4x S9650 Servo's
  • Control method: Arduino UNO
  • Target environment: indoor

This is a companion discussion topic for the original entry at https://community.robotshop.com/robots/show/robotic-arm-arduino-controlled

Code

I added the code for the arm as RoboticCode.txt, if any of you pro’s out there would check it, I’d like to know how my code can be improved!

I scanned your code.

One thing you could do,

if (botpos != botval && botpos < botval) {
   botpos = botpos ++;
   botservo.write(botpos);
   delay(pause);
}
else if (botpos > botval) {
   botpos = botpos --;
   botservo.write(botpos);
   delay(pause);
}

is remove botpos = botpos ++; and replace botservo.write(++botpos); . The same would go for the rest of your xxxpos = and xxxservo.write statements. The ++ or – before the variable means it would be incremented or decremented before you write it. At the very least chage the botpos = botpos ++; to botpos++;

Thank you
I will check it out and see if I can figure it out…

Something else,
Ismt the if (…!= && … < ) a bit useless. Because checking if the value is lower will also check if it isnt the same… Could I judt leave the ‘check if not the same’ part out?

Greetings

…some ideas to improve your code.

To improve your code there should be some refactoring target you set to yourself. 

One improvement could be that you respect the DRY principle. Looking at your code it seems that there are three sections. Each section is responsable for one servo. Each section has the same algorithm but applies that to a different servo. So you could extract the algorithm into a function and pass in the data that is distinct / variable. This is one way to remove code duplications.

Further you could remove all delays. Why do you use them? Do you want to make the robotic arm less reactive? If you insist on a slow behavior make one delay at the end of your loop function.

Then understandability/readability comes in when it is about the logic invariants. If you write something like if(midpos != midval && midpos < midval){…} then why don’t extract this expression into a function and give the function a proper intention revealing name that reflects, what the arm does or where the arm is. That could result in if(isBelowMidpoint()){…} that makes sense without the need to understand the logic expression behind it.

But there is always room for improvement. So never mind.

This robot arm is nice. Thank you for sharing. And welcome to LMR.

Thank you!

Thanks alot for your extensive comment! I will go and read all the seperate articles now and see where I can do all of the improvements.

Some thing I cant find anywhere, nor can come op with myself… 

Since the potmeter isnt 100% accurate (It gives a value between e.g. 130-132 when the potmeter is at 131) this makes the servo jerky and I wanted to get rid of that. 

What I thought up was… make 2 variables.

int 1 = potmeter value and int 2 makes the current servo value (servo.read()). Then the difference between those has to be atleast 3 in order for the servo to move. I cant find any arduino function to compare, nor could I find some help on the internet… Any of you all that got a clue? 

 

Thanks again,

 

RMW

 

And oh, I added the delays so the arm would move terrible slow so I could see whats going on. In the “final” code I want it to be faster.

Is it a map problem?

It looks like as if you have a map problem. For every potentiometer value there is a given servo position. Where the pot theoretically is a continuous value, the servo position is a discreete value. This is due the gears and their ratio.

So you could use some algorithm to solve the map problem or use: a map. For each pot value look up the servo value from this map and apply the servo value to the servo.

Be aware that some cheap servo start to jerk around 0° and around 180°. So a common practise is to reduce the servo angles to the range [10° to 170°] or more precise depending on the gears.

.

Thank you for the quick reply.

 

How would you advice me to do this? Not that I want to be leeching, but I have been looking to solve this problem for hours now… I dont know what else to try (:

My servo doesn’t jerk at 0 or 180 degrees, though I would like to adjust the servo range. could I just do it like this: map(val, 0, 1023, 10, 170)?

You could do
You could do this:
If(int1<=int2+3 || int1>=int2-3){
//move servo here

Just off of the too of my head. Not sure If || is valid for Arduino but that would work in say c#

Hope that helps.

Oops that should be && not
Oops that should be && not ||

Sorry. I’ll edit it and fix that. :L

possibly

if (botpos < botval)
botservo.write(botpos++);
else
if (botpos > botval)
botservo.write(botpos–);
delay(pause);

Be careful in how you call out the inc/dec

Your suggestion
botservo.write(botpos++);
will write the previous botpos, and then, it will increment. The number that is written will always be one off from the value that was intended. That is why I wrote ++botpos instead. What I wrote would replace the botpos = botpos ++; botservo.write(botpos); with a single line. Your code could be replaced with botservo.write(botpos); botpos = botpos ++; . The difference being when the variable was incremented. 

thank you!

thanks bird!

i think you have shown me this once before, but I am forgetful.  forgetful and appreciative…

hehe i’d better check my current code for this error

updated (with the style guide’s recommendation of block if statements):

if (botpos < botval) {
botservo.write(++botpos);
} else
if (botpos > botval) {
botservo.write(–botpos);
}
delay(pause);

Refactored Code

Here is an example of what I ment with this comment. No DRY harms and a bit more intension revealing. To keep the leg data together I used a struct and kept all leg data in an array.


/
 Sample Code for RMWessels’ Robot Arm
 Written by NilsB from LetsMakeRobots.com
/

#include <Servo.h>

#define LEG_COUNT 3
#define PAUSE 15

struct Leg {
  int actualValue;
  int nominalValuePin;
  int servoPin;
  Servo servo;
};

Leg legs[LEG_COUNT];

void setup()

  init(0,  9, A0);
  init(1, 10, A1);
  init(2, 11, A2);
}

void loop(){
  for(int index = 0; index < LEG_COUNT; index++){
    adjustLegAngle(index);
  }

  delay(PAUSE);
}

void adjustLegAngle(int index){
  int nominalValue = readNominalValueAt(legs[index].nominalValuePin);

  if( eq(nominalValue, legs[index].actualValue) ){
    return; // Nothing to do.
  }

  legs[index].actualValue = nominalValue;
  legs[index].servo.write(legs[index].actualValue);
}

boolean eq(int nominalValue, int actualValue){
  return actualValue == nominalValue;
}

void init(int index, int servoPin, int nominalValuePin){
  legs[index].servoPin = servoPin;
  legs[index].nominalValuePin = nominalValuePin;
  legs[index].actualValue = 0;
  legs[index].servo.attach(legs[index].servoPin);
}

int readNominalValueAt(int nominalValuePin){
  return map(
  analogRead(nominalValuePin),
  0, 1023, 0, 179);
}

Try a low-pass-filter using a filtered nominal curve.

More common than using a map is a low-pass-filter. Using this filter the jitter of the potentiometer signal is flattened / corrected. You could also try this solution.

How? Well, you could use a moving average. A simple solution to this is to always take i.e. the last four potentiometer values, sum them up and divide them by four (see image below). Use this calculated nominal value as the actual value for the servo.

One last hint: If you scale a value from 0 to 180 you get 181 steps. So your code tells the servo to go to angle 181°. Be aware that you start from 0 - not 1. Therefore scale the value from 0 to 179… or from 10 to 169.

FilteredNominalValueToActualValue.png

A classic two-level controller?

What purpose is this inc/dec anyhow?

Is the intension that …
a) … whenever the pot changes the servo must change too and in the given direction?
b) … the pot value is the nominal value that the servo has to follow?

To me it’s a bit of a puzzle what this inc/dec is all about. What makes sense is that the pot gives the nominal value and the software tries to calculate an actual value for the servo. A classic two-level controller.

Zweipunkt.svg

See this comment for more information.

Thanks everybody!

Thank you for all the comments, I am doing my best to read and test everything and I will post back with my results!