For flywheel rig. Interfaces with matlab flywheel interface. 2.007 MIT Biomimetics Robotics Lab. Sangbae Kim. Ben Katz.

Dependencies:   mbed

main.cpp

Committer:
abraham1
Date:
2017-04-14
Revision:
12:f9f08c7551f4
Parent:
11:ad41446b0edb

File content as of revision 12:f9f08c7551f4:

///setup code for encoder on pins PA0 and PA1 (A0 and A1)///

// TODO: explain basic flow of run and data collection

#include "mbed.h"
#include "time.h"
#include "stdio.h"
#include "ctype.h"

#define PI 3.14159265358979323846

//Just for basic debugging
//User button controls motor speed
//Green LED should turn on while listening to pc for input before starting run
InterruptIn button(USER_BUTTON);
DigitalOut green(LED2);

// Pololu VNH5019 Motor Driver Carrier. https://www.pololu.com/product/1451
PwmOut pwm(D5);     //pwm input on motor controller. do not use D3
DigitalOut a(D2);   //IN_A input on motor controller
DigitalOut b(D4);   //IN_B input on motor controller

//Hook up to Vout on current sensor
//SparkFun Hall-Effect Current Sensor Breakout - ACS712
//https://www.sparkfun.com/products/8882
AnalogIn currentSense(A5);

//For communication with pc through matlab
//Make sure baud rates are equal
Serial pc(USBTX, USBRX, 115200);

const int CPR = 900*4;  // Encoder counts per revolution (900).  Change to match your encoder. x4 for quadrature
const double VREF = 3;  // Microcontroller reference voltage
const float currentSensorOutputRatio = 0.185;   // Volts/Amp specified by current sensor. Divide Voltage by cSenseOutput to get current
const float PSupply_Voltage = 12.0;             // Voltage input from power supply
const float Output_Voltage = 2.0;               // Desired output voltage to motor
const float pwm_flywheel = Output_Voltage/PSupply_Voltage;

void EncoderInitialise(void) {
    // configure GPIO PA0 & PA1 as inputs for Encoder
    RCC->AHB1ENR |= 0x00000001;  // Enable clock for GPIOA
 
    GPIOA->MODER   |= GPIO_MODER_MODER0_1 | GPIO_MODER_MODER1_1 ;           //PA0 & PA1 as Alternate Function   /*!< GPIO port mode register,               Address offset: 0x00      */
    GPIOA->OTYPER  |= GPIO_OTYPER_OT_0 | GPIO_OTYPER_OT_1 ;                 //PA0 & PA1 as Inputs               /*!< GPIO port output type register,        Address offset: 0x04      */
    GPIOA->OSPEEDR |= 0x00000011;//|= GPIO_OSPEEDER_OSPEEDR0 | GPIO_OSPEEDER_OSPEEDR1 ;     // Low speed                        /*!< GPIO port output speed register,       Address offset: 0x08      */
    GPIOA->PUPDR   |= GPIO_PUPDR_PUPDR0_1 | GPIO_PUPDR_PUPDR1_1 ;           // Pull Down                        /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
    GPIOA->AFR[0]  |= 0x00000011 ;                                          //  AF01 for PA0 & PA1              /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
    GPIOA->AFR[1]  |= 0x00000000 ;                                          //                                  /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
   
    // configure TIM2 as Encoder input
    RCC->APB1ENR |= 0x00000001;  // Enable clock for TIM2
 
    TIM2->CR1   = 0x0001;       // CEN(Counter Enable)='1'     < TIM control register 1
    TIM2->SMCR  = 0x0003;       // SMS='011' (Encoder mode 3)  < TIM slave mode control register
    TIM2->CCMR1 = 0x0101;       // CC1S='01' CC2S='01'         < TIM capture/compare mode register 1
    TIM2->CCMR2 = 0x0000;       //                             < TIM capture/compare mode register 2
    TIM2->CCER  = 0x0011;       // CC1P CC2P                   < TIM capture/compare enable register
    TIM2->PSC   = 0x0000;       // Prescaler = (0+1)           < TIM prescaler
    TIM2->ARR   = CPR;          // reload at CPR               < TIM auto-reload register
    TIM2->CNT = 0x0000;         //reset the counter before we use it  
}


