*/
-#define TWI_ACK TWCR = (1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
-#define TWI_RESET TWCR &= ~((1 << TWSTO) | (1 << TWEN)); TWI_ACK
-#define TWI_NAK TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
-
-#define KP 0.039
-#define KI 0.08
+#define KP 0.062
+#define KI 0.12
#define KD 0.0
#define PID_T 0.01
-// wheel diameter=12cm, encoder=48cpr, gear ratio=1:34, real wheel diameter: 0.12454m
-#define STEP_PER_M_AVG 4171.4
-#define STEP_PER_M_LEFT (STEP_PER_M_AVG)
-#define STEP_PER_M_RIGHT (STEP_PER_M_AVG)
-#define WHEEL_DIST 0.36923 // Real: 0.252
+// wheel diameter=12cm, encoder=48cpr, gear ratio=1:47
+// STEP_PER_M = 48*47/(d*pi)
+// Left real diameter: 0.12808, Right real diameter: 0.121
+#define STEP_PER_M 5770.8
+#define STEP_PER_M_LEFT (STEP_PER_M)
+#define STEP_PER_M_RIGHT (STEP_PER_M)
+#define WHEEL_DIST 0.39912 // Measured: 0.252
+#define PWM_BREAK INT16_MIN
+
+#define TWI_ACK TWCR = (1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
+#define TWI_RESET TWCR &= ~((1 << TWSTO) | (1 << TWEN)); TWI_ACK
+#define TWI_NAK TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
+#define ENABLE_PWM_MOTOR1 TCCR1A |= (1 << COM1A1)
+#define ENABLE_PWM_MOTOR2 TCCR1A |= (1 << COM1B1)
+#define ENABLE_PWM_MOTOR3 TCCR2 |= (1 << COM21);
+#define ENABLE_PWM_MOTOR4 TCCR0 |= (1 << COM01);
+#define DISABLE_PWM_MOTOR1 TCCR1A &= ~(1 << COM1A1)
+#define DISABLE_PWM_MOTOR2 TCCR1A &= ~(1 << COM1B1)
+#define DISABLE_PWM_MOTOR3 TCCR2 &= ~(1 << COM21);
+#define DISABLE_PWM_MOTOR4 TCCR0 &= ~(1 << COM01);
+
enum mode {
MOTOR_MANUAL,
static volatile int16_t speed2_wish=0;
static volatile int16_t speed3_wish=0;
static volatile int16_t speed4_wish=0;
+static volatile int16_t speed1_wish_old=0;
+static volatile int16_t speed2_wish_old=0;
+static volatile int16_t speed3_wish_old=0;
+static volatile int16_t speed4_wish_old=0;
static volatile uint8_t run_update=0;
static volatile int16_t speed1=0; // step/s
static volatile int16_t speed2=0;
static int16_t m3_old=SHRT_MIN;
static int16_t m4_old=SHRT_MIN;
- error_state = ~((PIND & 0x40)>>3 | (PINB & 0x07)) & 0xf;
+ error_state &= 0xf0; // clear lower bits
+ error_state |= ~((PIND & 0x40)>>3 | (PINB & 0x07)) & 0xf;
if (m1_old != motor1) { // update only when changed
if (motor1 == 0) {
// stop
PORTC &= ~(1 << 3) & ~(1 << 2);
+ DISABLE_PWM_MOTOR1;
+ } else if (motor1 == PWM_BREAK) {
+ PORTC |= (1 << 3) | (1 << 2);
+ ENABLE_PWM_MOTOR1;
} else if ((!motor1_switch && motor1 > 0) || (motor1_switch && motor1 < 0)) {
// forward
uint8_t tmp=PORTC;
tmp &= ~(1 << 3);
tmp |= (1 << 2);
PORTC = tmp;
+ ENABLE_PWM_MOTOR1;
} else { // motor1 < 0
// backward
uint8_t tmp=PORTC;
tmp &= ~(1 << 2);
tmp |= (1 << 3);
PORTC = tmp;
+ ENABLE_PWM_MOTOR1;
}
m1_old = motor1;
if (motor2 == 0) {
// stop
PORTC &= ~(1 << 5) & ~(1 << 4);
+ DISABLE_PWM_MOTOR2;
+ } else if (motor2 == PWM_BREAK) {
+ PORTC |= (1 << 5) | (1 << 4);
+ ENABLE_PWM_MOTOR2;
} else if ((!motor2_switch && motor2 > 0) || (motor2_switch && motor2 < 0)) {
// forward
uint8_t tmp=PORTC;
tmp &= ~(1 << 5);
tmp |= (1 << 4);
PORTC = tmp;
+ ENABLE_PWM_MOTOR2;
} else { // motor2 < 0
// backward
uint8_t tmp=PORTC;
tmp &= ~(1 << 4);
tmp |= (1 << 5);
PORTC = tmp;
+ ENABLE_PWM_MOTOR2;
}
m2_old = motor2;
if (motor3 == 0) {
// stop
PORTC &= ~(1 << 7) & ~(1 << 6);
+ DISABLE_PWM_MOTOR3;
+ } else if (motor3 == PWM_BREAK) {
+ PORTC |= (1 << 7) | (1 << 6);
+ ENABLE_PWM_MOTOR3;
} else if ((!motor3_switch && motor3 > 0) || (motor3_switch && motor3 < 0)) {
// forward
uint8_t tmp=PORTC;
tmp &= ~(1 << 7);
tmp |= (1 << 6);
PORTC = tmp;
+ ENABLE_PWM_MOTOR3;
} else { // motor3 < 0
// backward
uint8_t tmp=PORTC;
tmp &= ~(1 << 6);
tmp |= (1 << 7);
PORTC = tmp;
+ ENABLE_PWM_MOTOR3;
}
m3_old = motor3;
if (motor4 == 0) {
// stop
PORTD &= ~(1 << 3) & ~(1 << 2);
+ DISABLE_PWM_MOTOR4;
+ } else if (motor4 == PWM_BREAK) {
+ PORTD |= (1 << 3) | (1 << 2);
+ ENABLE_PWM_MOTOR4;
} else if ((!motor4_switch && motor4 > 0) || (motor4_switch && motor4 < 0)) {
// forward
uint8_t tmp=PORTD;
tmp &= ~(1 << 3);
tmp |= (1 << 2);
PORTD = tmp;
+ ENABLE_PWM_MOTOR4;
} else { // motor4 < 0
// backward
uint8_t tmp=PORTD;
tmp &= ~(1 << 2);
tmp |= (1 << 3);
PORTD = tmp;
+ ENABLE_PWM_MOTOR4;
}
m4_old = motor4;
static int32_t esum3=0;
static int32_t esum4=0;
+ // protect motors from damage if stalling
+ if (labs(esum1) > 140000 && speed1 == 0) {
+ motor1 = 0;
+ motor1_mode = MOTOR_MANUAL;
+ error_state |= (1<<4);
+ esum1 = 0;
+ }
+ if (labs(esum2) > 140000 && speed2 == 0) {
+ motor2 = 0;
+ motor2_mode = MOTOR_MANUAL;
+ error_state |= (1<<5);
+ esum2 = 0;
+ }
+ if (labs(esum3) > 140000 && speed3 == 0) {
+ motor3 = 0;
+ motor3_mode = MOTOR_MANUAL;
+ error_state |= (1<<6);
+ esum3 = 0;
+ }
+ if (labs(esum4) > 140000 && speed4 == 0) {
+ motor4 = 0;
+ motor4_mode = MOTOR_MANUAL;
+ error_state |= (1<<7);
+ esum4 = 0;
+ }
+
if (motor1_mode == MOTOR_PID) {
+ if (speed1_wish != speed1_wish_old) {
+ if (abs(speed1_wish - speed1_wish_old) > 500) esum1 = 0;
+ speed1_wish_old = speed1_wish;
+ }
+
if (speed1_wish == 0) {
motor1 = 0;
eold1 = 0;
- esum1 = 0;
+ error_state &= ~(1<<4);
} else {
int16_t e = speed1_wish - speed1;
esum1+=e;
motor1 = KP*e + KI*PID_T*esum1 + KD/PID_T*(e - eold1);
eold1 = e;
- if (motor1 > 0 && speed1_wish < 0) motor1=0;
- else if (motor1 < 0 && speed1_wish > 0) motor1=0;
+ if (motor1 > 0 && speed1_wish < 0) motor1=PWM_BREAK;
+ else if (motor1 < 0 && speed1_wish > 0) motor1=PWM_BREAK;
else if (motor1 > 255) motor1 = 255;
else if (motor1 < -255) motor1 = -255;
}
}
if (motor2_mode == MOTOR_PID) {
+ if (speed2_wish != speed2_wish_old) {
+ if (abs(speed2_wish - speed2_wish_old) > 500) esum2 = 0;
+ speed2_wish_old = speed2_wish;
+ }
+
if (speed2_wish == 0) {
motor2 = 0;
eold2 = 0;
- esum2 = 0;
+ error_state &= ~(1<<5);
} else {
int16_t e = speed2_wish - speed2;
esum2+=e;
motor2 = KP*e + KI*PID_T*esum2 + KD/PID_T*(e - eold2);
eold2 = e;
- if (motor2 > 0 && speed2_wish < 0) motor2=0;
- else if (motor2 < 0 && speed2_wish > 0) motor2=0;
+ if (motor2 > 0 && speed2_wish < 0) motor2=PWM_BREAK;
+ else if (motor2 < 0 && speed2_wish > 0) motor2=PWM_BREAK;
else if (motor2 > 255) motor2 = 255;
else if (motor2 < -255) motor2 = -255;
}
}
if (motor3_mode == MOTOR_PID) {
+ if (speed3_wish != speed3_wish_old) {
+ if (abs(speed3_wish - speed3_wish_old) > 500) esum3 = 0;
+ speed3_wish_old = speed3_wish;
+ }
+
if (speed3_wish == 0) {
motor3 = 0;
eold3 = 0;
- esum3 = 0;
+ error_state &= ~(1<<6);
} else {
int16_t e = speed3_wish - speed3;
esum3+=e;
motor3 = KP*e + KI*PID_T*esum3 + KD/PID_T*(e - eold3);
eold3 = e;
- if (motor3 > 0 && speed3_wish < 0) motor3=0;
- else if (motor3 < 0 && speed3_wish > 0) motor3=0;
+ if (motor3 > 0 && speed3_wish < 0) motor3=PWM_BREAK;
+ else if (motor3 < 0 && speed3_wish > 0) motor3=PWM_BREAK;
else if (motor3 > 255) motor3 = 255;
else if (motor3 < -255) motor3 = -255;
}
}
if (motor4_mode == MOTOR_PID) {
+ if (speed4_wish != speed4_wish_old) {
+ if (abs(speed4_wish - speed4_wish_old) > 500) esum4 = 0;
+ speed4_wish_old = speed4_wish;
+ }
+
if (speed4_wish == 0) {
motor4 = 0;
eold4 = 0;
- esum4 = 0;
+ error_state &= ~(1<<7);
} else {
int16_t e = speed4_wish - speed4;
esum4+=e;
motor4 = KP*e + KI*PID_T*esum4 + KD/PID_T*(e - eold4);
eold4 = e;
- if (motor4 > 0 && speed4_wish < 0) motor4=0;
- else if (motor4 < 0 && speed4_wish > 0) motor4=0;
+ if (motor4 > 0 && speed4_wish < 0) motor4=PWM_BREAK;
+ else if (motor4 < 0 && speed4_wish > 0) motor4=PWM_BREAK;
else if (motor4 > 255) motor4 = 255;
else if (motor4 < -255) motor4 = -255;
}
TWI_RESET;
// Motor 1 & 2
- // Timer 1: Fast PWM non-inverting mode, Top=255 => 15.625kHz
+ // Also used for PWM frequency TIMER1_FREQ (F_CPU/256)
+ // Timer 1: Fast PWM non-inverting mode, Top=255 => 19.531kHz
// Prescaler=1
- TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM10);
+ //TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM10);
+ // Avoid narrow spike on extreme pwm value 0 by not setting COM1*1
+ TCCR1A = (1 << WGM10);
TCCR1B = (1 << WGM12) | (1 << CS10);
OCR1A = 0;
OCR1B = 0;
// Motor 3
// Timer 2: Fast PWM non-inverting mode, Top=255
// Prescaler=1
- TCCR2 = (1 << WGM21) | (1 << WGM20) | (1 << COM21) | (1 << CS20);
+ //TCCR2 = (1 << WGM21) | (1 << WGM20) | (1 << COM21) | (1 << CS20);
+ // Avoid narrow spike on extreme pwm value 0 by not setting COM21
+ TCCR2 = (1 << WGM21) | (1 << WGM20) | (1 << CS20);
OCR2 = 0;
// Motor 4
// Timer 0: Fast PWM non-inverting mode, Top=255
// Prescaler=1
- TCCR0 = (1 << WGM01) | (1 << WGM00) | (1 << COM01) | (1 << CS00);
+ //TCCR0 = (1 << WGM01) | (1 << WGM00) | (1 << COM01) | (1 << CS00);
+ // Avoid narrow spike on extreme pwm value 0 by not setting COM01
+ TCCR0 = (1 << WGM01) | (1 << WGM00) | (1 << CS00);
OCR0 = 0;
printf("\r\nStart\r\n");
if (aft_handicap > 0) {
speed1_wish = speed_wish_left * (100-aft_handicap)/100.0;
- speed4_wish = speed_wish_right * (100-aft_handicap)/100.0;
+ speed3_wish = speed_wish_right * (100-aft_handicap)/100.0;
} else {
speed1_wish = speed_wish_left;
- speed4_wish = speed_wish_right;
+ speed3_wish = speed_wish_right;
}
if (front_handicap > 0) {
speed2_wish = speed_wish_left * (100-front_handicap)/100.0;
- speed3_wish = speed_wish_right * (100-front_handicap)/100.0;
+ speed4_wish = speed_wish_right * (100-front_handicap)/100.0;
} else {
speed2_wish = speed_wish_left;
- speed3_wish = speed_wish_right;
+ speed4_wish = speed_wish_right;
}
motor1_mode = MOTOR_PID;
motor2_mode = MOTOR_PID;
motor4_mode = MOTOR_PID;
}
- if (run_update >= 156) { // ~100Hz
+ if (run_update >= 195) { // TIMER1_FREQ/195 = ~100Hz
run_update=0;
update_pos();