hello eveyone im working on a obsstacle avoide maze solver robot for that im using 3 ir sensors 1 front ,1 left and one in right for direction . to keep the bot in straight line im using arduino 9 axis motion shield with pid control for that i have mapped right half from 0 to 180 and left half as 0 to -179 to use pid by ease . now my actual problem is when im taking turn i have to add or subtract the setpoint but after second addition or subtraction the setpoint goes beyond my limits then im unable to control it . for taking turn setpoint has to update .anyone have solution , idea ,suggetion regarding it will be very helpful to me .my second thought is to reset the shield ,im using "Arduino_NineAxesMotion.h" is there any method in this lib which can reset the value to zero ,i have alredy used the reset function in the library .please help me with this i will be very thankful to you
For PID steering, most people make the PID setpoint to be zero, and the PID error term equal to (desired heading - actual heading) or vice versa.
i know that but to take turn you have to chage setpoint, for that you have to add 90 or subtract 90 but when i do so after second turn the setpoint goes beyond limits
No. You change "desired heading" instead. The PID setpoint is always zero.
how can you explain little bit more that'll be more helpful
desired_heading = 0; //head due North (conventional yaw angle)
pid_loop();
...
desired_heading = 90; //now turn to head due East
pid_loop();
The PID error term is always (desired_heading - current_heading), with setpoint = 0.
if ((millis() - lastStreamTime) >= streamPeriod)
{
lastStreamTime = millis();
mySensor.updateEuler(); //Update the Euler data into the structure of the object
mySensor.updateCalibStatus(); //Update the Calibration Status
// Serial.println(mySensor.readEulerHeading());
input = mySensor.readEulerHeading(); //Heading data
if (input > 180) {
input = input - 360;
}
computePID(input);
// Serial.println(input);
// Serial.print("\t\t\t");
// Serial.println(out);
}
..........
double computePID(double inp) {
error = setpoint - inp;
P = kp * error;
D = kd * (lastError - error);
I = ki * (error + I);
lastError = error;
out = P + I + D;
// Serial.println(out);
return out;
}
these are functions for chage direction i have to add 90 or subtract 90 this is a problem ,my setpoint is initially zero . one more problem is the 9 axis motion shield does not reset its value to zero
if ((millis() - lastStreamTime) >= streamPeriod)
{
lastStreamTime = millis();
mySensor.updateEuler(); //Update the Euler data into the structure of the object
mySensor.updateCalibStatus(); //Update the Calibration Status
// Serial.println(mySensor.readEulerHeading());
input = mySensor.readEulerHeading(); //Heading data
if (input > 180) {
input = input - 360;
}
computePID(input);
// Serial.println(input);
// Serial.print("\t\t\t");
// Serial.println(out);
}
......
double computePID(double inp) {
error = setpoint - inp;
P = kp * error;
D = kd * (lastError - error);
I = ki * (error + I);
lastError = error;
out = P + I + D;
// Serial.println(out);
return out;
}
this is my code my setpoint is initially 0 for turn i have to add or subtract 90 .one more problem is 9 axis motion shield does not reset its value to zero by code we have to reset the microcontoller
Please use code tags when posting code. See the "How to get the best out of this forum" for posting instructions.
If "input" from the 9-axis is 0-360 (yaw angle in conventional navigation), this is all you need to do. "setpoint" MUST be set to zero.
mySensor.updateEuler(); //Update the Euler data into the structure of the object
mySensor.updateCalibStatus(); //Update the Calibration Status
// Serial.println(mySensor.readEulerHeading());
current_heading = mySensor.readEulerHeading(); //Heading data
input = desired_heading - current_heading; //may need to change sign
if (input > 180) input = input-360; // choose shortest turn
if (input < -180) input = input+360;
computePID(input);
...
If you want to be clever, this works too, and saves two lines of code:
input = (desired_heading - current_heading + 540)%360 - 180;
computePID(input);
facing sme issue for second turn for first turn it works well but for second turn it starts behave weired
flag =0 initially
void right_turn(int val) {
if (flag == 0) {
desired_heading=current_heading+90;
flag=1;
}
//here are motor functions
digitalWrite(AIN1, LOW);
digitalWrite(AIN2, HIGH);
analogWrite(PWMA, constrain(val + out, 0, 255));
digitalWrite(BIN1, HIGH);
digitalWrite(BIN2, LOW);
analogWrite(PWMB, constrain(val - out, 0, 255));
}
Always post all the code, using code tags.
I don't understand the problem. Try to clearly explain what you expect the robot to do, and what it does instead.
one more problem is the 9 axis motion shield does not reset its value to zero
I have no idea what that means. I think you misunderstand what the shield is supposed to do, which is to give you an absolute 3D orientation.
#include
#include "Arduino_NineAxesMotion.h" //Contains the bridge code between the API and the Arduino Environment
#include <Wire.h>
//IR pinouts
#define leftIR A2
#define frontIR A1
#define rightIR A0
//Motor pinouts
#define AIN1 5
#define AIN2 4
#define PWMA 3
#define BIN1 7
#define BIN2 6
#define PWMB 9
int val = 25 ;
int out = 0;
void right_turn(int val);
void left_turn(int val);
void back(int val);
void forward(int val);
double computePID(double orientation);
bool Lflag = 0;
bool Rflag = 0;
bool flag = 0;
//bool Mflag = 0;
// PID constants
double kp = 1;
double ki = 0.0;
double kd = 0.0;
double error;
double lastError;
double inp;
int input = 0;
double P;
double I;
double D;
// Setpoint
static int setpoint = 0;
int current_heading;
int desired_heading;
NineAxesMotion mySensor; //Object that for the sensor
unsigned long lastStreamTime = 0; //To store the last streamed time stamp
const int streamPeriod = 20; //To stream at 50Hz without using additional timers (time period(ms) =1000/frequency(Hz))
void setup() {
//IR Sensor pinouts
pinMode(leftIR, INPUT);
pinMode(frontIR, INPUT);
pinMode(rightIR, INPUT);
// motor setup pins
pinMode(AIN1, OUTPUT);
pinMode(AIN2, OUTPUT);
pinMode(BIN1, OUTPUT);
pinMode(BIN2, OUTPUT);
pinMode(PWMA, OUTPUT);
pinMode(PWMB , OUTPUT);
//Peripheral Initialization
Serial.begin(9600); //Initialize the Serial Port to view information on the Serial Monitor
Wire.begin(); //Initialize I2C communication to the let the library communicate with the sensor.
//Sensor Initialization
mySensor.initSensor(); //The I2C Address can be changed here inside this function in the library
mySensor.setOperationMode(OPERATION_MODE_NDOF); //Can be configured to other operation modes as desired
mySensor.setUpdateMode(MANUAL); //The default is AUTO. Changing to MANUAL requires calling the relevant update functions prior to calling the read functions
//Setting to MANUAL requires fewer reads to the sensor
}
void loop() {
int left = digitalRead(leftIR);
int front = digitalRead(frontIR);
int right = digitalRead(rightIR);
// Serial.print(left);
// Serial.print("\t");
// Serial.print(front);
// Serial.print("\t");
// Serial.println(right);
if ((millis() - lastStreamTime) >= streamPeriod)
{
lastStreamTime = millis();
mySensor.updateEuler(); //Update the Euler data into the structure of the object
mySensor.updateCalibStatus(); //Update the Calibration Status
// Serial.println(mySensor.readEulerHeading());
current_heading = mySensor.readEulerHeading(); //Heading data
input = desired_heading - current_heading; //may need to change sign
if (input > 180){
input = input - 360; // choose shortest turn
}
if (input < -180) {
input = input + 360;
}
computePID(input);
Serial.print("\t\t\t");
Serial.print(out);
Serial.print("\t\t\t");
Serial.println(setpoint);
}
if (front == HIGH ) {
forward(val);
}
else if (Rflag == 1) {
right_turn(val);
// Rflag = 0;
}
else if (Lflag == 1) {
left_turn(val);
// Lflag = 0;
}
// right only
else if (right == HIGH) {
Rflag = 1;
}
// left only
else if (left == HIGH) {
Lflag = 1;
}
else if (left == HIGH && front == HIGH && right == HIGH) {
back(val);
}
// else {
// forward(val);
// }
}
void forward(int val) {
digitalWrite(AIN1, HIGH);
digitalWrite(AIN2, LOW);
analogWrite(PWMA, constrain(val + out, 0, 255));
digitalWrite(BIN1, HIGH);
digitalWrite(BIN2, LOW);
analogWrite(PWMB, constrain(val - out , 0, 255));
}
void right_turn(int val) {
desired_heading = 90;
digitalWrite(AIN1, LOW);
digitalWrite(AIN2, HIGH);
analogWrite(PWMA, constrain(val - out, 0, 255));
digitalWrite(BIN1, HIGH);
digitalWrite(BIN2, LOW);
analogWrite(PWMB, constrain(val + out, 0, 255));
// delay(200);
// Serial.println("Right");
}
void left_turn(int val) {
if (flag == 0) {
desired_heading=desired_heading -90;
flag=1;
}
digitalWrite(AIN1, HIGH);
digitalWrite(AIN2, LOW);
analogWrite(PWMA, constrain(val + out, 0, 255));
digitalWrite(BIN1, LOW);
digitalWrite(BIN2, HIGH);
analogWrite(PWMB, constrain(val - out, 0, 255));
// delay(200);
Serial.println("left");
}
void back (int val) {
digitalWrite(AIN1, LOW );
digitalWrite(AIN2, HIGH);
analogWrite(PWMA, constrain(val + out, 0, 255));
digitalWrite(BIN1, LOW);
digitalWrite(BIN2, LOW);
analogWrite(PWMB, constrain(val - out, 0, 255));
}
double computePID(double inp) {
error = setpoint - inp;
P = kp * error;
D = kd * (lastError - error);
I = ki * (error + I);
lastError = error;
out = P + I + D;
// Serial.println(out);
return out;
}
this is my code i just want my bot to take turn according to sensor values thats it
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.