Control code for Triforce robot.

Dependencies:   triforce-esc PwmInRC mbed

Revision:
1:026f79cfd378
Parent:
0:d6eeeae3c3cb
--- a/main.cpp	Fri Nov 18 14:22:26 2016 +0000
+++ b/main.cpp	Fri May 05 14:12:24 2017 +0000
@@ -1,47 +1,33 @@
-/* Debugging defines */
-#define DEBUG_INPUT  // Send input values to usb serial
-#define DEBUG_ORIENTATION // Send orientation readings to usb serial
-#define DEBUG_OUTPUT // Send output values to usb serial
-#define PC_DEBUGGING // Output debugging information over usb serial
-
-/* Configuration defines */
-//#define HEADING_LOCK // Enable heading lock functionality
-//#define ORIENTATION // Enable orientation functionality
 /* Includes */
-
 #include "bno055.h"
 #include "esc.h"
 #include "PwmIn.h"
 #include "mbed.h"
 #include "Triforce.h"
-
-/* Set the delay between fresh samples */
-#define BNO055_SAMPLERATE_DELAY_MS (100)
+#include "math.h"
 
 /* USB */
 Serial pc(USBTX, USBRX);
 
 /* 8 Channel RC input */
-PwmIn rc_channel_1(p5);
-PwmIn rc_channel_2(p6);
-PwmIn rc_channel_3(p7);
-PwmIn rc_channel_4(p8);
-PwmIn rc_channel_5(p11);
-PwmIn rc_channel_6(p12);
-PwmIn rc_channel_7(p13);
-PwmIn rc_channel_8(p14);
+PwmIn rc_channel_1(p5); // Roll
+PwmIn rc_channel_2(p6); // Pitch
+PwmIn rc_channel_3(p7); // Throttle
+PwmIn rc_channel_4(p8); // Yaw
+PwmIn rc_channel_5(p11); // Switch R front
+PwmIn rc_channel_6(p12); // Dial R 
+PwmIn rc_channel_7(p13); // Dial L
+PwmIn rc_channel_8(p14); // Switch L Back
 
 /* 5 channel ESC output */
-ESC esc_omni_1(p21);
-ESC esc_omni_2(p22);
-ESC esc_omni_3(p23); //LED4
-//ESC esc_weapon_1(p24); //LED3
-//ESC esc_weapon_2(p25); //LED2
+ESC esc_omni_1(p21, 20, 1500);
+ESC esc_omni_2(p22, 20, 1500);
+ESC esc_omni_3(p23, 20, 1500); //LED4
+ESC esc_weapon_1(p24); //LED3
+ESC esc_weapon_2(p25); //LED2
 
 /* LEDs */
 DigitalOut led1(LED1);
-DigitalOut led2(LED2);
-DigitalOut led3(LED3);
 
 /* Initial control positions */
 static struct rc_controls controls = {
@@ -71,41 +57,9 @@
     .y_translation = 50
 };
 
-/** Read control positions from RC receiver
- * 
- * Converts control input pulsewidths read in seconds to throttle % 
- */
-void read_inputs(){    
-    controls.channel_1 = convert_pulsewidth(rc_channel_1.pulsewidth());
-    controls.channel_2 = convert_pulsewidth(rc_channel_2.pulsewidth());
-    controls.channel_3 = convert_pulsewidth(rc_channel_3.pulsewidth());
-    controls.channel_4 = convert_pulsewidth(rc_channel_4.pulsewidth());
-    controls.channel_5 = convert_pulsewidth(rc_channel_5.pulsewidth());
-    controls.channel_6 = convert_pulsewidth(rc_channel_6.pulsewidth());
-    controls.channel_7 = convert_pulsewidth(rc_channel_7.pulsewidth());
-    controls.channel_8 = convert_pulsewidth(rc_channel_8.pulsewidth());
-    
-    #if defined (PC_DEBUGGING) && defined (DEBUG_INPUT)  
-    pc.printf("Input: C1: %i, C2: %i, C3: %i, C4: %i, C5: %i, C6: %i, C7: %i, C8: %i\r\n", controls.channel_1, controls.channel_2, controls.channel_3, controls.channel_4, controls.channel_5, controls.channel_6, controls.channel_7, controls.channel_8);
-    #endif
-}
 
+/******************************************************************************/
 
