One big fixed period control loop
Dependencies: FastAnalogIn MODSERIAL PID QEI RPCInterface Servo mbed-rtos mbed telemetry PinDetect
Fork of Everything by
main.cpp
- Committer:
- vsutardja
- Date:
- 2016-04-14
- Revision:
- 17:bf6192a361ab
- Parent:
- 16:3ab3c4670f4f
File content as of revision 17:bf6192a361ab:
#include "FastAnalogIn.h" #include "mbed.h" #include "PID.h" #include "QEI.h" #include "rtos.h" #include "SerialRPCInterface.h" #include "Servo.h" #include "telemetry.h" // ========= // Telemetry // ========= //DigitalOut test(PTD1); MODSERIAL telemetry_serial(PTC4, PTC3); // TX, RX //MODSERIAL telemetry_serial(USBTX, USBRX); telemetry::MbedHal telemetry_hal(telemetry_serial); // Hardware Abstraction Layer telemetry::Telemetry telemetry_obj(telemetry_hal); // Telemetry telemetry::Numeric<uint32_t> tele_time_ms(telemetry_obj, "time", "Time", "ms", 0); telemetry::NumericArray<uint16_t, 108> tele_linescan(telemetry_obj, "linescan", "Linescan", "ADC", 0); telemetry::Numeric<uint32_t> tele_exposure(telemetry_obj, "exposure", "Exposure", "us", 0); telemetry::Numeric<float> tele_velocity(telemetry_obj, "tele_vel", "Velocity", "who knows", 0); telemetry::Numeric<float> tele_pwm(telemetry_obj, "pwm", "PWM", "", 0); telemetry::Numeric<uint8_t> tele_center(telemetry_obj, "tele_center", "Center", "px", 0); Timer t; Timer t_tele; Ticker control_interrupt; int t_cam1 = 0; int t_cam2 = 0; int t_steer = 0; int t_vel = 0; int t_down = 0; float interrupt_T = 0.015; bool ctrl_flag = false; // ============= // Communication // ============= char comm_cmd; // Command char comm_in[5]; // Input Serial bt(USBTX, USBRX); // USB connection //Serial bt(PTC4, PTC3); // BlueSMiRF connection void communication(void const *args); // Communications // ===== // Motor // ===== const int motor_T = 25000; // Frequency float motor_duty = 0.0; // Duty cycle bool e_stop = false; // Emergency stop PwmOut motor(PTA4); // Enable pin (PWM) // ======= // Encoder // ======= const int ppr = 389; // Pulses per revolution const float c = 0.20106; // Wheel circumference int prev_pulses = 0; // Previous pulse count int prev_pulse_counts[5] = {0}; int curr_pulses = 0; // Current pulse count float velocity = 0; // Velocity QEI qei(PTD3, PTD2, NC, ppr, QEI::X4_ENCODING); // Quadrature encoder // ======== // Velocity // ======== float Kmp = 36.0; // Proportional factor float Kmi = 1; // Integral factor float Kmd = 0; // Derivative factor float interval = 0.01; // Sampling interval float ref_v = 0.5; // Reference velocity int vel_count = 1; PID motor_ctrl(Kmp, Kmi, Kmd, interrupt_T); // Motor controller // ===== // Servo // ===== float angle = 88; // Angle float Ksp = 1; // Steering proportion float Ksi = 0; float Ksd = 0; PID servo_ctrl(Ksp, Ksi, Ksd, interrupt_T); Servo servo(PTA12); // Signal pin (PWM) // ====== // Camera // ====== int t_int = 10000; // Exposure time const int T_INT_MAX = interrupt_T * 1000000 - 2000; // Maximum exposure time const int T_INT_MIN = 35; // Minimum exposure time int img[108] = {0}; // Image data DigitalOut clk(PTD5); // Clock pin DigitalOut si(PTD0); // SI pin FastAnalogIn ao(PTC2); // AO pin // ================ // Image processing // ================ int max = -1; // Maximum luminosity int left[5] = {0}; // Left edge int right[5] = {0}; // Right edge int j = 0; // Peaks index int center = 64; // Center estimate int centers[5] = {0}; // Possible centers int prev_center = 64; // Previous center float scores[5] = {0}; // Candidate scores int best_score_idx = 0; // Most likely center index // ================ // Functions // ================ void killswitch(MODSERIAL_IRQ_INFO *q) { MODSERIAL *serial = q->serial; if (serial->rxGetLastChar() == 'k') { e_stop = true; motor = 1.0; } if (serial->rxGetLastChar() == '+') { ref_v = ref_v + 0.2; motor_ctrl.setSetPoint(ref_v); } if (serial->rxGetLastChar() == '-') { ref_v = ref_v - 0.2; motor_ctrl.setSetPoint(ref_v); } } // Communications //void communication(void const *args) { // telemetry_serial.baud(115200); // telemetry_serial.attach(&killswitch, MODSERIAL::RxIrq); // telemetry_obj.transmit_header(); // while (true) { // tele_time_ms = t_tele.read_ms(); // telemetry_obj.do_io(); // } //} void communication(void const *args) { // Initialize bluetooth bt.baud(115200); while (true) { bt.printf("\r\nPress q to return to this prompt.\r\n"); bt.printf("Available diagnostics:\r\n"); bt.printf(" [0] Velocity\r\n"); bt.printf(" [1] Steering\r\n"); bt.printf(" [2] Change Kmp\r\n"); bt.printf(" [3] Change Kmi\r\n"); bt.printf(" [4] Change Kmd\r\n"); bt.printf(" [5] Change Ksp\r\n"); bt.printf(" [6] Change reference velocity\r\n"); bt.printf(" [7] EMERGENCY STOP\r\n"); bt.printf(" [8] Timing\r\n"); comm_cmd = bt.getc(); while (comm_cmd != 'q') { switch(atoi(&comm_cmd)){ case 0: bt.printf("Duty cycle: %f, Pulse count: %d, Velocity: %f, Kmp: %f, Kmi: %f, Kmd: %f\r\n", motor_duty, curr_pulses, velocity, Kmp, Kmi, Kmd); break; case 1: bt.printf("Servo angle: %f, Track center: %d, t_int: %d\r\n", angle, center, t_int); break; case 2: bt.printf("Current: %f, New (5 digits): ", Kmp); for (int i = 0; i < 5; i++) { comm_in[i] = bt.getc(); bt.putc(comm_in[i]); } bt.printf("\r\n"); Kmp = atof(comm_in); motor_ctrl.setTunings(Kmp, Kmi, Kmd); comm_cmd = 'q'; break; case 3: bt.printf("Current: %f, New (5 digits): ", Kmi); for (int i = 0; i < 5; i++) { comm_in[i] = bt.getc(); bt.putc(comm_in[i]); } bt.printf("\r\n"); Kmi = atof(comm_in); motor_ctrl.setTunings(Kmp, Kmi, Kmd); comm_cmd = 'q'; break; case 4: bt.printf("Current: %f, New (5 digits): ", Kmd); for (int i = 0; i < 5; i++) { comm_in[i] = bt.getc(); bt.putc(comm_in[i]); } bt.printf("\r\n"); Kmd = atof(comm_in); motor_ctrl.setTunings(Kmp, Kmi, Kmd); comm_cmd = 'q'; break; case 5: bt.printf("Current: %f, New (5 digits): ", Ksp); for (int i = 0; i < 5; i++) { comm_in[i] = bt.getc(); bt.putc(comm_in[i]); } bt.printf("\r\n"); Ksp = atof(comm_in); comm_cmd = 'q'; break; case 6: bt.printf("Current: %f, New (5 digits): ", ref_v); for (int i = 0; i < 5; i++) { comm_in[i] = bt.getc(); bt.putc(comm_in[i]); } bt.printf("\r\n"); ref_v = atof(comm_in); motor_ctrl.setSetPoint(ref_v); comm_cmd = 'q'; break; case 7: e_stop = true; bt.printf("STOPPED\r\n"); comm_cmd = 'q'; break; case 8: bt.printf("Read 1: %dus, Exposure: %dus, Read 2: %dus, Steering: %dus, Velocity: %dus, Down: %dus, Total: %dus\r\n", t_cam1, t_int, t_cam2, t_steer, t_vel, t_down, t_cam1+t_int+t_cam2+t_steer+t_vel+t_down); break; } if (bt.readable()) { comm_cmd = bt.getc(); } } } } void control() { // Image capture t_down = t.read_us(); t.reset(); // Dummy read PTD->PCOR = (0x01 << 5); PTD->PSOR = (0x01); PTD->PSOR = (0x01 << 5); PTD->PCOR = (0x01); for (int i = 0; i < 128; i++) { PTD->PCOR = (0x01 << 5); PTD->PSOR = (0x01 << 5); } t_cam1 = t.read_us(); // Expose wait_us(t_int); // Read camera PTD->PCOR = (0x01 << 5); PTD->PSOR = (0x01); PTD->PSOR = (0x01 << 5); PTD->PCOR = (0x01); t.reset(); for (int i = 0; i < 128; i++) { PTD->PCOR = (0x01 << 5); if (i > 9 && i < 118) { img[i-10] = ao.read_u16(); tele_linescan[i-10] = img[i-10]; } PTD->PSOR = (0x01 << 5); } t_cam2 = t.read_us(); // Steering control t.reset(); // Detect peak edges j = 0; for (int i = 0; i < 108 && j < 5; i++) { if (img[i] > max * 0.65) { left[j] = i; while (img[i] > max * 0.65) { if (i < 107) { i = i + 1; } else { j = j - 1; break; } } if (i < 107) { right[j] = i; } j = j + 1; } } if (j > 0) { // Calculate peak centers for (int i = 0; i < j; i++) { centers[i] = (left[i] + right[i] + 20) / 2; } // Assign scores for (int i = 0; i < j; i++) { scores[i] = 4 / (right[i] - left[i]) + img[centers[i]] / 65536 + 16 / abs(centers[i] - prev_center); } // Choose most likely center best_score_idx = 0; for (int i = 0; i < j; i++) { if (scores[i] > scores[best_score_idx]) { best_score_idx = i; } } prev_center = center; center = centers[best_score_idx]; tele_center = center; angle = 88 + (64 - center) * 0.9; if (angle > 113) { angle = 113; } if (angle < 63) { angle = 63; } // servo_ctrl.setProcessValue(center); // angle = 88 + servo_ctrl.compute(); // servo = floor(angle / 180 * 100 + 0.5) / 100; servo = angle / 180; } // AGC max = -1; for (int i = 0; i < 107; i++) { if (img[i] > max) { max = img[i]; } } if (max > 60000) { t_int = t_int - 0.1 * (max - 60000); } if (max < 50000) { t_int = t_int + 0.1 * (50000 - max); } if (t_int < T_INT_MIN) { t_int = T_INT_MIN; } if (t_int > T_INT_MAX) { t_int = T_INT_MAX; } tele_exposure = t_int; t_steer = t.read_us(); // wait_us(8000 - t.read_us()); // Velocity control t.reset(); if (!e_stop) { curr_pulses = qei.getPulses(); if (vel_count < 6) { velocity = curr_pulses / interrupt_T / vel_count / ppr * c; prev_pulse_counts[vel_count - 1] = curr_pulses; vel_count = vel_count + 1; } else { velocity = (curr_pulses - prev_pulse_counts[0]) / interrupt_T / 5 / ppr * c; for (int i = 0; i < 4; i++) { prev_pulse_counts[i] = prev_pulse_counts[i+1]; } prev_pulse_counts[4] = curr_pulses; } tele_velocity = velocity; motor_ctrl.setProcessValue(velocity); motor_duty = motor_ctrl.compute(); motor = 1.0 - motor_duty; tele_pwm = motor_duty; } else { motor = 1.0; } t_vel = t.read_us(); t.reset(); ctrl_flag = false; // test = 0; } void set_ctrl_flag() { // test = 1; ctrl_flag = true; } // ==== // Main // ==== int main() { t.start(); t_tele.start(); tele_center.set_limits(0, 128); tele_pwm.set_limits(0.0, 1.0); // Initialize motor motor.period_us(motor_T); motor = 1.0 - motor_duty; // Initialize motor controller motor_ctrl.setInputLimits(0.0, 10.0); motor_ctrl.setOutputLimits(0.0, 0.5); motor_ctrl.setSetPoint(ref_v); motor_ctrl.setBias(0.0); motor_ctrl.setMode(1); // Initialize servo servo.calibrate(0.001, 45.0); servo = angle / 180.0; // Initialize servo controller servo_ctrl.setInputLimits(10, 117); servo_ctrl.setOutputLimits(-25, 25); servo_ctrl.setSetPoint(63.5); servo_ctrl.setBias(0); servo_ctrl.setMode(1); // Initialize communications thread // Thread communication_thread(communication); // control_interrupt.attach(control, interrupt_T); // Thread::wait(osWaitForever); control_interrupt.attach(set_ctrl_flag, interrupt_T); while (true) { if (ctrl_flag) { control(); } } }