Motor control for robots. More compact, less object-oriented revision.

Dependencies:   FastPWM3 mbed-dev-f303

Fork of Hobbyking_Cheetah_V1 by Ben Katz

Revision:
26:2b865c00d7e9
Parent:
25:f5741040c4bb
Child:
27:501fee691e0e
--- a/main.cpp	Sun Apr 09 03:05:52 2017 +0000
+++ b/main.cpp	Mon May 01 15:22:58 2017 +0000
@@ -6,21 +6,28 @@
 
 #define REST_MODE 0
 #define CALIBRATION_MODE 1
-#define TORQUE_MODE 2
-#define PD_MODE 3
+#define MOTOR_MODE 2
 #define SETUP_MODE 4
 #define ENCODER_MODE 5
 
+#define P_MASK
+#define D_MASK
+#define KP_MASK
+#define KD_MASK
+#define TFF_MASK
 
+/*
 const unsigned int BOARDNUM = 0x2;
 //const unsigned int a_id =                            
-const unsigned int TX_ID = 0x0100;
 const unsigned int cmd_ID = (BOARDNUM<<8) + 0x7;
+*/
+const unsigned int TX_ID = 0x01;
+
 
-float __float_reg[64];
-int __int_reg[256];
+float __float_reg[64];                                                          // Floats stored in flash
+int __int_reg[256];                                                             // Ints stored in flash.  Includes position sensor calibration lookup table
 
-#include "CANnucleo.h"
+
 #include "mbed.h"
 #include "PositionSensor.h"
 #include "structs.h"
@@ -36,6 +43,7 @@
 #include "user_config.h"
 #include "PreferenceWriter.h"
 
+ 
 PreferenceWriter prefs(6);
 
 GPIOStruct gpio;
@@ -44,70 +52,112 @@
 VelocityEstimatorStruct velocity;
 
 
-CANnucleo::CAN          can(PB_8, PB_9);                                        // CAN Rx pin name, CAN Tx pin name
-CANnucleo::CANMessage   rxMsg;
-CANnucleo::CANMessage   txMsg;
-int                     ledState;
-int                     counter = 0;
-int canCmd = 1000;
-volatile bool           msgAvailable = false;
-
-DigitalOut toggle(PA_0);
-Ticker  loop;
-/**
- * @brief   'CAN receive-complete' interrup handler.
- * @note    Called on arrival of new CAN message.
- *          Keep it as short as possible.
- * @param   
- * @retval  
- */
-void onMsgReceived() {
-    msgAvailable = true;
-    //printf("ping\n\r");
-}
+//using namespace CANnucleo;
 
-void sendCMD(int TX_addr, int val){
-    txMsg.clear();      //clear Tx message storage
-    txMsg.id = TX_addr;
-    txMsg << val;
-    can.write(txMsg);
-    //wait(.1);
-    
-    }
-    
-void readCAN(void){
-    if(msgAvailable) { 
-    msgAvailable = false;                                                       // reset flag for next use
-    can.read(rxMsg);                                                            // read message into Rx message storage
-    // Filtering performed by software:           
-    if(rxMsg.id == cmd_ID) {                                                    // See comments in CAN.cpp for filtering performed by hardware
-            rxMsg >> canCmd;                                                    // extract first data item
-            }                                                                   
-        }
-    }
-    
-void cancontroller(void){
-    //printf("%d\n\r", canCmd);
-    readCAN();
-    //sendCMD(TX_ID, canCmd);
+CAN          can(PB_8, PB_9);                                        // CAN Rx pin name, CAN Tx pin name
+CANMessage   rxMsg;
+CANMessage   txMsg;
 
-    }
-    
 
 Serial pc(PA_2, PA_3);
 
-PositionSensorAM5147 spi(16384, 0.0, NPP);   
-PositionSensorEncoder encoder(4096, 0, 21); 
+PositionSensorAM5147 spi(16384, 0.0, NPP);  
+PositionSensorEncoder encoder(4096, 0, NPP); 
+
+
+DigitalOut toggle(PA_0);
 
 volatile int count = 0;
 volatile int state = REST_MODE;
 volatile int state_change;
 
