servodisc goodness

Dependencies:   mbed-dev-f303

main.cpp

Committer:
benkatz
Date:
2017-10-27
Revision:
1:27b535673eed
Parent:
0:92d18e011d98
Child:
3:2e9713c61c2d

File content as of revision 1:27b535673eed:

#include "mbed.h"

#define PI              3.14159265f
#define PWM_ARR         0x2E8               // PWM timer auto-reload 
#define DT              0.00002067f         // PWM_ARR/36 MHz
#define CPR             8000.0f             // Encoder counts/revolution
#define J               0.00015f            // Inertia
#define KT              0.087f              // Torque Constant
#define R               0.85f               // Resistance
#define V_IN            40.0f               // DC input voltage
#define K_SAT           40.0f               // Controller saturation gain
#define DTC_MAX         0.95f               // Max duty cycle (limited by bootstrapping)
#define V               V_IN*DTC_MAX        // Max useable voltage

#define TICKSTORAD(x)           x*2*PI/CPR  
#define CONSTRAIN(x,min,max)    ((x)<(min)?(min):((x)>(max)?(max):(x)))

Serial pc (PA_2, PA_3);                     // Serial to programming header
Serial io(PB_6, PB_7);                      // Differential Serial to JST Header
DigitalIn id_1(PB_3);                       // ID Setting Jumpers
DigitalIn id_2(PB_4);
DigitalIn id_3(PB_5);
DigitalOut led(PA_15);                      // Debug LED
DigitalIn d_in(PA_4);                       // LED on input from AND Board
DigitalOut d_out(PA_5);                     // LED on output to AND Board


void Control();
void InitEncoder();
void InitPWM();
void InitGPIO();
void WriteVoltage( float v);
int GetID();



/* Control Variables */
int id;
int q_raw;
float q, q_old, dq, u, e, q_ref;
int count = 0;

/* PWM Timer Interrupt */
extern "C" void TIM1_UP_TIM16_IRQHandler(void) {    
  if (TIM1->SR & TIM_SR_UIF ) {
      }
      count++;
      Control();
      if(count > 5000){
          io.printf("derp\n\r");
          pc.printf("derp\n\r");
          led = !led;
          d_out = !d_out;
          count = 0;
          }
  TIM1->SR = 0x0; // reset the status register
}

/* Main Loop */
int main() {
    pc.printf("\n\r Rubix Controller\n\r");
    id = GetID();
    pc.printf(" Motor ID:  %d\n\r", id);
    
    io.baud(921600);
    
    id_1.mode(PullUp);
    id_2.mode(PullUp);
    id_3.mode(PullUp);
    d_in.mode(PullDown);
    led = 1;
    d_out = 1;
    
    InitEncoder();
    InitPWM();
    wait(.1);

    while(1) {
    }
}

/* Position Control */
void Control(void){
    q_raw = TIM2->CNT;
    q = TICKSTORAD(q_raw);
    dq = (q - q_old)/DT;
    q_old = q;
    e = K_SAT*((q_ref - q) + (-abs(dq)*dq*1.0f*R*J)/(2.0f*KT*(-V - KT*abs(dq))));   // Bullshit sliding mode control with nonlinear sliding surface, for minimum-time response
    u = CONSTRAIN(e, -V, V);
    //WriteVoltage(u);
    WriteVoltage(10.0f);
    }
    
/* Set motor voltage */
void WriteVoltage(float v){
    if(v>0){
        TIM1->CCR1 = 0;
        TIM1->CCR2 = (int) (PWM_ARR*(v/V));
        }
    else if(v<0){
        TIM1->CCR2 = 0;
        TIM1->CCR1 = (int) (PWM_ARR*(v/V));
        }
    }

/* Read ID Jumpers */
int GetID(void){
    int i1 = !id_1.read();
    int i2 = !id_2.read();
    int i3 = !id_3.read();
    return (i1<<2) | (i2<<1) | i3;
    }

/* Initialize Encoder */
void InitEncoder(void) {
    pc.printf("Initializing Encoder\n\r");
    // configure GPIO PA0 & PA1 as inputs for Encoder
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;                                      // enable the clock to GPIOA
    GPIOA->MODER   |= GPIO_MODER_MODER0_1 | GPIO_MODER_MODER1_1 ;           // PA0 & PA1 as Alternate Function 
    GPIOA->OTYPER  |= GPIO_OTYPER_OT_0 | GPIO_OTYPER_OT_1 ;                 // PA0 & PA1 as Inputs 
    GPIOA->OSPEEDR |= 0x00000011;                                           // GPIO Speed
    GPIOA->PUPDR   |= GPIO_PUPDR_PUPDR0_1 | GPIO_PUPDR_PUPDR1_1 ;           // Pull Down   
    GPIOA->AFR[0]  |= 0x00000011 ;                                          //  AF01 for PA0 & PA1 
    GPIOA->AFR[1]  |= 0x00000000 ;                                          //                                  
    
    // configure TIM2 as Encoder input
    RCC->APB1ENR |= 0x00000001;                             // Enable clock for TIM2
    TIM2->CR1   = 0x0001;                                   // CEN(Counter Enable)='1'   
    TIM2->SMCR  = 0x0003;                                   // SMS='011' (Encoder mode 3)   
    TIM2->CCMR1 = 0x5151;                                   // CC1S='01' CC2S='01'          
    TIM2->CCMR2 = 0x0000;                                                                 
    TIM2->CCER  = 0x0011;                                   // CC1P CC2P                    
    TIM2->PSC   = 0x0000;                                   // Prescaler = (0+1)            
    TIM2->CNT = 0x0000;                                     //reset the counter before we use it  
}

/* Initialize PWM */
void InitPWM(void){
    pc.printf("Initializing PWM\n\r");
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;                      // enable the clock to GPIOA
    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;                      // enable the clock to GPIOB
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;                     // enable TIM1 clock
    
    GPIOA->MODER   |= GPIO_MODER_MODER7_1 | GPIO_MODER_MODER8_1 | GPIO_MODER_MODER9_1 ;     //PA_7, PA_8, PA_9 to alternate funtion mode
    GPIOB->MODER   |= GPIO_MODER_MODER0_1;                  // PB_0 to alternate function mode
    GPIOA->AFR[0]    |= 0x60000000;                         // PA_7 to alternate function 6
    GPIOA->AFR[1]    |= 0x00000066;                         // PA_8, PA_9 to alternate function 6
    GPIOB->AFR[0]    |= 0x00000006;                         // PB_0 to alternate function 6
    
    //PWM Setup
    TIM1->CCMR1 |= 0x6060;                                  // Enable output compare 1 and 2
    TIM1->CCER |= TIM_CCER_CC1E | TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC2E;  // enable outputs 1, 2, and complementary outputs
    TIM1->BDTR |= TIM_BDTR_MOE | 0xF;                       // MOE = 1 | set dead-time
    TIM1->PSC = 0x0;                                        // no prescaler, timer counts up in sync with the peripheral clock
    TIM1->ARR = PWM_ARR;                                    // set auto reload
    TIM1->CR1 |= TIM_CR1_ARPE;                              // autoreload on, 
    TIM1->CR1 |= TIM_CR1_CEN;                               // enable TIM1
    
    NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);                     //Enable TIM1 IRQ

    TIM1->DIER |= TIM_DIER_UIE;                             // enable update interrupt
    TIM1->CR1 |= 0x40;                                      //CMS = 10, interrupt only when counting up
    TIM1->RCR |= 0x001;                                     // update event once per up/down count of tim1 
    TIM1->EGR |= TIM_EGR_UG;                                
    }