-/** Output to OmniMixer and ESCs 
- * 
- * Sends calculated output values to devices
- */
-void output_stage(){
-    esc_omni_1.setThrottle(outputs.wheel_1);
-    esc_omni_2.setThrottle(outputs.wheel_2);
-    esc_omni_3.setThrottle(outputs.wheel_3);
-    //esc_weapon_1.setThrottle(outputs.weapon_motor_1);
-    //esc_weapon_2.setThrottle(outputs.weapon_motor_2);
-    
-    #if defined (PC_DEBUGGING) && defined (DEBUG_OUTPUT)  
-    pc.printf("Output Stage: Rotation: %i, X: %i, Y: %i, Weapon1: %i, Weapon2: %i", outputs.wheel_1, outputs.wheel_2, outputs.wheel_3, outputs.weapon_motor_1, outputs.weapon_motor_2);
-    #endif
-}
 
 /** Init
  * 
@@ -132,6 +86,133 @@
     #endif
 }
 
+void reset_outputs(){
+    outputs.wheel_1 = 50;
+    outputs.wheel_2 = 50;
+    outputs.wheel_3 = 50;    
+}
+
+
+/** Read control positions from RC receiver
+ * 
+ * Converts control input pulsewidths read in seconds to throttle % 
+ */
+void read_inputs(){    
+    
+    
+    /* Check for armed status */
+    
+    
+    if(!armed || just_armed){
+        #if defined (PC_DEBUGGING) && defined (DEBUG_INPUT) 
+        if(arming_count == 0){
+            
+            pc.printf("MOVE STICKS TO ARMING POSITIONS AND HOLD TO ARM \r\n");
+        }    
+        #endif
+        
+        failsafe = true;
+        int c1 = convert_pulsewidth(rc_channel_1.pulsewidth());
+        int c2 = convert_pulsewidth(rc_channel_2.pulsewidth());
+        int c3 = convert_pulsewidth(rc_channel_3.pulsewidth());
+        int c4 = convert_pulsewidth(rc_channel_4.pulsewidth());
+        pc.printf("Input: C1: %i \t C2: %i \t C3: %i \t C4: %i \r\n", c1, c2, c3, c4);
+        
+        if(c1 > RC_ARM_CHANNEL_1 && c2 > RC_ARM_CHANNEL_2 && c3 < RC_ARM_CHANNEL_3 && c4 < RC_ARM_CHANNEL_4){       
+            
+            if(!armed){
+                #if defined (PC_DEBUGGING) && defined (DEBUG_INPUT) 
+                pc.printf("ARMING %i\r\n", arming_count);    
+                #endif
+                arming_count++;
+                wait_ms(1000);
+                if(arming_count > RC_ARM_DELAY){
+                    armed = true;
+                    just_armed = true;
+                }
+            }else{
+                #if defined (PC_DEBUGGING) && defined (DEBUG_INPUT) 
+                pc.printf("ARMED - CENTER CONTROLS \r\n");    
+                #endif
+            }
+        } else if(just_armed){
+            /* Wait for controls to be centered to avoid unexpected movement */
+            if(BETWEEN(c1, 45, 55) && BETWEEN(c2, 45, 55) && c3 < RC_ARM_CHANNEL_3 && BETWEEN(c4, 45, 55)){     
+                #if defined (PC_DEBUGGING) && defined (DEBUG_INPUT) 
+                pc.printf("CONTROLS CENTERED DISABLING ARM LOCK\r\n");    
+                #endif
+                just_armed = false;
+                failsafe_timer = 0;
+            }
+              
+        }else {
+            arming_count = 0;
+        }
+        
+        
+    }else{
+        
+            
+            
+            
+            
+        #if defined (PC_DEBUGGING) && defined (DEBUG_INPUT) 
+        pc.printf("******************ARMED****************** \r\n");    
+        #endif
+
+        controls.channel_1 = convert_pulsewidth(rc_channel_1.pulsewidth());
+        controls.channel_2 = convert_pulsewidth(rc_channel_2.pulsewidth());
+        controls.channel_3 = convert_pulsewidth(rc_channel_3.pulsewidth());
+        controls.channel_4 = convert_pulsewidth(rc_channel_4.pulsewidth());
+        controls.channel_5 = convert_pulsewidth(rc_channel_5.pulsewidth());
+        controls.channel_6 = convert_pulsewidth(rc_channel_6.pulsewidth());
+        controls.channel_7 = convert_pulsewidth(rc_channel_7.pulsewidth());
+        controls.channel_8 = convert_pulsewidth(rc_channel_8.pulsewidth());
+        
+        /* Check if rc is stalled and failsafe output */
+        
+        if(rc_channel_1.stallTimer.read_ms() > 200){            
+            failsafe = true;
+            #if defined (PC_DEBUGGING) && defined (DEBUG_INPUT) 
+            pc.printf("NO SIGNAL - FAILSAFE ACTIVATED \r\n");    
+            #endif
+            failsafe_timer++;
+            wait_ms(100);
+            if(failsafe_timer > NO_SIGNAL_TIMEOUT){
+                armed = false;
+            }
+        }else{
+            failsafe_timer = 0;
+            failsafe = false;
+        }
+        
+        
+        
+        direction.rotation = controls.channel_4;    
+        direction.x_translation = controls.channel_2;
+        direction.y_translation = controls.channel_1;   
+        
+        /* Heading lock enable switch */
+        if(controls.channel_8 > 75 && !heading_lock_enabled){
+            heading_lock = orientation.heading;
+            heading_lock_enabled = true;
+        }else if(controls.channel_8 < 75 && heading_lock_enabled){
+            heading_lock_enabled = false;
+        }
+        
+        /* Speed for heading lock */
+        heading_lock_speed = (int) controls.channel_7;
+        
+        #if defined (PC_DEBUGGING) && defined (DEBUG_INPUT)  
+        pc.printf("Input: C1: %i \t C2: %i \t C3: %i \t C4: %i \t C5: %i \t C6: %i \t C7: %i \t C8: %i\r\n", controls.channel_1, controls.channel_2, controls.channel_3, controls.channel_4, controls.channel_5, controls.channel_6, controls.channel_7, controls.channel_8);
+        
+        pc.printf("Heading Lock: %s \r\n", heading_lock_enabled ? "true" : "false");
+        pc.printf("Heading Lock Speed: %i \r\n", heading_lock_speed);
+        #endif
+   }
+}
+
+
 /** Calculate Orientation
  * 
  * Calculates orientation using the BNO055 sensor
@@ -141,20 +222,23 @@
     /* If there is an error then we maintain the same 
      * orientation to stop random control flipping */
     if(!bno055Healthy()){
+        #if defined (PC_DEBUGGING) && defined (DEBUG_ORIENTATION) 
         pc.printf("ERROR: BNO055 has an error/status problem!!!\r\n");
+        #endif
     }else{       
         
         /* Read in the Euler angles */
         orientation = getEulerAngles();    
         
-        /* We are upside down in range -30 -> -90 */
+        /* We are upside down in range -30 -> -90  
+         * the sensor will report -60 when inverted */
         if(orientation.roll < -30 && orientation.roll > -90){
             inverted = true;   
         }else{
             inverted = false; 
         }
         #if defined (PC_DEBUGGING) && defined (DEBUG_ORIENTATION)     
-        pc.printf("Roll=%7.2f, Inverted=%s", orientation.roll, inverted ? "true" : "false");
+        pc.printf("Inverted= %s \t (%7.2f) \r\n", inverted ? "true" : "false", orientation.roll);
         #endif
     }        
     
