Can anyone help me with the code for a autonomous 3 omni wheeled having encoders and will have holonomoic drive configuration?

My robot is moving in X & -X direction only using 2 motors, how to drive it in Y & -y direction ?

#define ENCA1 2
#define ENCB1 3
#define PWM1 5
#define IN1_1 25
#define IN2_1 24

#define ENCA2 18
#define ENCB2 19
#define PWM2 6
#define IN1_2 27
#define IN2_2 26

#define ENCA3 20
#define ENCB3 21
#define PWM3 4
#define IN1_3 22
#define IN2_3 23

int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
long prevT1 = 0;
long prevT2 = 0;
long prevT3 = 0;
float eprev1 = 0;
float eintegral1 = 0;
float eprev2 = 0;
float eintegral2 = 0;
float eprev3 = 0;
float eintegral3 = 0;

int targetX = 0; // Set the desired target position in X-direction
int targetY = 800;  // Set the desired target position in Y-direction

bool stopping1 = false; // Flag for motor 1 stopping
bool stopping2 = false; // Flag for motor 2 stopping
bool stopping3 = false; // Flag for motor 3 stopping

void setup() {
  Serial.begin(9600);
  pinMode(IN1_1, OUTPUT);
  pinMode(IN2_1, OUTPUT);
  pinMode(IN1_2, OUTPUT);
  pinMode(IN2_2, OUTPUT);
  pinMode(IN1_3, OUTPUT);
  pinMode(IN2_3, OUTPUT);
  pinMode(PWM1, OUTPUT);
  pinMode(PWM2, OUTPUT);
  pinMode(PWM3, OUTPUT);
  analogWrite(PWM1, 0);
  analogWrite(PWM2, 0);
  analogWrite(PWM3, 0);
  pinMode(ENCA1, INPUT);
  pinMode(ENCB1, INPUT);
  pinMode(ENCA2, INPUT);
  pinMode(ENCB2, INPUT);
  pinMode(ENCA3, INPUT);
  pinMode(ENCB3, INPUT);
  attachInterrupt(digitalPinToInterrupt(ENCA1), readEncoder1, RISING);
  attachInterrupt(digitalPinToInterrupt(ENCA2), readEncoder2, RISING);
  attachInterrupt(digitalPinToInterrupt(ENCA3), readEncoder3, RISING);
  Serial.println("target pos");
}

