// This alternate version of the code does not require
// atomic.h. Instead, interrupts() and noInterrupts()
// are used. Please use this code if your
// platform does not support ATOMIC_BLOCK.
// Pins
#define ENCA 2
#define ENCB 3
#define PWM 5
#define IN1 6
#define IN2 7
#define out 8
// globals
long prevT = 0;
int posPrev = 0;
// Use the "volatile" directive for variables
// used in an interrupt
volatile int pos_i = 0;
volatile float velocity_i = 0;
volatile long prevT_i = 0;
float v1Filt = 0;
float v1Prev = 0;
float v2Filt = 0;
float v2Prev = 0;
float eintegral = 0;
void setMotor(int dir, int pwmVal, int pwm, int in1, int in2){
analogWrite(pwm,pwmVal); // Motor speed
if(dir == 1){
// Turn one way
digitalWrite(in1,HIGH);
digitalWrite(in2,LOW);
}
else if(dir == -1){
// Turn the other way
digitalWrite(in1,LOW);
digitalWrite(in2,HIGH);
}
else{
// Or dont turn
digitalWrite(in1,LOW);
digitalWrite(in2,LOW);
}
}
void readEncoder(){
// Read encoder B when ENCA rises
int b = digitalRead(ENCB);
int increment = 0;
if(b>0){
// If B is high, increment forward
increment = 1;
}
else{
// Otherwise, increment backward
increment = -1;
}
pos_i = pos_i + increment;
/*
// Compute velocity with method 2
long currT = micros();
float deltaT = ((float) (currT - prevT_i))/1.0e6;
velocity_i = increment/deltaT;
prevT_i = currT;
*/
}
ISR(TIMER1_COMPA_vect) // timer1 Interrupt ทุกๆ 0.1 วินาที
{
digitalWrite(out,HIGH);
// read the position and velocity
int pos = 0;
float velocity2 = 0;
//noInterrupts(); // disable interrupts temporarily while reading
pos = pos_i;
velocity2 = velocity_i;
//interrupts(); // turn interrupts back on
// Compute velocity with method 1
long currT = micros();
float deltaT = ((float) (currT-prevT))/1.0e6;
float velocity1 = (pos - posPrev)/deltaT;
posPrev = pos;
prevT = currT;
// Convert count/s to RPM
float v1 = velocity1/200.0*60.0;
float v2 = velocity2/200.0*60.0;
// Low-pass filter (25 Hz cutoff)
v1Filt = 0.854*v1Filt + 0.0728*v1 + 0.0728*v1Prev;
v1Prev = v1;
v2Filt = 0.854*v2Filt + 0.0728*v2 + 0.0728*v2Prev;
v2Prev = v2;
// Set a target
float vt = 70*(sin(currT/1e6)>0);
// Compute the control signal u
float kp = 5;
float ki = 10;
float kd = 5;
float e = vt-v1Filt;
eintegral = eintegral + e*deltaT;
float u = kp*e + ki*eintegral + kd*deltaT;
//u = 70;
// Set the motor speed and direction
int dir = 1;
if (u<0){
dir = -1;
}
int pwr = (int) fabs(u);
if(pwr > 255){
pwr = 255;
}
setMotor(dir,pwr,PWM,IN1,IN2);
Serial.print(">0:");
Serial.println(0);
Serial.print(">vt:");
Serial.println(vt);
Serial.print(">v1Filt:");
Serial.println(v1Filt);
digitalWrite(out,LOW);
}
void setup() {
Serial.begin(115200);
pinMode(ENCA,INPUT);
pinMode(ENCB,INPUT);
pinMode(PWM,OUTPUT);
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
pinMode(out,OUTPUT);
attachInterrupt(digitalPinToInterrupt(ENCA),
readEncoder,RISING);
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 625/2; // 0.1 sec.
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}
void loop() {
delay(1);
}