MIT Motor FOC Control
main.cpp
- Committer:
- benkatz
- Date:
- 2017-03-31
- Revision:
- 22:60276ba87ac6
- Parent:
- 20:bf9ea5125d52
- Child:
- 23:2adf23ee0305
File content as of revision 22:60276ba87ac6:
/// high-bandwidth 3-phase motor control, for robots /// Written by benkatz, with much inspiration from bayleyw, nkirkby, scolton, David Otten, and others /// Hardware documentation can be found at build-its.blogspot.com /// Written for the STM32F446, but can be implemented on other STM32 MCU's with some further register-diddling const unsigned int BOARDNUM = 0x2; //const unsigned int a_id = const unsigned int TX_ID = 0x0100; const unsigned int cmd_ID = (BOARDNUM<<8) + 0x7; #include "CANnucleo.h" #include "mbed.h" #include "PositionSensor.h" #include "structs.h" #include "foc.h" #include "calibration.h" #include "hw_setup.h" #include "math_ops.h" #include "current_controller_config.h" #include "hw_config.h" #include "motor_config.h" GPIOStruct gpio; ControllerStruct controller; COMStruct com; 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"); } 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); //sendCMD(TX_ID+b_ID, b1); //sendCMD(TX_ID+c_ID, c1); } Serial pc(PA_2, PA_3); PositionSensorAM5147 spi(16384, -0.4658, NPP); ///1 I really need an eeprom or something to store this.... PositionSensorEncoder encoder(4096, 0, 21); int count = 0; int mode = 0; float velocity_estimate(void){ velocity.vel_2 = encoder.GetMechVelocity(); velocity.vel_1 = spi.GetMechVelocity(); velocity.ts = .01f; velocity.vel_1_est = velocity.ts*velocity.vel_1 + (1-velocity.ts)*velocity.vel_1_est; //LPF velocity.vel_2_est = (1-velocity.ts)*(velocity.vel_2_est + velocity.vel_2 - velocity.vel_2_old); //HPF velocity.est = velocity.vel_1_est + velocity.vel_2_est; velocity.vel_1_old = velocity.vel_1; velocity.vel_2_old = velocity.vel_2; return velocity.est; } // Current Sampling Interrupt extern "C" void TIM1_UP_TIM10_IRQHandler(void) { if (TIM1->SR & TIM_SR_UIF ) { //toggle = 1; count++; ADC1->CR2 |= 0x40000000; //Begin sample and conversion //volatile int delay; //for (delay = 0; delay < 55; delay++); if(controller.mode == 2){ controller.adc2_raw = ADC2->DR; controller.adc1_raw = ADC1->DR; //toggle = 0; spi.Sample(); controller.theta_elec = spi.GetElecPosition(); commutate(&controller, &gpio, controller.theta_elec); } //controller.dtheta_mech = spi.GetMechVelocity(); //controller.dtheta_elec = encoder.GetElecVelocity(); //ontroller.dtheta_mech = encoder.GetMechVelocity(); //controller.i_q_ref = 2.0f*controller.dtheta_mech; //float v1 = encoder.GetMechVelocity(); //float v2 = spi.GetMechVelocity(); if(count > 100){ count = 0; //for (int i = 1; i<16; i++){ //pc.printf("%d\n\r ", spi.GetRawPosition()); // } //pc.printf("\n\r"); //pc.printf("%.4f %.4f %.4f\n\r",velocity.vel_1 ,velocity.vel_2, velocity.est ); } } TIM1->SR = 0x0; // reset the status register } void enter_torque_mode(void){ controller.mode = 2; TIM1->CR1 ^= TIM_CR1_UDIS; //enable interrupts controller.i_d_ref = 0; controller.i_q_ref = 1; reset_foc(&controller); //resets integrators, and other control loop parameters gpio.enable->write(1); GPIOC->ODR ^= (1 << 5); //turn on LED } void enter_calibration_mode(void){ controller.mode = 1; TIM1->CR1 ^= TIM_CR1_UDIS; gpio.enable->write(1); GPIOC->ODR ^= (1 << 5); //calibrate_encoder(&spi); order_phases(&spi, &gpio); calibrate(&spi, &gpio); GPIOC->ODR ^= (1 << 5); wait(.2); gpio.enable->write(0); TIM1->CR1 ^= TIM_CR1_UDIS; controller.mode = 0; } int main() { controller.v_bus = V_BUS; controller.mode = 0; //spi.ZeroPosition(); Init_All_HW(&gpio); // Setup PWM, ADC, GPIO wait(.1); //TIM1->CR1 |= TIM_CR1_UDIS; gpio.enable->write(1); gpio.pwm_u->write(1.0f); //write duty cycles gpio.pwm_v->write(1.0f); gpio.pwm_w->write(1.0f); zero_current(&controller.adc1_offset, &controller.adc2_offset); //Measure current sensor zero-offset //gpio.enable->write(0); reset_foc(&controller); //TIM1->CR1 ^= TIM_CR1_UDIS; //enable interrupt //gpio.enable->write(1); //gpio.pwm_u->write(1.0f - .05f); //write duty cycles //gpio.pwm_v->write(1.0f - .05f); //gpio.pwm_w->write(1.0f - .1f); 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); pc.baud(115200); wait(.01); pc.printf("HobbyKing Cheetah v1.1\n\r"); pc.printf("ADC1 Offset: %d ADC2 Offset: %d", controller.adc1_offset, controller.adc2_offset); wait(.01); enter_calibration_mode(); enter_torque_mode(); while(1) { } }