//Zero encoder count//
void ZeroEncoder() {
    TIM2->CNT=0 ; //reset timer count to zero
}

int GetCounts(void) {
    int count = TIM2->CNT;  //Read the timer count register
    return count;
    }
    
void pressed() {
    float pwm_float = pwm.read();
    int pwmV = (int)(100*pwm_float);
    if(pwmV == 0){
        pwm.write(0.05);
    } else if (pwmV == 5){
        pwm.write(0.2);
    } else if (pwmV == 20){
        pwm.write(0.75);
    } else if (pwmV == 75){
        pwm.write(0.0);
    } else {
        pwm.write(0.0);
    }
}


int main() {
    
    int endcount, startcount; //encoder counts
    double time_between_readings; //between encoder readings
    double velocity;
    double currentSensed = 0;
    clock_t start, end, absoluteStart;
    int ticks;
    a=1; b=0; pwm.write(0);
    button.fall(&pressed);  //adds pressed callback upon button push
    
    /*  we don't send all the information to matlab all the time. some collection and smoothing is done
        here in order to not overload matlab with input making it slow. And to take a lot of data so we
        can do smoothing quickly on this side */
    double updatePeriod = 0.01; /* must select carefully. too fast and you don't get enough encoder ticks*/
    double publishFrequency = 0.05; /* seconds. rate to publish to matlab. no need to overload matlab with input*/
    double samplesPerPublish = (int)(publishFrequency/updatePeriod); /*this improves time response of current filter and maintains smoothness*/
    int publishCounter = 1;
    
    /* the filter ratio on the speed data from encoder and on current input */
    double filterRatio = 0.1;
    double currentFilterRatio = 0.035;
    
    /* the current sensor has some resting value. record and subtract that out */
    float currentSensorOffset = 0; int i; 
    for(i=1;i<301;i++){ currentSensorOffset += currentSense.read(); }
    currentSensorOffset = currentSensorOffset*VREF/300;
    
    EncoderInitialise();
    fflush(pc); //clear any previous output
    
        
    while(1) {
    

        
        while(1) {                              //Listen for PC input to start run
            green = true;
            if(pc.readable()) {
                char charIn = pc.getc();
                if(charIn == 'g'){ 
                    fflush(pc);
                    absoluteStart = clock();
                    end = clock();
                    ZeroEncoder();
                    velocity = 0;
                    startcount = 0;
                    endcount = 0;
                    currentSensed = 0;
                    pwm.write(pwm_flywheel);
                    break; 
                }
            }
            wait(0.05);
        }  
    
    
        
        while(1) {
            
            green = false;
            wait(updatePeriod);
            start = end;
            end = clock();        
            time_between_readings = ((double)(end - start)) / CLOCKS_PER_SEC;
            startcount = endcount;
            endcount = GetCounts();       
            ticks = endcount-startcount;
            if(abs(ticks)>CPR/2) /***** for rollover case: *****/
            { ticks = ((ticks<0)-(ticks>0))*(CPR-abs(ticks)); }
            
            velocity = filterRatio*((double)ticks)/CPR*2*PI/time_between_readings + (1-filterRatio)*velocity; /* with filtering*/
            currentSensed = currentFilterRatio*((double)currentSense.read()*VREF-currentSensorOffset) + (1-currentFilterRatio)*currentSensed;
            
            if(pc.readable()) {             //PC will send 'r' when run is finished
                char charIn = pc.getc();
                if(charIn == 'r'){
                    fflush(pc);
                    pwm.write(0.0);         //kill the motor
                    break;                  //return to listening loop
                }
            }        
            
            if(publishCounter == samplesPerPublish) {           //only publish once every samplesPerPublish
                printf("%+9.5f,%+8.4f,%+9.4f,%+8.2f\n", currentSensed/currentSensorOutputRatio, pwm.read(), -velocity, ((double)(end-absoluteStart)/CLOCKS_PER_SEC));
                publishCounter = 1;  //output formatting very important. running a simple string length checksum on matlab side to discard bad data
            }
            publishCounter++;
            
        }
    
    
    }
    
}