@@ -164,53 +248,70 @@
 /** Calculate controls
  * 
  * Calculates controls based on if the robot is inverted or not
+ * TODO: Add inverted support
  */
 void calculate_controls(){
-    if(inverted){
+       
+    #ifdef OMNI_MIXER
     
-    }else{  
+    float x = direction.x_translation -50;
+    float y = direction.y_translation -50;    
     
-        float theta = (float)atan2((double)direction.x_translation, (double)direction.y_translation);
-        float magnitude = (float)sqrt((double)((direction.x_translation*direction.x_translation)+(direction.y_translation*direction.y_translation)));
+    float theta = (float)atan2((double)x, (double)y);
+    float magnitude = (float)sqrt((double)((x*x)+(y*y)));
     
-        if(magnitude > 75.0f){  
+    if(magnitude > 5.0f){  
     
-            float vx = magnitude * cos(theta);
-            float vy = magnitude * sin(theta);
-            const float sqrt3o2 = 1.0*sqrt(3.0)/2;
+        float vx = magnitude * sin(theta);
+        float vy = magnitude * cos(theta);
+        const float sqrt3o2 = 1.0*sqrt(3.0)/2.0;
     
-            float w0 = -vx;                   // v dot [-1, 0] / 25mm
-            float w1 = 0.5*vx - sqrt3o2 * vy; // v dot [1/2, -sqrt(3)/2] / 25mm
-            float w2 = 0.5*vx + sqrt3o2 * vy; // v dot [1/2, +sqrt(3)/2] / 25mm           
-            
-            float w0_speed =  map(w0, 0, 600, 0, 100);
-            float w1_speed =  map(w1, 0, 600, 0, 100);
-            float w2_speed =  map(w2, 0, 600, 0, 100);
-            
-            /* Add in rotation */
-            
-            w0_speed += direction.rotation;
-            w1_speed += direction.rotation;
-            w2_speed += direction.rotation;
-            
-            /* Clamp outputs to correct range */
-            outputs.wheel_1 = clamp(w0_speed, 0, 100);
-            outputs.wheel_2 = clamp(w1_speed, 0, 100);
-            outputs.wheel_3 = clamp(w2_speed, 0, 100);
-            
-            
-            
+        float w0 = -vx;                   // v dot [-1, 0] / 25mm
+        float w1 = 0.5*vx - sqrt3o2 * vy; // v dot [1/2, -sqrt(3)/2] / 25mm
+        float w2 = 0.5*vx + sqrt3o2 * vy; // v dot [1/2, +sqrt(3)/2] / 25mm           
+        #if defined (PC_DEBUGGING) && defined (DEBUG_CONTROLS) 
+        pc.printf("Calculated Controls: (%7.2f) \t (%7.2f) \t (%7.2f) \r\n", w0, w1, w2);
+        #endif
+        float w0_speed =  map(w0, -70, 70, 0, 100);
+        float w1_speed =  map(w1, -70, 70, 0, 100);
+        float w2_speed =  map(w2, -70, 70, 0, 100);
+        
+        /* Add in rotation */
+        #if defined (PC_DEBUGGING) && defined (DEBUG_CONTROLS) 
+        pc.printf("Mapped Controls: (%7.2f) \t (%7.2f) \t (%7.2f) \r\n", w0_speed, w1_speed, w2_speed);
+        #endif
+        outputs.wheel_1 += w0_speed -50;
+        outputs.wheel_2 += w1_speed -50;
+        outputs.wheel_3 += w2_speed -50;
+        
+                      
+    }else{
+        outputs.wheel_1 = 50;
+        outputs.wheel_2 = 50;
+        outputs.wheel_3 = 50;
+    }   
     
-        }else{
-            outputs.wheel_1 = 50;
-            outputs.wheel_2 = 50;
-            outputs.wheel_3 = 50;
-        }
-             
-        
-        
-        
-    }
+     outputs.wheel_1 += direction.rotation -50;
+     outputs.wheel_2 += direction.rotation -50;
+     outputs.wheel_3 += direction.rotation -50;
+    
+    #else
+    
+    outputs.wheel_1 = direction.rotation;
+    outputs.wheel_2 = direction.x_translation;
+    outputs.wheel_3 = direction.y_translation;
+    
+    #endif
+    
+    /* Clamp outputs to correct range */
+    outputs.wheel_1 = clamp(outputs.wheel_1, 0, 100);
+    outputs.wheel_2 = clamp(outputs.wheel_2, 0, 100);
+    outputs.wheel_3 = clamp(outputs.wheel_3, 0, 100);
+    
+    #if defined (PC_DEBUGGING) && defined (DEBUG_CONTROLS)     
+    pc.printf("Final Controls: %i \t %i \t %i \r\n", outputs.wheel_1, outputs.wheel_2, outputs.wheel_3);
+    #endif        
+    
 }
 
 /** Heading correction
@@ -220,45 +321,83 @@
  *
  *  @param speed speed to rotate in percent
  */
