Hey Im trying to make a 2 axis robot using IK but im have some issues

Hi everyone,

I'm having a bit of trouble getting inverse kinematics (IK) working correctly on my 2DOF robotic arm. Most of the time, the arm moves perfectly to the positions I give it but it seems to struggle or completely fail when I use:

  • Values 100 mm or greater, or Single-digit values (like X = 5, Z = 3 0r X = 60, Z = 4)

Anything in between tends to work fine. I'm not sure if it's an issue in the math, or just a logic bug.


Project Details

  • Arduino Board: Uno (basic)

  • Servo Pins:

    • Base: Pin 3 (not in use because I am just using the X Z plane for now)

    • Shoulder: Pin 5

    • Elbow: Pin 6

  • Link Lengths:

    • Shoulder to elbow: 100 mm

    • Elbow to wrist: 100 mm

  • Planes Used: X-Z (ignoring Y for now)

  • No gripper:

  • Hardware Arduino uno, two 9g servos (shoulder, Elbow) both have a 5v’s supplied
    I have added the base servo as well not to sure if its needed or not (hight torque servo ā€black oneā€)

I’m using the standard Servo.H and Maths.H library and calculating IK using the Law of Cosines and Pythagoras theorem. Below is the code I’m using:

Cang =  hypotenuse 
ABangle = is the a and b angels in a triangle
ABang = random variable (slightly relating to ABangle)
  float X = 75; //these are the current cordites
  float Z = 90;
#include <Servo.h>
#include <math.h>

Servo bServo;
Servo shServo;
Servo elServo;

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

  bServo.attach(3);
  shServo.attach(5);
  elServo.attach(6);
}
//----------------------------------------------
void loop() {

  kinamatics();
}
//----------------------------------------------
void kinamatics() {

  float X = 75;
  float Z = 90;

  float C = calculateHypotenuse(X, Z);

  float numerator = (100 * 100 + C * C - 100 * 100);
  float denominator = (2 * 100 * C);
  float angleRad = acos(numerator / denominator);
  float ABang = angleRad * 180 / PI;

  //float Cang = (180 - (2 * ABang));

  float ABangle = (ABang * 2);
  float Cang = (180 - ABangle);

  Serial.print("Angle Cs disstace: ");
  Serial.println(C);


  Serial.print("Angle Sh in degrees: ");
  Serial.println(ABang);

  Serial.print("Angle El in degrees: ");
  Serial.println(Cang);

  shServo.write(ABang);
  elServo.write(Cang);
  delay(10000);
}
//----------------------------------------------
float calculateHypotenuse(float X, float Z) {
  // Calculate the square of a and b
  float XSquared = pow(X, 2);
  float ZSquared = pow(Z, 2);

  // Calculate the sum of squares
  float sumOfSquares = XSquared + ZSquared;

  // Calculate the square root of the sum
  float c = sqrt(sumOfSquares);

  return c;
}

Some Images

What I’ve Observed

  • For positions like (X=75, Z=90), the arm moves accurately.

  • For positions like (X=105, Z=90) or (X=3, Z=2), it fails or behaves oddly.

  • No compile errors—just strange behaviour or the arm just folds in on its self

Questions

  • Am I missing an angle offset or servo range issue?

  • Could this be due to acos() receiving a value outside [-1,1]?

I'm very happy to provide more information Like test values if needed. This is my first IK project, and first forum post so any help would be really appreciated.

Thanks

(it only let me add 3 photos)

Please edit your first post here (DON'T add another one!) and, as the forum rules require, enclose your code inside "CODE" tags. Without it, the code is almost unreadable and not very usable for testing your code and helping you.

Use the small pencil button :pencil2: below your post to edit it, select the code section and press the <CODE/> button, then save it.
Thanks.

1 Like

Welcome to the forum

Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'

Use code tags (the < CODE/ > icon above the compose window) to make it easier to read and copy for examination

https://forum.arduino.cc/t/how-to-get-the-best-out-of-this-forum

Please post your full sketch, using code tags when you do

Posting your code using code tags prevents parts of it being interpreted as HTML coding and makes it easier to copy for examination

In my experience the easiest way to tidy up the code and add the code tags is as follows

Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

It is also helpful to post error messages in code tags as it makes it easier to scroll through them and copy them for examination

1 Like

Hey sorry about that one mate hope I have fixed it enough but the link u provide wouldn’t let me view it so I hope what I have change has made it a little bit more useable

Try this link

(post deleted by author)

I can't look closer at your code, I was trying to see where your maths might have gone off the rails.

Here is an expression, not your problem:

100 * 100 + C * C - 100 * 100

Isn't that just C * C?

Here

is a good question. Does that happen? Add printing. See if. See what gets returned when.

Is the printing you do plausible or does it just reflect the flaws?

a7

Are you sure that both servos can turn all the way to 0 (zero) and all the way to 180 degrees?
Here's a simple test sketch.

/*
Connect servo to pin 9 on UNO or Nano.
 Try this test sketch with the Servo library to see how your
 servo responds to different settings, type a position
 (0 to 180) or if you type a number greater than 180 it will be
 interpreted as microseconds(544 to 2400), in the top of serial
 monitor and hit [ENTER], start at 90 (or 1472) and work your
 way toward zero (544) 5 degrees (or 50 micros) at a time, then
 toward 180 (2400). 
*/
#include <Servo.h>
Servo servo;

void setup() {
  // initialize serial:
  Serial.begin(9600); // set serial monitor baud rate to match
                      // set serial monitor line ending to "NewLine"
  servo.write(90);
  servo.attach(9);
  prntIt();
}

void loop() {
  // if there's any serial available, read it:
  while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:
    int pos = Serial.parseInt();
    if(Serial.read() == '\n'){} //skip 1 second delay
    pos = constrain(pos, 0, 2400);
    servo.write(pos);
    prntIt();
  }
}
void prntIt()
{
  Serial.print("  degrees = "); 
  Serial.print(servo.read());
  Serial.print("\t");
  Serial.print("microseconds =  ");
  Serial.println(servo.readMicroseconds());
}  

