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

// Deklarasi servo motor
Servo servo1;
Servo servo2;


// Panjang link
const float L1 = 10.0; // Panjang link 1 dalam cm
const float L2 = 10.0; // Panjang link 2 dalam cm

// Faktor skala
const float alpha = 0.1;

// Fungsi untuk menghitung Jacobian
void calculateJacobian(float theta1, float theta2, float &j11, float &j12, float &j21, float &j22) {
  j11 = -L1 * sin(theta1) - L2 * sin(theta1 + theta2);
  j12 = -L2 * sin(theta1 + theta2);
  j21 = L1 * cos(theta1) + L2 * cos(theta1 + theta2);
  j22 = L2 * cos(theta1 + theta2);
}

// Fungsi untuk menghitung pseudo-inverse dari Jacobian
void calculatePseudoInverseJacobian(float j11, float j12, float j21, float j22, float &j11_inv, float &j12_inv, float &j21_inv, float &j22_inv) {
  float det = j11 * j22 - j12 * j21;
  if (det == 0) {
    // Jika determinan nol, gunakan metode lain atau tambahkan regularisasi
    j11_inv = j12_inv = j21_inv = j22_inv = 0;
  } else {
    float inv_det = 1.0 / det;
    j11_inv = j22 * inv_det;
    j12_inv = -j12 * inv_det;
    j21_inv = -j21 * inv_det;
    j22_inv = j11 * inv_det;
  }
}

// Fungsi untuk menghitung kinematika maju
void forwardKinematics(float theta1, float theta2, float &x, float &y) {
  x = L1 * cos(theta1) + L2 * cos(theta1 + theta2);
  y = L1 * sin(theta1) + L2 * sin(theta1 + theta2);
}

// Fungsi untuk menghitung kinematika balik menggunakan Pseudo-Inverse Jacobian
void inverseKinematicsPseudoInverse(float x_d, float y_d, float &theta1, float &theta2) {
  const int maxIter = 100;
  const float tol = 0.01;

  for (int i = 0; i < maxIter; i++) {
    float x, y;
    forwardKinematics(theta1, theta2, x, y);

    float ex = x_d - x;
    float ey = y_d - y;

    if (sqrt(ex * ex + ey * ey) < tol) break;

    float j11, j12, j21, j22;
    calculateJacobian(theta1, theta2, j11, j12, j21, j22);

    float j11_inv, j12_inv, j21_inv, j22_inv;
    calculatePseudoInverseJacobian(j11, j12, j21, j22, j11_inv, j12_inv, j21_inv, j22_inv);

    float dtheta1 = alpha * (j11_inv * ex + j12_inv * ey);
    float dtheta2 = alpha * (j21_inv * ex + j22_inv * ey);

    theta1 += dtheta1;
    theta2 += dtheta2;
  }

  theta1 = theta1 * 180.0 / PI;
  theta2 = theta2 * 180.0 / PI;
}

void setup() {
  servo1.attach(9);
  servo2.attach(10);
}

void loop() {
  float x_d = 15.0;
  float y_d = 10.0;

  float theta1 = 0;
  float theta2 = 0;

  inverseKinematicsPseudoInverse(x_d, y_d, theta1, theta2);

  servo1.write(theta1);
  servo2.write(theta2);

  delay(2000);
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5