+ #define P_MIN -12.5f
+ #define P_MAX 12.5f
+ #define V_MIN -30.0f
+ #define V_MAX 30.0f
+ #define KP_MIN 0.0f
+ #define KP_MAX 500.0f
+ #define KD_MIN 0.0f
+ #define KD_MAX 100.0f
+ #define T_MIN -18.0f
+ #define T_MAX 18.0f
+ 
+
+/// CAN Reply Packet Structure ///
+/// 16 bit position, between -4*pi and 4*pi
+/// 12 bit velocity, between -30 and + 30 rad/s
+/// 12 bit current, between -40 and 40;
+/// CAN Packet is 5 8-bit words
+/// Formatted as follows.  For each quantity, bit 0 is LSB
+/// 0: [position[15-8]]
+/// 1: [position[7-0]] 
+/// 2: [velocity[11-4]]
+/// 3: [velocity[3-0], current[11-8]]
+/// 4: [current[7-0]]
+void pack_reply(CANMessage *msg, float p, float v, float i){
+    int p_int = float_to_uint(p, P_MIN, P_MAX, 16);
+    int v_int = float_to_uint(v, V_MIN, V_MAX, 12);
+    int i_int = float_to_uint(i, -I_MAX, I_MAX, 12);
+    msg->data[0] = p_int>>8;
+    msg->data[1] = p_int&0xFF;
+    msg->data[2] = v_int>>4;
+    msg->data[3] = ((v_int&0xF)<<4) + (i_int>>8);
+    msg->data[4] = i_int&0xFF;
+    }
+    
+/// CAN Command Packet Structure ///
+/// 16 bit position command, between -4*pi and 4*pi
+/// 12 bit velocity command, between -30 and + 30 rad/s
+/// 12 bit kp, between 0 and 500 N-m/rad
+/// 12 bit kd, between 0 and 100 N-m*s/rad
+/// 12 bit feed forward torque, between -18 and 18 N-m
+/// CAN Packet is 8 8-bit words
+/// Formatted as follows.  For each quantity, bit 0 is LSB
+/// 0: [position[15-8]]
+/// 1: [position[7-0]] 
+/// 2: [velocity[11-4]]
+/// 3: [velocity[3-0], kp[11-8]]
+/// 4: [kp[7-0]]
+/// 5: [kd[11-4]]
+/// 6: [kd[3-0], torque[11-8]]
+/// 7: [torque[7-0]]
+void unpack_cmd(CANMessage msg, ControllerStruct * controller){
+    int p_int = (msg.data[0]<<8)|msg.data[1];
+    int v_int = (msg.data[2]<<4)|(msg.data[3]>>4);
+    int kp_int = ((msg.data[3]&0xF)<<8)|msg.data[4];
+    int kd_int = (msg.data[5]<<4)|(msg.data[6]>>4);
+    int t_int = ((msg.data[6]&0xF)<<8)|msg.data[7];
+    
+    controller->p_des = uint_to_float(p_int, P_MIN, P_MAX, 16);
+    controller->v_des = uint_to_float(v_int, V_MIN, V_MAX, 12);
+    controller->kp = uint_to_float(kp_int, KP_MIN, KP_MAX, 12);
+    controller->kd = uint_to_float(kd_int, KD_MIN, KD_MAX, 12);
+    controller->t_ff = uint_to_float(t_int, T_MIN, T_MAX, 12);
+    
+    /*
+    printf("Received   ");
+    printf("%.3f  %.3f  %.3f  %.3f  %.3f   %.3f", controller->p_des, controller->v_des, controller->kp, controller->kd, controller->t_ff, controller->i_q_ref);
+    printf("\n\r");
+    */
+    
+    }
+
+void onMsgReceived() {
+    //msgAvailable = true;
+    //printf("%.3f   %.3f   %.3f\n\r", controller.theta_mech, controller.dtheta_mech, controller.i_q);
+    can.read(rxMsg);  
+    if((rxMsg.id == CAN_ID) && (state == MOTOR_MODE)){
+        unpack_cmd(rxMsg, &controller);
+        pack_reply(&txMsg, controller.theta_mech, controller.dtheta_mech, controller.i_q);
+        can.write(txMsg);
+    }
+    
+}
+
 void enter_menu_state(void){
     printf("\n\r\n\r\n\r");
     printf(" Commands:\n\r");
-    printf(" t - Torque Mode\n\r");
-    printf(" p - PD Mode\n\r");
+    printf(" m - Motor Mode\n\r");
     printf(" c - Calibrate Encoder\n\r");
     printf(" s - Setup\n\r");
     printf(" e - Display Encoder\n\r");
@@ -121,6 +171,7 @@
     printf(" %-7s %-25s %-5s %-5s %-5s\n\r\n\r", "prefix", "parameter", "min", "max", "current value");
     printf(" %-7s %-25s %-5s %-5s %.1f\n\r", "b", "Current Bandwidth (Hz)", "100", "2000", I_BW);
     printf(" %-7s %-25s %-5s %-5s %-5i\n\r", "i", "CAN ID", "0", "127", CAN_ID);
+    printf(" %-7s %-25s %-5s %-5s %-5i\n\r", "m", "CAN Master ID", "0", "127", CAN_MASTER);
     printf(" %-7s %-25s %-5s %-5s %.1f\n\r", "l", "Torque Limit (N-m)", "0.0", "18.0", TORQUE_LIMIT);
     printf("\n\r To change a value, type 'prefix''value''ENTER'\n\r i.e. 'b1000''ENTER'\n\r\n\r");
     state_change = 0;
@@ -128,19 +179,19 @@
     
 void enter_torque_mode(void){
     controller.i_d_ref = 0;
-    controller.i_q_ref = 1;                                                     // Current Setpoints
+    controller.i_q_ref = 6;                                                     // Current Setpoints
     reset_foc(&controller);                                                     // Tesets integrators, and other control loop parameters
     gpio.enable->write(1);                                                      // Enable gate drive
-    GPIOC->ODR ^= (1 << 5);                                                     // Turn on status LED
+    GPIOC->ODR |= (1 << 5);                                                     // Turn on status LED
     state_change = 0;
     }
     
 void calibrate(void){
     gpio.enable->write(1);                                                      // Enable gate drive
-    GPIOC->ODR ^= (1 << 5);                                                     // Turn on status LED
+    GPIOC->ODR |= (1 << 5);                                                     // Turn on status LED
     order_phases(&spi, &gpio, &controller, &prefs);                             // Check phase ordering
     calibrate(&spi, &gpio, &controller, &prefs);                                // Perform calibration procedure
-    GPIOC->ODR ^= (1 << 5);                                                     // Turn off status LED
+    GPIOC->ODR &= !(1 << 5);                                                     // Turn off status LED
     wait(.2);
     gpio.enable->write(0);                                                      // Turn off gate drive
     printf("\n\r Calibration complete.  Press 'esc' to return to menu\n\r");
@@ -184,24 +235,31 @@
                     }
                 break;
              
-            case TORQUE_MODE:                                                   // Run torque control
+            case MOTOR_MODE:                                                   // Run torque control
                 if(state_change){
                     enter_torque_mode();
                     }
                 count++;
-                controller.theta_elec = spi.GetElecPosition();                  
+                toggle.write(1);
+                controller.theta_elec = spi.GetElecPosition();
+                controller.theta_mech = spi.GetMechPosition();
+                controller.dtheta_mech = spi.GetMechVelocity();  
+                //TIM1->CCR3 = 0x708*(1.0f);
+                //TIM1->CCR1 = 0x708*(1.0f);
+                //TIM1->CCR2 = 0x708*(1.0f);     
+                
+                //controller.i_q_ref = controller.t_ff/KT_OUT;   
+                //torque_control(&controller);      
+                controller.i_q_ref = 1; 
                 commutate(&controller, &gpio, controller.theta_elec);           // Run current loop
                 spi.Sample();                                                   // Sample position sensor
+                toggle.write(0);
+                
                 if(count > 100){
                      count = 0;
-                     //readCAN();
-                     //controller.i_q_ref = ((float)(canCmd-1000))/100;
-                    //pc.printf("%f\n\r ", controller.theta_elec);
+                     //printf("%d  %d\n\r", controller.adc1_raw, controller.adc2_raw);
                      }
                 break;
-            
-            case PD_MODE:
-                break;
             case SETUP_MODE:
                 if(state_change){
                     enter_setup_state();
@@ -211,9 +269,7 @@
                 print_encoder();
                 break;
                 }
-                
-   
-            
+                 
       }
   TIM1->SR = 0x0;                                                               // reset the status register
 }