-void calculate_heading_correction(float speed, float deadband){
-    
-    /* Sanitize speed */
-    if(speed > 100)
-        speed = 100;
-    else if(speed < 0)
-        speed = 0;
+void calculate_heading_correction(){
+    if(heading_lock_enabled){            
+                
+        /* Normalize headings */
+        float n_current_heading = normalize(orientation.heading);
+        float n_heading_lock = normalize(heading_lock);    
+        
+        #if defined (PC_DEBUGGING) && defined (DEBUG_HEADING_LOCK) 
+        pc.printf("Current heading: %f \t Desired Heading: %f \r\n", n_current_heading, n_heading_lock);
+        #endif
+        
+        /* Calculate error */
+        float error = n_current_heading - n_heading_lock;    
+        
+        /* Normalize error */
+        error = normalize(error);
         
-    /* speed is in percent, but controls normal position is at 50% for no movement */
-    speed /= 2;
-    
-    /* deadband specifies total angle to ignore, so split for each side */
-    deadband = (deadband / 2);
-    
-    /* Normalize headings */
-    float n_current_heading = normalize(orientation.heading);
-    float n_heading_lock = normalize(heading_lock);    
+        /* Figure out which way to turn */
+        if(abs(error) > heading_lock_deadband){  
+            
+            /* Speed is 0 -> 100
+             * error is -180 -> 180
+             * output is 0 -> 100
+             */         
+            //error = error * (heading_lock_speed / 100.0);    
+            #if defined (PC_DEBUGGING) && defined (DEBUG_HEADING_LOCK) 
+            pc.printf("ERROR: %7.2f", error);
+            #endif
+            error = map(error, -180, 180, 1.0, -1.0);         
+          
+            
+            float amount = error * 50;
+            
+            amount *= heading_lock_speed / 100.0;
+                       
+            direction.rotation += amount;
+          
+        }else{
+            
+            /* In deadband so do nothing */
+            direction.rotation = 50;
+        }
+        #if defined (PC_DEBUGGING) && defined (DEBUG_HEADING_LOCK)     
+        pc.printf("Heading error: (%7.2f) \t Rotation: (%7.2f) \t Speed: (%7.2f) \r\n", error, direction.rotation, heading_lock_speed);
+        #endif 
+        
+    }
+}
+
+/** Output to OmniMixer and ESCs 
+ * 
+ * Sends calculated output values to devices
+ */
+void output_stage(){
+    if(!failsafe){
+    //outputs.wheel_1 -= 18;
+    //outputs.wheel_2 -= 27;
+    //outputs.wheel_3 -= 14;
     
-    pc.printf("Current heading: %f, Desired Heading: %f", n_current_heading, n_heading_lock);
-    
-    /* Calculate error */
-    float error = n_current_heading - n_heading_lock;    
-    
-    /* Normalize error */
-    error = normalize(error);
-    
-    /* Figure out which way to turn */
-    if(error > deadband){
-        
-        /* Turning left */
-        direction.rotation += speed;        
-    }else if(error < -deadband){
-        
-        /* Turning right */
-        direction.rotation -= speed;        
+    esc_omni_1.setThrottle(outputs.wheel_1);
+    esc_omni_2.setThrottle(outputs.wheel_2);
+    esc_omni_3.setThrottle(outputs.wheel_3);
+    //esc_weapon_1.setThrottle(outputs.weapon_motor_1);
+    //esc_weapon_2.setThrottle(outputs.weapon_motor_2);
+    }else{
+        esc_omni_1.failsafe();
+        esc_omni_2.failsafe();
+        esc_omni_3.failsafe();        
     }
     
+    #if defined (PC_DEBUGGING) && defined (DEBUG_OUTPUT)  
+    pc.printf("OUTPUT M1: %i \t M2: %i \t M3: %i \t W1: %i \t W2: %i \r\n", outputs.wheel_1, outputs.wheel_2, outputs.wheel_3, outputs.weapon_motor_1, outputs.weapon_motor_2);
+    #endif
 }
 
+/******************************************************************************/
+
 /** Main
  * 
  * Main Loop
@@ -272,21 +411,31 @@
     init();
     
     while(true){
-        read_inputs();      
-          
-        //calculate_orientation();
-        //calculate_controls();
+        led1 = armed;
+        reset_outputs();
         
-        #ifdef HEADING_LOCK
-        calculate_heading_correction(speed, deadband){
+        #ifdef PC_DEBUGGING
+        pc.printf("\x1b[2J\x1b[H");
         #endif
-        //output_stage();
         
-        wait_ms(20);
-    }
-    
-    
-    
+        read_inputs(); 
+        if(armed && !just_armed){     
+            led1 = armed;
+            #ifdef ORIENTATION  
+            calculate_orientation();
+            #endif
+            
+            #ifdef HEADING_LOCK
+            calculate_heading_correction();
+            #endif
+            calculate_controls();
+                
+            output_stage();
+        }
+        #ifdef PC_DEBUGGING
+            wait_ms(50);
+        #endif
+    }     
 }