The subsystem design/basis for the final project

Dependencies:   mbed-rtos mbed-src pixylib

Revision:
0:80a37292f6b2
Child:
1:cc5636894b95
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Mar 09 02:45:40 2016 +0000
@@ -0,0 +1,320 @@
+// Description: combines the functionality of both the PIcontrol program that controls a motor and the Pixy subsystem
+//              to create a program that will control the robot
+
+#include "rtos.h"
+#include "mbed.h"
+#include "Robot_Control.h"
+#include "Pixy.h"
+
+#define MAX_BLOCKS 1
+#define TARGET 12 //the code of our target, very important, should this be octal...?
+
+//controls whether or not motors are a part of the program
+//for our test of the PIXY, they will not be
+#define MOTORS_ON 0
+
+//steering inputs, may want to change to variables or something
+#define STEER_SETPOINT 160
+#define STEER_KP 1
+#define STEER_KI 0
+#define STEER_MAX 2147483648
+
+//speed inputs
+#define HEIGHT_SETPOINT 160
+#define SPEED_KP 1
+#define SPEED_KI 0
+#define SPEED_MAX 2147483648
+
+//shared variables between sensor thread and motor thread, protected by mutex
+float left_setpoint, right_setpoint;
+
+//the setpoint mutex
+osMutexId setpoint_mutex;
+osMutexDef(setpoint_mutex);
+
+//motorPI function variables
+float L_xState, R_xState; //the states for the left and right pi control loop (must have them outside of function to make them cumulative)
+
+//PI function variables
+float steer_xState, speed_xState; //the states for the steering and speed pi control loop
+
+//main()variables
+short idCode;
+char isMeasuring;
+char inKey;
+float pwmPeriod = 0.001;
+
+//global variables
+float Kp, Ki; //kp and ki for motors
+
+// Various debugging variables
+float vels[60], times[60], errs[60], xvals[60], uvals[60]; // Used to measure step response
+int x_global, height_global;
+float speed_global, steer_global;
+
+// ******** Main Thread ********
+int main() {  // This thread executes first upon reset or power-on.
+    
+    if(MOTORS_ON){
+        // left
+        PWM0.period(pwmPeriod);
+        PWM0.pulsewidth(0);
+        Thread::wait(500);
+
+        // right
+        PWM1.period(pwmPeriod);
+        PWM1.pulsewidth(0);
+        Thread::wait(500);
+   
+        //mutex for the left and right motor setpoints
+        setpoint_mutex = osMutexCreate(osMutex(setpoint_mutex));
+    }
+    
+    Bumper.rise(&ExtCollisionISR); // Attach the address of the interrupt handler to the rising edge of Bumper
+    
+    // Start execution of the threads: PiControlThread,ExtCollisionThread, and SensorControlThread:
+    SensorControl = osThreadCreate(osThread(SensorControlThread), NULL);
+    if(MOTORS_ON) PiControl = osThreadCreate(osThread(PiControlThread), NULL);
+    ExtCollision = osThreadCreate(osThread(ExtCollisionThread), NULL);
+    
+    // Start the watch dog timer and enable the watch dog interrupt
+    osTimerId OneShot = osTimerCreate(osTimer(Wdtimer), osTimerOnce, (void *)0);
+    led3=0; // Clear watch dog led3 status
+    
+    if(MOTORS_ON){
+        //SPI Section
+        pc.printf("\n\rStarting SPI...");
+        // Restart with a new SPI protocol.
+        DE0.format(16,1); // 16 bit mode 1
+        IoReset = 0; 
+        IoReset = 1; 
+        wait_us(10);
+        IoReset = 0;
+        SpiReset = 0; 
+        SpiReset = 1; 
+        wait_us(10);
+        SpiReset = 0; 
+        idCode = DE0.write(0x8004); //changed from 8002 for one motor to 8004 for two
+        pc.printf("\n\rDevice Id: %d", idCode);
+    
+        // motor Kp and Ki
+        Kp = 0.000120;
+        Ki = 0.0000000001;
+    }
+    
+    // Specify address of the PeriodicInt ISR as PiControllerISR, specify the interval 
+    // in seconds between interrupts, and start interrupt generation:
+    if(MOTORS_ON) PeriodicInt.attach(&PiControllerISR, .001);
+    PeriodicInt2.attach(&SensorControllerISR, .0167); //trigger sensor thread 60 times/sec
+    
+    //isMeasuring = 1; 
+    //Setpoint = 6; 
+    
+    while (1) {
+        
+        osTimerStart(OneShot, 2000); // Start or restart the watchdog timer interrupt and set to  2000ms.
+
+        if(!MOTORS_ON){
+            pc.printf("X Coordinate: %d, Steering: %d,", x_global, steer_global);
+            pc.printf("Height: %d, Speed: %d,", height_global, speed_global);
+            pc.printf(" L setpoint: %d, R setpoint: %d \n\r", left_setpoint, right_setpoint);
+        }
+        /*
+        if (!isMeasuring && (Setpoint!=0)) {
+            pc.printf("\n\r-----------------------------------\n\r");
+            printf("times (ms) \t vel (rads/s) \t error \t\t x value \t u value \n\r");  
+            for (i=0; i<60; i++) {
+                  printf("%f, \t %f, \t %f, \t %f, \t %f \n\r", times[i], vels[i], errs[i], xvals[i], uvals[i]);  
+            }
+            pc.printf("\n\r-----------------------------------\n\r");
+            Setpoint = 0; 
+            i = 0;
+        }
+        */
+        Thread::wait(500); // Go to sleep for 500 ms
+    }
+}
+
+// ******** Control Thread ********
+void SensorControlThread(void const *argument) {
+    float speed, steer;
+    int x, count, height;
+    
+    Pixy pixy(Pixy::SPI, p11, p12, p13);
+    
+    while (1) {
+        osSignalWait(SignalSensor, osWaitForever); //note: SignalSensor is just zero, waits for any signal dirrected at thread.
+
+        count = pixy.getBlocks(130); //get as many blocks as are available
+
+        //find the target block in all of the blocks that were sent
+        for(x=0;x<count;x++){
+            if (pixy.blocks[x].signature == TARGET) break;
+            if (x==count) pc.printf("no target in frame");
+        }
+
+        // if blocks were returned
+        if (count){
+
+            //height = CalcHeight() //find the feedback from the pixy for the height
+            height = pixy.blocks[(x-1)].height; //use this for now
+
+            steer = PI(0, STEER_SETPOINT, STEER_KP, STEER_KI, pixy.blocks[(x-1)].x, STEER_MAX); //the feedback for the steering is the x location of the target block
+            speed = PI(1, HEIGHT_SETPOINT, SPEED_KP, SPEED_KI, height, SPEED_MAX);
+
+            if(!MOTORS_ON){
+                x_global = pixy.blocks[x-1].x;
+                height_global = height;
+                steer_global = steer;
+                speed_global = speed;
+            }
+
+            // give setpoints to PiControlThread
+            osMutexWait(setpoint_mutex, osWaitForever); //enter mutex
+            left_setpoint = speed - steer;
+            right_setpoint = speed + steer;
+            osMutexRelease(setpoint_mutex); //exit mutex
+        }
+
+    } 
+}
+    
+// ******** Control Thread ********
+void PiControlThread(void const *argument) {
+    short dP_L, dt_L, dP_R, dt_R;
+    float uL,uR;
+    float left_set,right_set;
+
+    while (1) {
+        osSignalWait(SignalPi, osWaitForever); // Go to sleep until signal, SignalPi, is received. SignalPi is just zero lol, waits for any signal to thread
+        led2= !led2; // Alive status - led2 toggles each time PiControlThread is signaled.
+        
+        dP_L = DE0.write(0); // Read QEI-0 position register
+        dt_L = DE0.write(0);  // Read QEI-0 time register
+        dP_R = DE0.write(0); // Read QEI-0 position register
+        dt_R = DE0.write(0);  // Read QEI-0 time register
+        
+        osMutexWait(setpoint_mutex, osWaitForever);//enter mutex
+        left_set= left_setpoint; //copy setpoint
+        right_set= right_setpoint;
+        osMutexRelease(setpoint_mutex);//exit mutex
+
+        uL = motorPI(0, left_set, Kp, Ki, dP_L, dt_L);
+        uR = motorPI(1, right_set, Kp, Ki, dP_R, dt_R);
+        
+        PWM0.pulsewidth(fabs(uL));
+        PWM1.pulsewidth(fabs(uR));
+    } 
+}
+
+// ******** Collision Thread ********
+void ExtCollisionThread(void const *argument) {
+    while (1) {
+        osSignalWait(SignalExtCollision, osWaitForever); // Go to sleep until signal, SignalExtCollision, is received
+        led4 = 1;
+    }
+}
+
+// ******** Watchdog Interrupt Handler ********
+void Watchdog(void const *n) {
+    led3=1; // led3 is activated when the watchdog timer times out
+}
+
+// ******** Period Timer Interrupt Handler ********
+void PiControllerISR(void) {
+    osSignalSet(PiControl,0x1); // Activate the signal, PiControl, with each periodic timer interrupt.
+}
+
+// ******** Period Timer Interrupt Handler ********
+void SensorControllerISR(void) {
+    osSignalSet(SensorControl,0x1); // Activate the signal, SensorControl, with each periodic timer interrupt. (basically sends signal to id of thread)
+}
+    
+// ******** Collision Interrupt Handler ********
+void ExtCollisionISR(void) {
+    osSignalSet(ExtCollision,0x1); // Activate the signal, ExtCollision, with each pexternal interrupt.
+}
+
+// motorPI - motor pi control extacted from previous work
+// Input:   0 for Left motor, 1 for right motor
+// Output: pwm pulsewidth for corresponding motor
+
+float motorPI(int RL_Motor, float Setpoint, float Kp, float Ki, short dP1, short dt1){
+    int dP32, i;
+    float angVel, e, u, xState;
+    
+    if (dP1 & 0x00008000) {
+        dP32 = dP1 | 0xFFFF0000;
+    } else {
+        dP32 = dP1;
+    }   
+        
+    angVel = QE2RadsPerSec(dP32, dt1);
+        
+    e = Setpoint - angVel;
+
+    RL_Motor ? xState = R_xState : xState = L_xState; //state is cumulative, select left or right state global variable
+        
+    // Avoid integrator wind up
+     if((u>=pwmPeriod)||(u<=-pwmPeriod)){
+        //xState= xState; - turns off integrator when u maxed
+    }else{
+        xState = xState + e;
+    }
+
+    RL_Motor ? R_xState = xState : L_xState = xState; //update state variable
+        
+    u = Ki*xState + Kp*e;
+        
+    // Set direction and pwm
+    if (u >= 0) {
+       RL_Motor ? DIR1 = 1 : DIR0 = 1;   
+    } else {
+       RL_Motor ? DIR1 = 0 : DIR0 = 0;
+    }
+        
+    if (isMeasuring) {
+        vels[i] = angVel;
+        times[i] = i;
+        errs[i] = e;
+        xvals[i] = xState;
+        uvals[i] = u;
+        if (i>=59) {
+            isMeasuring = 0;
+        }
+        i++;
+    }
+        
+    if (fabs(u) > pwmPeriod) u = pwmPeriod;
+    
+    return u;
+}
+
+// PI() - A generic PI controller function used by the sensor control thread
+// st_or_sp - 0 for steering, 1 for speed
+float PI(int st_or_sp, float setpoint, float Kp, float Ki, int feedback, float max_val){
+    float e, xState, u;
+    
+    e = setpoint - (float)feedback;
+    
+    st_or_sp ? xState = speed_xState : xState = steer_xState; 
+
+    // Avoid integrator wind up
+     if((u>=max_val)||(u<=-max_val)){
+        //xState= xState; - turns off integrator when u maxed
+    }else{
+        xState = xState + e;
+    }
+    
+    st_or_sp ? speed_xState = xState : steer_xState = xState; //update state variable
+
+    u = Ki*xState + Kp*e;
+    
+    if (fabs(u) > max_val) u = max_val;
+    
+    return u;
+}
+
+float QE2RadsPerSec(int counts, int time) {
+    return (counts*122.62)/time;
+}
\ No newline at end of file