@@ -233,6 +289,7 @@
                 state_change = 1;
                 char_count = 0;
                 cmd_id = 0;
+                GPIOC->ODR &= !(1 << 5); 
                 for(int i = 0; i<8; i++){cmd_val[i] = 0;}
                 }
         if(state == REST_MODE){
@@ -241,8 +298,8 @@
                     state = CALIBRATION_MODE;
                     state_change = 1;
                     break;
-                case 't':
-                    state = TORQUE_MODE;
+                case 'm':
+                    state = MOTOR_MODE;
                     state_change = 1;
                     break;
                 case 'e':
@@ -264,6 +321,9 @@
                     case 'i':
                         CAN_ID = atoi(cmd_val);
                         break;
+                    case 'm':
+                        CAN_MASTER = atoi(cmd_val);
+                        break;
                     case 'l':
                         TORQUE_LIMIT = fmaxf(fminf(atof(cmd_val), 18.0f), 0.0f);
                         break;
@@ -310,24 +370,27 @@
     Init_All_HW(&gpio);                                                         // Setup PWM, ADC, GPIO
 
     wait(.1);
-    //TIM1->CR1 |= TIM_CR1_UDIS;
-    gpio.enable->write(1);                                                      // Enable gate drive
-    gpio.pwm_u->write(1.0f);                                                    // Write duty cycles
-    gpio.pwm_v->write(1.0f);
-    gpio.pwm_w->write(1.0f);
+    gpio.enable->write(1);
+    TIM1->CCR3 = 0x708*(1.0f);                        // Write duty cycles
+    TIM1->CCR2 = 0x708*(1.0f);
+    TIM1->CCR1 = 0x708*(1.0f);
     zero_current(&controller.adc1_offset, &controller.adc2_offset);             // Measure current sensor zero-offset
-    //gpio.enable->write(0);
+    gpio.enable->write(0);
     reset_foc(&controller);                                                     // Reset current controller
-    
-    TIM1->CR1 ^= TIM_CR1_UDIS; //enable interrupt
+    TIM1->CR1 ^= TIM_CR1_UDIS;
+    //TIM1->CR1 |= TIM_CR1_UDIS; //enable interrupt
     
     wait(.1);
     NVIC_SetPriority(TIM5_IRQn, 2);                                             // set interrupt priority
 
+
     can.frequency(1000000);                                                     // set bit rate to 1Mbps
-    can.attach(&onMsgReceived);                                                 // attach 'CAN receive-complete' interrupt handler
-    can.filter(0x020 << 25, 0xF0000004, CANAny, 0);
-    
+    can.filter(CAN_ID<<21, 0xFFE00004, CANStandard, 0);
+    //can.filter(CAN_ID, 0xF, CANStandard, 0);
+    can.attach(&onMsgReceived);                                     // attach 'CAN receive-complete' interrupt handler                                                                    
+    txMsg.id = TX_ID;
+    txMsg.len = 5;
+    rxMsg.len = 8;
     
     prefs.load();                                                               // Read flash
     spi.SetElecOffset(E_OFFSET);                                                // Set position sensor offset
@@ -335,7 +398,7 @@
     memcpy(&lut, &ENCODER_LUT, sizeof(lut));
     spi.WriteLUT(lut);                                                          // Set potision sensor nonlinearity lookup table
     
-    pc.baud(115200);                                                            // set serial baud rate
+    pc.baud(921600);                                                            // set serial baud rate
     wait(.01);
     pc.printf("\n\r\n\r HobbyKing Cheetah\n\r\n\r");
     wait(.01);