void loop() {
  // PID constants
  float kp = 1;
  float kd = 0.025;
  float ki = 0.0;

  // time differences
  long currT1 = micros();
  long currT2 = micros();
  long currT3 = micros();
  float deltaT1 = ((float)(currT1 - prevT1)) / (1.0e6);
  float deltaT2 = ((float)(currT2 - prevT2)) / (1.0e6);
  float deltaT3 = ((float)(currT3 - prevT3)) / (1.0e6);
  prevT1 = currT1;
  prevT2 = currT2;
  prevT3 = currT3;

  // Calculate the average position of all encoders
  long averagePositionX = (pos1 + pos2) / 2;
  long averagePositionY = pos3;

  // Calculate the error as the difference between the target positions
  int errorX = targetX - averagePositionX;
  int errorY = targetY - averagePositionY;

  // Calculate derivatives and integrals for both axes
  float dedt1 = (errorX - eprev1) / deltaT1;
  float dedt2 = (errorX - eprev2) / deltaT2;
  float dedt3 = (errorY - eprev3) / deltaT3;
  eintegral1 = eintegral1 + errorX * deltaT1;
  eintegral2 = eintegral2 + errorX * deltaT2;
  eintegral3 = eintegral3 + errorY * deltaT3;

  // Calculate control signals for all motors
  float u1 = kp * errorX + kd * dedt1 + ki * eintegral1;
  float u2 = kp * errorX + kd * dedt2 + ki * eintegral2;
  float u3 = kp * errorY + kd * dedt3 + ki * eintegral3;

  // Calculate motor powers
  float pwr1 = fabs(u1);
  float pwr2 = fabs(u2);
  float pwr3 = fabs(u3);
  if (pwr1 > 255) {
    pwr1 = 255;
  }
  if (pwr2 > 255) {
    pwr2 = 255;
  }
  if (pwr3 > 255) {
    pwr3 = 255;
  }

  // Set motor directions
  int dir1 = (u1 >= 0) ? 1 : -1;
  int dir2 = (u2 >= 0) ? 1 : -1;
  int dir3 = (u3 >= 0) ? 1 : -1;

  // Signal the motors
  setMotor(dir1, pwr1, PWM1, IN1_1, IN2_1);
  setMotor(dir2, pwr2, PWM2, IN1_2, IN2_2);
  setMotor(dir3, pwr3, PWM3, IN1_3, IN2_3);

  // Store previous errors
  eprev1 = errorX;
  eprev2 = errorX;
  eprev3 = errorY;

  Serial.print(targetX);
  Serial.print(" ");
  Serial.print(targetY);
  Serial.print(" ");
  Serial.print(averagePositionX);
  Serial.print(" ");
  Serial.print(averagePositionY);
  Serial.println();

  // Check if stopping is needed for all motors
  if (targetX == averagePositionX && targetY == averagePositionY && !stopping1 && !stopping2 && !stopping3) {
    stopping1 = true;
    stopping2 = true;
    stopping3 = true;
  }

  // Gradually reduce motor speed for smoother stopping
  if (stopping1) {
    pwr1 -= 5; // Adjust the decrement value for desired stopping speed
    if (pwr1 <= 0) {
      pwr1 = 0;
      stopping1 = false;
    }
    analogWrite(PWM1, pwr1);
  }

  if (stopping2) {
    pwr2 -= 5; // Adjust the decrement value for desired stopping speed
    if (pwr2 <= 0) {
      pwr2 = 0;
      stopping2 = false;
    }
    analogWrite(PWM2, pwr2);
  }

  if (stopping3) {
    pwr3 -= 5; // Adjust the decrement value for desired stopping speed
    if (pwr3 <= 0) {
      pwr3 = 0;
      stopping3 = false;
    }
    analogWrite(PWM3, pwr3);
  }
}

void setMotor(int dir, int pwmVal, int pwm, int in1, int in2) {
  analogWrite(pwm, pwmVal);
  if (dir == 1) {
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
  } else if (dir == -1) {
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
  } else {
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
  }
}

void readEncoder1() {
  int b = digitalRead(ENCB1);
  if (b > 0) {
    pos1++;
  } else {
    pos1--;
  }
}

void readEncoder2() {
  int b = digitalRead(ENCB2);
  if (b > 0) {
    pos2++;
  } else {
    pos2--;
  }
}

void readEncoder3() {
  int b = digitalRead(ENCB3);
  if (b > 0) {
    pos3++;
  } else {
    pos3--;
  }
}

Hello kumar986

Welcome to the worldbest Arduino forum ever.

I assume that you have written the programme by yourself, then it is quite easy to find the error.

There's a trick to figuring out why something isn't working:

Use a logic analyzer to see what happens.
Put Serial.print statements at various places in the code to see the values of variables, especially ones that control the motors, and determine whether they meet your expectations.

Have a nice day and enjoy coding in C++.

I'm not sure how to solve your problem, but I do know that you really need to learn to use arrays. Your code is 3x longer than it should be right now.

This is how you declare constants in C

  // PID constants
  const float kp = 1;
  const float kd = 0.025;
  const float ki = 0.0;

This seems unnecessary. currT1, currT2 and currT3 will always have the same value. Likewise deltaT1, deltaT2 and deltaT3 will always have the same value. Same for prevT1, prevT2 and prevT3.

Can you explain why averagePositionX is calculated as an average of 2 encoder positions, but averagePositionY is not? And why pos1 and pos2 are averaged to calculate averagePositionX? I suspect this is somehow related to your moving in X but not Y directions problem.

all in all it seems to be a generated code.

yeah, thanks for pointing the issue.

Yeah, it's a generated base code. I want to know how to apply the hlonomic drive function in the robot. I have tried different codes but they are not working, that's why I'm seeking help of the community.

If you are serious about wanting help, you should post links, pictures and schematics. Without those, the forum members cannot understand how this robot can work.

Ask the robot again until you have had received the expected answer.

One answer could be "42" :grinning:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.