Hi, @randomlad255
Welcome to the forum.

Would it be worth putting in brackets rather than assume BODMAS?

float numerator = ((100 * 100) + (C * C) - (100 * 100));

If what you are trying do is;

100 squared plus c squared - 100 squared

which will equal C squared.

What are you trying to do with this equation?

Can you please draw a diagram showing your angles and sides.

Tom.... :smiley: :+1: :coffee: :australia:

Hi, @randomlad255
Here is what I beleive is your first calculation.

Cos A = X / C

A = Acos X / C radians

Try this with the IDE monitor open.

#include <Servo.h>
#include <math.h>

Servo bServo;
Servo shServo;
Servo elServo;

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

  bServo.attach(3);
  shServo.attach(5);
  elServo.attach(6);
}
//----------------------------------------------
void loop() {

  kinamatics();
}
//----------------------------------------------
void kinamatics() {

  float X = 75;
  float Z = 90;

  float C = calculateHypotenuse(X, Z);
Serial.print("Hypotenuse ");
Serial.print (C);
Serial.print( "     ");
 // float numerator = (100 * 100 + C * C - 100 * 100);
//  float denominator = (2 * 100 * C);
    float angleRad = acos(X / C);
  float Aang = angleRad * 180 / PI;
  float Bang = 180 - 90 - Aang;
  Serial.print (" Angle A ");
  Serial.print(Aang);
  Serial.print("  Angle B  ");
  Serial.println(Bang);

}
//----------------------------------------------
float calculateHypotenuse(float X, float Z) {
  // Calculate the square of a and b
  float XSquared = pow(X, 2);
  float ZSquared = pow(Z, 2);

  // Calculate the sum of squares
  float sumOfSquares = XSquared + ZSquared;

  // Calculate the square root of the sum
  float c = sqrt(sumOfSquares);

  return c;
}

Tom.... :smiley: :+1: :coffee: :australia:
PS. Feel free to edit, find errors etc, I haven't had a coffee for 6 hours.

You should not use "100" and "100" but L1 and L2.

float L1 = 100;
float L2 = 100;

Shouldn't the numerator be (not using the hypotenuse):

float numerator = (X^2 + y^2) + (L1^2 - L2^2)

And the denominator be:

float denominator = (2 * L1) * (sqrt(X^2 + y^2))) // L1 = Shoulder to elbow: 100 mm

X and Y are the movement and L1 and L2 are the lengths...

hey @TomGeorge I ran your code I got these vales from the serial monitor

(I assume it wasn’t meant to make the robot move because there was no servo Write)

so I haven’t got the measurements for the pos it moved to

Hypotenuse 117.15      Angle A 50.19  Angle B  39.81

Your image really represents what I am trying to do But its is the next step that I am having a bit of trouble with

I am trying to find the green angels to write to the servos and am not to sure of the correct formula to do that where the

float numerator = (100 * 100 + C * C - 100 * 100);

came from witch is the Law of Cosines but looking back it was a bit dumb because as people have pointed out it just equals C
so I don’t think that pythagorizes is what the problem is but I could be missing something

But if you have a way to make the 2 reds and and blue line into 2 right angel triangles so it can find that angels. That’s seems to be the way I've been finding how most people do it but cant find any source codešŸ˜’ ….
Regards.

but @xfpd Made a really good point I am going to spend the day trouble shooting with that for now

You should label all sides and vertices of all triangles.

Triangle (C EL SH) has two equal sides. Find isosceles triangle theorem to find angles... AND... all three sides of the lower triangle are known (C 75 90)... you can calculate all remaining angles of (C SH EL).

because the formula used is incorrect.

1 Like