Einstein Filho
/
MANGUEBAJA2019_FRONT2
Mangue Baja team's code to frontal ECU
main.cpp
- Committer:
- einsteingustavo
- Date:
- 2019-07-24
- Revision:
- 0:12fb9cbcabcc
File content as of revision 0:12fb9cbcabcc:
#include "mbed.h" #include "stats_report.h" /* User libraries */ #include "definitions.h" #include "frontdefs.h" #include "CANMsg.h" #include "LSM6DS3.h" #include "Kalman.h" #define MB1 //#define MB2 /* Communication protocols */ CAN can(PB_8, PB_9, 1000000); Serial serial(PA_2, PA_3, 115200); LSM6DS3 LSM6DS3(PB_7, PB_6); /* I/O pins */ InterruptIn freq_sensor(PB_10, PullNone); InterruptIn choke_switch(PA_5, PullUp); // servomotor CHOKE mode InterruptIn run_switch(PA_7, PullUp); // servomotor RUN mode InterruptIn horn_button(PB_1, PullUp); InterruptIn headlight_switch(PB_0, PullUp); DigitalOut horn(PB_11); DigitalOut headlight(PA_1); /* Debug pins */ DigitalOut led(PC_13); PwmOut signal(PA_6); DigitalOut dbg1(PC_14); DigitalOut dbg2(PC_15); DigitalOut dbg3(PA_4); /* Interrupt services routine */ void canISR(); void servoSwitchISR(); void ticker2HzISR(); void ticker5HzISR(); void ticker20HzISR(); void tickerTrottleISR(); void frequencyCounterISR(); void hornISR(); void headlightISR(); /* Interrupt handlers */ void canHandler(); void throttleDebounceHandler(); void hornDebounceHandler(); void headlightDebounceHandler(); /* General functions*/ void setupInterrupts(); void filterMessage(CANMsg msg); void calcAngles(int16_t accx, int16_t accy, int16_t accz, int16_t grx, int16_t gry, int16_t grz, int16_t dt); void displayData(uint16_t vel, uint16_t Hz, uint16_t temp, bool comb, \ bool b, bool tl, bool fl, int16_t gp, int16_t gr, bool box); /* Debug variables */ Timer t; bool buffer_full = false; unsigned int t0, t1; /* Mbed OS tools */ Thread eventThread; EventQueue queue(1024); Ticker ticker2Hz; Ticker ticker5Hz; Ticker ticker20Hz; Ticker tickerTrottle; Timeout debounce_throttle; Timeout debounce_horn; Timeout debounce_headlight; // Timeout horn_limiter; // stop sound of horn after a determined period CircularBuffer <state_t, BUFFER_SIZE> state_buffer; /* Global variables */ bool switch_clicked = false; uint8_t switch_state = 0x00, flags = 0x00, pulse_counter = 0, temp_motor = 0; state_t current_state = IDLE_ST; uint64_t current_period = 0, last_count = 0, last_acq = 0; uint8_t imu_failed = 0; // number of times before a new connection attempt with imu float speed_hz = 0; uint16_t rpm_hz = 0, speed_display = 0, speed_radio = 0, dt = 0; int16_t angle_roll = 0, angle_pitch = 0; packet_t data; int main() { /* Main variables */ CANMsg txMsg; /* Initialization */ t.start(); horn = horn_button.read(); // horn OFF headlight = headlight_switch.read(); // headlight OFF led = 1; // led OFF eventThread.start(callback(&queue, &EventQueue::dispatch_forever)); t0 = t.read_us(); uint16_t lsm_addr = LSM6DS3.begin(LSM6DS3.G_SCALE_245DPS, LSM6DS3.A_SCALE_2G, LSM6DS3.G_ODR_26_BW_2, LSM6DS3.A_ODR_26); t1 = t.read_us(); // serial.printf("%d\r\n", (t1 - t0)); setupInterrupts(); while (true) { if (state_buffer.full()) { buffer_full = true; led = 0; state_buffer.pop(current_state); } else { led = 1; buffer_full = false; if (!state_buffer.empty()) state_buffer.pop(current_state); else current_state = IDLE_ST; } switch (current_state) { case IDLE_ST: // Thread::wait(2); break; case SLOWACQ_ST: break; case IMU_ST: t0 = t.read_us(); dbg1 = !dbg1; if (lsm_addr) { bool nack = LSM6DS3.readAccel(); // read accelerometer data into LSM6DS3.aN_raw if (!nack) nack = LSM6DS3.readGyro(); // " gyroscope data into LSM6DS3.gN_raw if (nack) { lsm_addr = 0; LSM6DS3.ax_raw = 0; LSM6DS3.ay_raw = 0; LSM6DS3.az_raw = 0; LSM6DS3.gx_raw = 0; LSM6DS3.gy_raw = 0; LSM6DS3.gz_raw = 0; } } else if (imu_failed == IMU_TRIES) { lsm_addr = LSM6DS3.begin(LSM6DS3.G_SCALE_245DPS, LSM6DS3.A_SCALE_2G, LSM6DS3.G_ODR_26_BW_2, LSM6DS3.A_ODR_26); t1 = t.read_us(); imu_failed = 0; // serial.printf("%d\r\n", (t1 - t0)); } else { imu_failed++; } last_acq = t.read_ms(); // serial.printf("accz = %d\r\n", LSM6DS3.gz_raw); calcAngles(LSM6DS3.ax_raw, LSM6DS3.ay_raw, LSM6DS3.az_raw, LSM6DS3.gx_raw, LSM6DS3.gy_raw, LSM6DS3.gz_raw, dt); /* Send accelerometer data */ txMsg.clear(IMU_ACC_ID); txMsg << LSM6DS3.ax_raw << LSM6DS3.ay_raw << LSM6DS3.az_raw; if(can.write(txMsg)) { /* Send gyroscope data only if accelerometer data succeeds */ txMsg.clear(IMU_DPS_ID); txMsg << LSM6DS3.gx_raw << LSM6DS3.gy_raw << LSM6DS3.gz_raw << dt; can.write(txMsg); } break; case SPEED_ST: // serial.printf("speed ok\r\n"); dbg2 = !dbg2; freq_sensor.fall(NULL); // disable interrupt if (current_period != 0) { speed_hz = 1000000*((float)pulse_counter/current_period); //calculates frequency in Hz } else { speed_hz = 0; } speed_display = ((float)(PI*WHEEL_DIAMETER*speed_hz)/WHEEL_HOLES_NUMBER); // make conversion hz to km/h speed_radio = ((float)((speed_display)/60.0)*65535); pulse_counter = 0; current_period = 0; //|-> reset pulses related variables last_count = t.read_us(); freq_sensor.fall(&frequencyCounterISR); // enable interrupt /* Send speed data */ txMsg.clear(SPEED_ID); txMsg << speed_radio; can.write(txMsg); // state_buffer.push(DEBUG_ST); // debug break; case THROTTLE_ST: // serial.printf("throttle ok\r\n"); dbg3 = !dbg3; if (switch_clicked) { switch_state = !choke_switch.read() << 1 | !run_switch.read() << 0; //serial.printf("switch_state = %d\r\n", switch_state); /* Send CAN message */ txMsg.clear(THROTTLE_ID); txMsg << switch_state; // serial.printf("can ok\r/n"); // append data (8 bytes max) can.write(txMsg); switch_clicked = false; } break; case DISPLAY_ST: // serial.printf("rpm_hz=%d\r\n", rpm_hz); displayData(speed_display, rpm_hz, temp_motor, (flags & 0x08), false, true, false, angle_pitch, angle_roll, (flags & 0x80)); // state_buffer.push(DEBUG_ST); break; case DEBUG_ST: // serial.printf("r= %d, p=%d\r\n", angle_roll, angle_pitch); // serial.printf("imu acc x =%d\r\n", LSM6DS3.ax_raw); // serial.printf("imu acc y =%d\r\n", LSM6DS3.ay_raw); // serial.printf("imu acc z =%d\r\n", LSM6DS3.az_raw); // serial.printf("imu dps x =%d\r\n", LSM6DS3.gx_raw); // serial.printf("imu dps y =%d\r\n", LSM6DS3.gy_raw); // serial.printf("imu dps z =%d\r\n", LSM6DS3.gz_raw); break; default: break; } } } /* Interrupt services routine */ void canISR() { CAN_IER &= ~CAN_IER_FMPIE0; // disable RX interrupt queue.call(&canHandler); // add canHandler() to events queue } void servoSwitchISR() { choke_switch.rise(NULL); // throttle interrupt in both edges dettach run_switch.rise(NULL); // throttle interrupt in both edges dettach choke_switch.fall(NULL); // throttle interrupt in both edges dettach run_switch.fall(NULL); // throttle interrupt in both edges dettach switch_clicked = true; debounce_throttle.attach(&throttleDebounceHandler, 0.1); } void ticker2HzISR() { state_buffer.push(DISPLAY_ST); } void ticker5HzISR() { state_buffer.push(SPEED_ST); state_buffer.push(DISPLAY_ST); } void ticker20HzISR() { state_buffer.push(IMU_ST); } void frequencyCounterISR() { pulse_counter++; current_period += t.read_us() - last_count; last_count = t.read_us(); } //void hornISR() //{ // debounce_horn.attach(&hornDebounceHandler, DEBOUNCE_TIME); //} void headlightISR() { debounce_headlight.attach(&headlightDebounceHandler, DEBOUNCE_TIME); } /* Interrupt handlers */ void canHandler() { CANMsg rxMsg; can.read(rxMsg); filterMessage(rxMsg); CAN_IER |= CAN_IER_FMPIE0; // enable RX interrupt } void throttleDebounceHandler() { state_buffer.push(THROTTLE_ST); choke_switch.rise(&servoSwitchISR); // trigger throttle interrupt in both edges run_switch.rise(&servoSwitchISR); // trigger throttle interrupt in both edges choke_switch.fall(&servoSwitchISR); // trigger throttle interrupt in both edges run_switch.fall(&servoSwitchISR); // trigger throttle interrupt in both edges } //void hornDebounceHandler() //{ // horn = horn_button.read(); //} void headlightDebounceHandler() { headlight = headlight_switch.read(); } /* General functions */ void setupInterrupts() { can.attach(&canISR, CAN::RxIrq); choke_switch.rise(&servoSwitchISR); // trigger throttle interrupt in both edges choke_switch.fall(&servoSwitchISR); // trigger throttle interrupt in both edges run_switch.rise(&servoSwitchISR); // trigger throttle interrupt in both edges run_switch.fall(&servoSwitchISR); // trigger throttle interrupt in both edges // horn_button.rise(&hornISR); // horn_button.fall(&hornISR); headlight_switch.rise(&headlightISR); headlight_switch.fall(&headlightISR); // ticker2Hz.attach(&ticker2HzISR, 0.4); ticker5Hz.attach(&ticker5HzISR, 0.2); ticker20Hz.attach(&ticker20HzISR, 0.05); signal.period_ms(2); signal.write(0.5f); } void filterMessage(CANMsg msg) { // serial.printf("id: %d\r\n", msg.id); if(msg.id == RPM_ID) { msg >> rpm_hz; } else if(msg.id == TEMPERATURE_ID) { msg >> temp_motor; } else if (msg.id == FLAGS_ID) { msg >> flags; } } /* Function adapted from Kristian Lauszus library example, source: https://github.com/TKJElectronics/KalmanFilter*/ void calcAngles(int16_t accx, int16_t accy, int16_t accz, int16_t grx, int16_t gry, int16_t grz, int16_t dt){ static Kalman kalmanX, kalmanY; float kalAngleX, kalAngleY; float pitch, roll; float gyroXrate, gyroYrate; float ax, ay, az; static bool first_execution = true; ax = (float) accx * TO_G; ay = (float) accy * TO_G; az = (float) accz * TO_G; pitch = atan2(ay, az) * RAD_TO_DEGREE; roll = atan(-ax / sqrt(ay * ay + az * az)) * RAD_TO_DEGREE; gyroXrate = grx / TO_DPS; // Convert to deg/s gyroYrate = gry / TO_DPS; // Convert to deg/s if (first_execution) { // set starting angle if first execution first_execution = false; kalmanX.setAngle(roll); kalmanY.setAngle(pitch); } // This fixes the transition problem when the accelerometer angle jumps between -180 and 180 degrees if((roll < -90 && kalAngleX > 90) || (roll > 90 && kalAngleX < -90)) { kalmanX.setAngle(roll); kalAngleX = roll; } else { kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter } if(abs(kalAngleX) > 90) { gyroYrate = -gyroYrate; // Invert rate, so it fits the restriced accelerometer reading } kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt); angle_roll = roll; angle_pitch = pitch; } void displayData(uint16_t vel, uint16_t Hz, uint16_t temp, bool comb, \ bool b, bool tl, bool fl, int16_t gp, int16_t gr, bool box) { static uint16_t vel2 = -1, Hz2 = -1, temp2 = -1; static int16_t gr2 = -1, gp2 = -1; static bool box2 = false; static bool comb2 = true, b2 = true, tl2 = false, fl2 = false; char str[512]; int aux=0; strcpy(str,""); if(box!=box2) sprintf(str + strlen(str), "page1.box.val=%d%c%c%c",box,0xff,0xff,0xff); if(vel!=vel2) sprintf(str + strlen(str), "page1.v.val=%d%c%c%c",vel,0xff,0xff,0xff); if(Hz!=Hz2) { int r = (Hz*6000)/(5000.0); sprintf(str + strlen(str), "page1.r.val=%d%c%c%c",r,0xff,0xff,0xff); } if(comb!=comb2) { if (!comb) sprintf(str + strlen(str),"page1.c.val=%d%c%c%c",25,0xff,0xff,0xff); else sprintf(str + strlen(str),"page1.c.val=%d%c%c%c",100,0xff,0xff,0xff); } if(temp!=temp2) { int tp = (100*temp)/120; sprintf(str + strlen(str),"page1.tp.val=%d%c%c%c",tp,0xff,0xff,0xff); } if(b!=b2) sprintf(str + strlen(str),"page1.b.val=%d%c%c%c",b,0xff,0xff,0xff); if(tl!=tl2) sprintf(str + strlen(str),"page1.tl.val=%d%c%c%c",tl,0xff,0xff,0xff); if(fl!=fl2) sprintf(str + strlen(str),"page1.fl.val=%d%c%c%c",fl,0xff,0xff,0xff); if(gp!=gp2) { int gpn = 7; if(gp<=-35){gpn=0;} else if(gp>=-30&&gp<-25){gpn=1;} else if(gp>=-25&&gp<-20){gpn=2;} else if(gp>=-20&&gp<-15){gpn=3;} else if(gp>=-15&&gp<-10){gpn=4;} else if(gp>=-10&&gp<-5){gpn=5;} else if(gp>=-5&&gp<0){gpn=6;} else if(gp==0){gpn=7;} else if(gp>0&&gp<=5){gpn=8;} else if(gp>5&&gp<=10){gpn=9;} else if(gp>10&&gp<=15){gpn=10;} else if(gp>15&&gp<=20){gpn=11;} else if(gp>20&&gp<=25){gpn=12;} else if(gp>25&&gp<=30){gpn=13;} else if(gp>=35){gpn=14;} #ifdef MB2 sprintf(str + strlen(str),"page3.gr.val=%d%c%c%c",gpn,0xff,0xff,0xff); sprintf(str + strlen(str),"page3.gr_n.val=%d%c%c%c",gp*(-1),0xff,0xff,0xff); #endif #ifdef MB1 sprintf(str + strlen(str),"page2.gp.val=%d%c%c%c",gpn,0xff,0xff,0xff); sprintf(str + strlen(str),"page2.gp_n.val=%d%c%c%c",gp,0xff,0xff,0xff); #endif } if(gr!=gr2) { int grn = 7; if(gr<=-35){grn=0;} else if(gr>=-30&&gr<-25){grn=1;} else if(gr>=-25&&gr<-20){grn=2;} else if(gr>=-20&&gr<-15){grn=3;} else if(gr>=-15&&gr<-10){grn=4;} else if(gr>=-10&&gr<-5){grn=5;} else if(gr>=-5&&gr<0){grn=6;} else if(gr==0){grn=7;} else if(gr>0&&gr<=5){grn=8;} else if(gr>5&&gr<=10){grn=9;} else if(gr>10&&gr<=15){grn=10;} else if(gr>15&&gr<=20){grn=11;} else if(gr>20&&gr<=25){grn=12;} else if(gr>25&&gr<=30){grn=13;} else if(gr>=35){grn=14;} #ifdef MB2 sprintf(str + strlen(str),"page3.gp.val=%d%c%c%c",grn,0xff,0xff,0xff); sprintf(str + strlen(str),"page3.gp_n.val=%d%c%c%c",gr,0xff,0xff,0xff); #endif #ifdef MB1 sprintf(str + strlen(str),"page2.gr.val=%d%c%c%c",grn,0xff,0xff,0xff); sprintf(str + strlen(str),"page2.gr_n.val=%d%c%c%c",gr,0xff,0xff,0xff); #endif } while(str[aux]!='\0') { serial.putc(str[aux]); aux++; } box2 = box; vel2 = vel; Hz2 = Hz; temp2 = temp; gr2=gr; gp2=gp; comb2 = comb; b2=b; tl2=tl; fl2=fl; }