Thesis Rotating Platform, Uart Control
Dependencies: BufferedSerial X_NUCLEO_IHM01A1_Disabled_Control mbed
Fork of Demo_IHM01A1_3-Motors by
Diff: main.cpp
- Revision:
- 23:1bcf834fb859
- Parent:
- 21:ed054abddfe4
- Child:
- 25:716a21ab5fd3
--- a/main.cpp Mon Mar 14 09:09:02 2016 +0000 +++ b/main.cpp Wed May 24 10:01:41 2017 +0000 @@ -1,91 +1,297 @@ -/** - ****************************************************************************** - * @file main.cpp - * @author Davide Aliprandi, STMicroelectronics - * @version V1.0.0 - * @date October 14th, 2015 - * @brief mbed test application for the STMicroelectronics X-NUCLEO-IHM01A1 - * Motor Control Expansion Board: control of 2 motors. - ****************************************************************************** - * @attention - * - * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ +//////////////////////////////////////// +// Rotating Platform // +// Arkadiraf@gmail.com - 24/05/2017 // +//////////////////////////////////////// + +/* + Parts: + Nucleo STM32F401RE + X-NUCLEO-IHM01A1 - 3 Stepper motor controller +*/ + +/* + Pinout: + Nucleo STM32F401RE + PA_5 --> led (DigitalOut) + + PC - Serial 2 + PA_2 (Tx) --> STLINK + PA_3 (Rx) --> STLINK + + X-NUCLEO-IHM01A1 (http://www.st.com/content/ccc/resource/technical/document/data_brief/59/ff/d0/16/94/ff/49/85/DM00122463.pdf/files/DM00122463.pdf/jcr:content/translations/en.DM00122463.pdf) + SPI: + PA_7 (D11) --> mosi + PA_9 (D12) --> miso + PA_8 (D13) --> sclk + + Motor 1 + PA_10(D2) --> flag_irq (DigitalOut) + PA_9 (D8) --> Standby (DigitalOut) + PA_8 (D7) --> MOT1Dir (DigitalOut) + PC_7 (D9) --> MOT1Step (PWM) + PB_6 (D10)--> ssel (DigitalOut) + + Motor 2 + PA_10(D2) --> flag_irq (DigitalOut) + PA_9 (D8) --> Standby (DigitalOut) + PB_5 (D4) --> MOT2Dir (DigitalOut) + PB_3 (D3) --> MOT2Step (PWM) + PB_6 (D10)--> ssel (DigitalOut) + + Motor 3 + PA_10(D2) --> flag_irq (DigitalOut) + PA_9 (D8) --> Standby (DigitalOut) + PB_4 (D5) --> MOT3Dir (DigitalOut) + PB_10(D6) --> MOT3Step (PWM) + PB_6 (D10)--> ssel (DigitalOut) -/* Includes ------------------------------------------------------------------*/ - -/* mbed specific header files. */ -#include "mbed.h" +*/ -/* Helper header files. */ -#include "DevSPI.h" - -/* Component specific header files. */ -#include "l6474_class.h" +/////////////// +// Libraries // +/////////////// +#include "mbed.h" +#include "BufferedSerial.h" // solves issues of loosing data. alternative doing it yourself +#include "FastPWM.h" // high frequency pwm with good resolution +#include "l6474_class.h" // stepper library -/* Definitions ---------------------------------------------------------------*/ - -/* Number of steps to move. */ -#define STEPS 3200 +/////////////// +// #defines // +/////////////// +#define DEBUG_MSG +#define Motor_Control_Interval 2000 // 500Hz +#define TimeoutCommand 2000 // 2 second (ms units) +#define STEPS2ROTATION 3200.0f // Number of steps for rotation at 16 microstepping -/* Variables -----------------------------------------------------------------*/ +///////////// +// Objects // +///////////// + +// X-NUCLEO-IHM01A1 +DigitalOut MOT1Dir(D7); +DigitalOut MOT1Step(D9); +DigitalOut MOT2Dir(D4); +DigitalOut MOT2Step(D3); +DigitalOut MOT3Dir(D5); +DigitalOut MOT3Step(D6); /* Motor Control Component. */ L6474 *motor1; L6474 *motor2; L6474 *motor3; -/* Main ----------------------------------------------------------------------*/ +// Led +DigitalOut led(LED1); + +// serial +BufferedSerial pc(USBTX, USBRX); + +// Define Ticker for Motor Motion Control Ticker +Ticker Platform_Control_Ticker; + +// Define Ticker for Steps control +Ticker Motor1_Step_Ticker; +Ticker Motor2_Step_Ticker; +Ticker Motor3_Step_Ticker; + +// Timer for clock counter +Timer time_timer; + + +/////////////// +// variables // +/////////////// + +// Driver Flag status, enabled / disabled +bool EN_Stepper_Flag=0; + +// Motor Speed control +volatile float CMD_Motor_SPD[3]= {0}; +volatile float Motor_SPD[3]= {0}; +// Motor Position control +volatile float CMD_Motor_Pos[3]= {0}; +volatile float Motor_Pos[3]= {0}; + +// timeout command time stamp +volatile int CMDTimeStamp=0; + +/////////////// +// Functions // +/////////////// + +// Incoming Message parser +void Parse_Message(char inbyte); + +// Init Platform +void Platform_Init(); + +// Platform Motion Set +void Platform_Motion_Set(float Set_SPD_M1, float Set_SPD_M2, float Set_SPD_M3); + +// Platform Motion Control +void Platform_Motion_Control(); + +// Motor1 Step Control +void Motor1_Step_Control(); + +// Motor2 Step Control +void Motor2_Step_Control(); + +// Motor3 Step Control +void Motor3_Step_Control(); + +//////////////////////// +// Main Code Setup : // +//////////////////////// int main() { - /*----- Initialization. -----*/ - - /* Initializing SPI bus. */ + //Initializing SPI bus. DevSPI dev_spi(D11, D12, D13); - - /* Initializing Motor Control Components. */ + + //Initializing Motor Control Components. motor1 = new L6474(D2, D8, D7, D9, D10, dev_spi); motor2 = new L6474(D2, D8, D4, D3, D10, dev_spi); - motor3 = new L6474(D2, D8, D5, D6, D10, dev_spi); + motor3 = new L6474(D2, D8, D5, D6, D10, dev_spi); + + // Setup serial + pc.baud(57600); + + // Init shika shuka + Platform_Init(); + + // initil time timer: + time_timer.start(); + + /////////////////////// + // Main Code Loop : // + /////////////////////// + while(1) { + // loop time stamp + int Timer_TimeStamp_ms=time_timer.read_ms(); + static int ADC_Read_time=0; + + // receive Motor Command + while (InMSG.readable()) { + char InChar=InMSG.getc(); + //pc.printf("%c" ,InChar); // debug check/ + Parse_Message(InChar); + }//end serial + + // set time out on commad and stop motion + if (abs(Timer_TimeStamp_ms-CMDTimeStamp)>TimeoutCommand){ +#ifdef DEBUG_MSG + // pc.printf("Timer_TimeStamp_ms %d CMDTimeStamp %d\r\n", Timer_TimeStamp_ms,CMDTimeStamp); +#endif /* DEBUG_MSG */ + CMDTimeStamp=Timer_TimeStamp_ms; + PitchMotor->Disable(); + RollMotor->Disable(); + CMD_Motor_SPD[0]=0; + CMD_Motor_SPD[1]=0; + Motor_SPD[0]=0; + Motor_SPD[1]=0; + EN_Stepper_Flag=0; + } + + // read ADC value + if (abs(Timer_TimeStamp_ms-ADC_Read_time)>VccReadDelay) { + ADC_Read_time=Timer_TimeStamp_ms; + // LPF on value + float ReadVoltage=Vcc_11.read(); + ReadVoltage=ReadVoltage* 3.3f*11.0f; // 1/11 voltage divider + + static float dt_VCC_Read=((float)VccReadDelay)/1000.0f; + static float Alpha_LPF=dt_VCC_Read/(1.0f+dt_VCC_Read) ; // α := dt / (RC + dt) + + // LPF: y[i] := y[i-1] + α * (x[i] - y[i-1]) + VCC_Voltage = VCC_Voltage + Alpha_LPF * (ReadVoltage - VCC_Voltage); + // disable motion if voltage too low + if (VCC_Voltage<VCC_Thresh) { + PitchMotor->Disable(); + RollMotor->Disable(); + Motor_SPD[0]=0; + Motor_SPD[1]=0; + EN_Stepper_Flag=0; + } + +#ifdef DEBUG_MSG + //pc.printf("CMD: %.3f ,%.3f ,%.3f ,%.3f \r\n" ,CMD_Values[0],CMD_Values[1],CMD_Values[2],CMD_Values[3]); // debug check/ + //pc.printf("VCC = %.2f LPF_V %.2f V \r\n", VCC_Voltage,ReadVoltage); + +#endif /* DEBUG_MSG */ + } + }// End Main Loop +}// End Main + + +/////////////// +// Functions // +/////////////// +// Incoming Message parser Format: "$<SPD_M1>,<SPD_M2>,<SPD_YAW>,<PITCH_ANGLE>\r\n" // up to /r/n +void Parse_Message(char inbyte) +{ + static const uint16_t BufferCMDSize=32; + static const uint16_t BufferCMD_ValuesSize=4; + + static float CMD_Values[BufferCMD_ValuesSize]= {0}; + static char BufferCMD[BufferCMDSize]= {0}; + static uint16_t BufferIndex=0; + static uint16_t Values_Index=0; + + BufferIndex=BufferIndex%(BufferCMDSize); // simple overflow handler + Values_Index=Values_Index%(BufferCMD_ValuesSize); // simple overflow handler + + BufferCMD[BufferIndex]=inbyte; + BufferIndex++; + + // parse incoming message + if (inbyte=='$') { // start of message + BufferIndex=0; // initialize to start of parser + Values_Index=0; // index for values position + } else if (inbyte==',') { // seperator char + CMD_Values[Values_Index]=atof(BufferCMD); // input value to buffer values + BufferIndex=0; // initialize to start of parser + Values_Index++; + } else if(inbyte=='\r') { // end of message // parse message + // Update last value + CMD_Values[Values_Index]=atof(BufferCMD); // input value to buffer values + + BufferIndex=0; // initialize to start of parser + Values_Index=0; // reset values index + + // set time stamp on time out commad + CMDTimeStamp=time_timer.read_ms(); + // update command + ShikaShuka_Motion_Set(CMD_Values[2],CMD_Values[3]); + + // send out the remaining message for the brushed controller + OutMSG.printf("$%.3f,%.3f\r\n",CMD_Values[0],CMD_Values[1]); + +#ifdef DEBUG_MSG + pc.printf("CMD: %.3f ,%.3f ,%.3f ,%.3f \r\n" ,CMD_Values[0],CMD_Values[1],CMD_Values[2],CMD_Values[3]); // debug check/ + //pc.printf("CMD: %.3f ,%.3f \r\n" ,CMD_Values[0],CMD_Values[1]); // debug check/ + led = !led; +#endif /* DEBUG_MSG */ + + }//end parser +}// end parser function + + +// Init shika shuka +void Platform_Init() +{ + //Initializing Motor Control Components. if (motor1->Init() != COMPONENT_OK) exit(EXIT_FAILURE); if (motor2->Init() != COMPONENT_OK) exit(EXIT_FAILURE); if (motor3->Init() != COMPONENT_OK) exit(EXIT_FAILURE); - - - + /*----- Changing motor setting. -----*/ - /* Setting High Impedance State to update L6474's registers. */ motor1->SoftHiZ(); motor2->SoftHiZ(); @@ -98,89 +304,138 @@ motor1->SetStepMode(STEP_MODE_1_16); motor2->SetStepMode(STEP_MODE_1_16); motor3->SetStepMode(STEP_MODE_1_16); - /* Increasing the torque regulation current to 500mA. */ - motor1->SetParameter(L6474_TVAL, 1250); // Limit 2.0A - motor2->SetParameter(L6474_TVAL, 1700); // Limit 1.7A - motor3->SetParameter(L6474_TVAL, 850); // Limit 1.0A - - /* Max speed to 2400 step/s. */ - motor1->SetMaxSpeed(1000); - motor2->SetMaxSpeed(1000); - motor3->SetMaxSpeed(1000); - /* Min speed to 200 step/s. */ - motor1->SetMinSpeed(100); - motor2->SetMinSpeed(100); - motor3->SetMinSpeed(100); - - /* set accelerations */ - motor1->SetAcceleration(500); - motor2->SetAcceleration(500); - motor3->SetAcceleration(500); - motor1->SetDeceleration(500); - motor2->SetDeceleration(500); - motor3->SetDeceleration(500); + /* Increasing the torque regulation current. */ + motor1->SetParameter(L6474_TVAL, 1250); // Limit 2.0A + motor2->SetParameter(L6474_TVAL, 1650); // Limit 1.7A + motor3->SetParameter(L6474_TVAL, 250); // Limit 0.28A + + /* Increasing the max threshold overcurrent. */ + motor1->SetParameter(L6474_OCD_TH, L6474_OCD_TH_2625mA); + motor2->SetParameter(L6474_OCD_TH, L6474_OCD_TH_2625mA); + motor3->SetParameter(L6474_OCD_TH, L6474_OCD_TH_750mA); // Enabling motor motor1->Enable(); motor2->Enable(); motor3->Enable(); - + + // Initialize Control Pins + MOT1Dir.write(0); + MOT1Step.write(0); + MOT2Dir.write(0); + MOT2Step.write(0); + MOT3Dir.write(0); + MOT3Step.write(0); - /* Printing to the console. */ - printf("Motor Control Application Example for 3 Motors\r\n\n"); - - /*----- Moving. -----*/ + // Start Moition Control + Platform_Control_Ticker.attach_us(&ShikaShuka_Motion_Control, ShikaShuka_Control_Interval); - /* Moving N steps in the forward direction. */ - motor1->Move(StepperMotor::FWD, STEPS); - motor2->Move(StepperMotor::FWD, STEPS); - motor3->Move(StepperMotor::FWD, STEPS); - /* Waiting while the motor is active. */ - motor1->WaitWhileActive(); - motor2->WaitWhileActive(); - motor3->WaitWhileActive(); - - /* Waiting 2 seconds. */ - wait_ms(2000); - +}// End Init shika shuka - /* Moving N steps in the backward direction. */ - motor1->Move(StepperMotor::BWD, STEPS); - motor2->Move(StepperMotor::BWD, STEPS); - motor3->Move(StepperMotor::BWD, STEPS); - /* Waiting while the motor is active. */ - motor1->WaitWhileActive(); - motor2->WaitWhileActive(); - motor3->WaitWhileActive(); +// ShikaShuka Motion Set +void ShikaShuka_Motion_Set(float Set_SPD_M1, float Set_SPD_M2) +{ + static const float MaxSPDCMD=5.0f; + static const float DeadZoneCMD=0.001f; + + // variable limits: (-MaxSPDCMD>SPD_M>MaxSPDCMD) + if (Set_SPD_M1 > MaxSPDCMD) Set_SPD_M1 = MaxSPDCMD; + if (Set_SPD_M1 < -MaxSPDCMD) Set_SPD_M1 = -MaxSPDCMD; + if (abs(Set_SPD_M1) < DeadZoneCMD) Set_SPD_M1 = 0; - /* Waiting 2 seconds. */ - wait_ms(2000); + if (Set_SPD_M2 > MaxSPDCMD) Set_SPD_M2 = MaxSPDCMD; + if (Set_SPD_M2 < -MaxSPDCMD) Set_SPD_M2 = -MaxSPDCMD; + if (abs(Set_SPD_M2) < DeadZoneCMD) Set_SPD_M2 = 0; + // verify voltage level: + if (VCC_Voltage>VCC_Thresh) { + // enable stepper drivers + if (EN_Stepper_Flag==0){ + PitchMotor->Enable(); + RollMotor->Enable(); + EN_Stepper_Flag=1; + } + // update motor speed command + CMD_Motor_SPD[0]=Set_SPD_M1; + CMD_Motor_SPD[1]=Set_SPD_M2; + } else { + // disable motion if voltage too low + if (EN_Stepper_Flag==1){ + PitchMotor->Disable(); + RollMotor->Disable(); + Motor_SPD[0]=0; + Motor_SPD[1]=0; + EN_Stepper_Flag=0; + } + CMD_Motor_SPD[0]=0; + CMD_Motor_SPD[1]=0; + } +}// End ShikaShuka Motion Set - /* Infinite Loop. */ - while(1) - { - /*----- Moving. -----*/ +// ShikaShuka Motion Control +void ShikaShuka_Motion_Control() +{ + // variable limits: (-100>SPD_M>100) + static const float MaxSPD=5.0f; + static const float DeadZone=0.001f; + static const float MaxACC=0.5f/(1000000/ShikaShuka_Control_Interval); //acceleration set as val/sec here for open loop it is %/sec - /* Moving N steps in the forward direction. */ - motor1->Move(StepperMotor::FWD, STEPS); - motor2->Move(StepperMotor::FWD, STEPS); - motor3->Move(StepperMotor::FWD, STEPS); - /* Waiting while the motor is active. */ - motor1->WaitWhileActive(); - motor2->WaitWhileActive(); - motor3->WaitWhileActive(); - - /* Moving N steps in the backward direction. */ - motor1->Move(StepperMotor::BWD, STEPS); - motor2->Move(StepperMotor::BWD, STEPS); - motor3->Move(StepperMotor::BWD, STEPS); - /* Waiting while the motor is active. */ - motor1->WaitWhileActive(); - motor2->WaitWhileActive(); - motor3->WaitWhileActive(); - - /* Waiting 2 seconds. */ - wait_ms(2000); + static float SetMotorSPDPWM[2]= {0}; // the actual command set frequency in Hz + + // implement control loop here: (basic control with max acceleration limit) + if(1) { + if (abs(CMD_Motor_SPD[0]-Motor_SPD[0])> MaxACC) { + CMD_Motor_SPD[0]>Motor_SPD[0] ? Motor_SPD[0]+=MaxACC : Motor_SPD[0]-=MaxACC; + } else { + Motor_SPD[0]=CMD_Motor_SPD[0]; + } + if (abs(CMD_Motor_SPD[1]-Motor_SPD[1])> MaxACC) { + CMD_Motor_SPD[1]>Motor_SPD[1] ? Motor_SPD[1]+=MaxACC : Motor_SPD[1]-=MaxACC; + } else { + Motor_SPD[1]=CMD_Motor_SPD[1]; + } + } + // update driver PWM frequency + if (1) { + // motor 1 + if (abs(Motor_SPD[0])<DeadZone) { + SetMotorSPDPWM[0]=1; + PitchStep.write(0); // disable pulsing, euqal to stop + } else { + // Set Pulse rate based on pulses per second + SetMotorSPDPWM[0]=(abs(Motor_SPD[0])*STEPS2ROTATION); // rotation per second, to pulses with duty cycle of 0.5 + PitchStep.write(0.5f); // enable pulsing + } + // update driver PWM based on direction + if (SetMotorSPDPWM[0]>STEPS2ROTATION*MaxSPD) SetMotorSPDPWM[0]=STEPS2ROTATION*MaxSPD; // make sure pwm command is trimmed + if (SetMotorSPDPWM[0]<1) SetMotorSPDPWM[0]=1; // make sure pwm command is trimmed + + if (Motor_SPD[0]>0) { + PitchDir.write(1); + } else { + PitchDir.write(0); + } + PitchStep.period(1.0f/(SetMotorSPDPWM[0])); + + // motor 2 + if (abs(Motor_SPD[1])<DeadZone) { + SetMotorSPDPWM[1]=1; + RollStep.write(0); // disable pulsing, euqal to stop + } else { + // Set Pulse rate based on pulses per second + SetMotorSPDPWM[1]=(abs(Motor_SPD[1])*STEPS2ROTATION); // rotation per second, to pulses with duty cycle of 0.5 + RollStep.write(0.5f); // enable pulsing + } + // update driver PWM based on direction + if (SetMotorSPDPWM[1]>STEPS2ROTATION*MaxSPD) SetMotorSPDPWM[1]=STEPS2ROTATION*MaxSPD; // make sure pwm command is trimmed + if (SetMotorSPDPWM[1]<1) SetMotorSPDPWM[1]=1; // make sure pwm command is trimmed + + if (Motor_SPD[1]>0) { + RollDir.write(1); + } else { + RollDir.write(0); + } + RollStep.period(1.0f/(SetMotorSPDPWM[1])); } -} + //pc.printf("CMD: %.3f ,%.3f \r\n" ,SetMotorSPDPWM[0],SetMotorSPDPWM[1]); // debug check/ +}// End ShikaShuka Motion Control