I'm working on a robotics project where an arduino nano is acting as the motion controller. I'm trying to use a trapezoidal motion profile generator and PID loop to follow that profile, but I found out the motion was quite jerky and I assumed it's because both the motion profile and the PID run at the same speed (10ms loop using timer interrupt library)
#include <TimerOne.h>
void setup() {
Timer1.initialize(10000);
Timer1.attachInterrupt(Compute);
}
now I want to use two seperate loops, one running at the same 10ms interval for the profile generation and one running at 1ms for the PID (I'm not sure if the motors can actually act that quickly, but I can adjust the timings a bit), this way the PID has about 10 loops to get to the desired position accurately, reducing the jerky motion.
I'm not sure how I can set up two different interrupts using that library or by setting the flags like TCCR0A to generate the desired interrupt timers.
Here's the actual "Compute" function in case it's relevant (there are some bugs regarding the direction and it's using two different methods for generating the profile, also I'm changing it so don't think it matters, but just in case it does, I posted it)
void Compute(){
int dir;
if (setPoint > target){
dir = 1;
} else if (setPoint < target){
dir = -1;
}
if (mode == 1) {
target += v*dir;
if (abs(setPoint - target) <= turningPoint){
v -= acceleration;
} else {
if (v < maxV){
v += acceleration;
}
}
if (abs(target) >= abs(setPoint)){
target = setPoint;
mode = 0;
v = 0;
Serial.println("Finished!");
}
#ifdef DEBUG
printDebug();
#endif
} else if (mode ==2){
target += v*dir;
if (phase == 1 and v < reachableV){
v += acceleration;
if (v >= reachableV){
phase = 3;
v = reachableV;
}
} else if (phase == 3){
v -= acceleration;
if (v <= 0){
target = setPoint;
mode = 0;
v = 0;
phase = 0;
Serial.println("Finished!");
}
}
#ifdef DEBUG
printDebug();
#endif
}
error = target- pos;
/////////////////////////////////////////////////
PID_P = kp * error;
if (PID_P > outMax) PID_P = outMax;
if (PID_P < outMin) PID_P = outMin;
/////////////////////////////////////////////////
if (abs(error) < 50){
PID_I += ki * error * sampleTime;
} else {
PID_I *= 0.8;
}
/////////////////////////////////////////////////
PID_D = kd * (pos - lastPos) / sampleTime;
if (PID_D > outMax) PID_D = outMax;
if (PID_D < outMin) PID_D = outMin;
/////////////////////////////////////////////////
output = PID_P - PID_D + PID_I;
if (output > outMax) output = outMax;
if (output < outMin) output = outMin;
/////////////////////////////////////////////////
lastPos = pos;
if (output < 0){
digitalWrite(DIR,1);
} else {
digitalWrite(DIR,0);
}
analogWrite(PWM,abs(output));
/////////////////////////////////////////////////
}
p.s: I'm most likly going to use the PID library instead of trying to write my own like I currently have the code.
loop()