Evening,
I’m testing the SimpleFOC library on a VESC 6 with some confident results! i started from this topic and simply re-mapped the MCU pins following the schematic of the new VESC version. I’m using PlatformIO and had a bit of trouble getting the serial to work via USB (had to put monitor_dtr = 1 on the .ino) but couldn’t get USART6 functioning (for now i’ll not use it).
I had already done some testing on the B-G431B-ESC1 but the initFOC() couldn’t calculate the number of motor poles and the zero electric angle correctly probably due to a faulty motor.
I’m now using a Flipsky 6354 and the init routine completes successfully.
However the strange fact remains that the motor moves smoothly in the init routine but slightly jerky in normal operation (“sounds” like a stepper motor) like the previous motor plus B-G431B-ESC1, so I assume it is related to some parameter or due to the FOC algorithm.
In any case, even though I haven’t fine tuned the PID’s both speed and position control works.
At the moment the main problem is that, using the commander, the motor in speed control reaches maximum 80 rad/s, which is very strange. Does anyone have any advice for me?
The MCU should be set with all the peripherals set to the maximum clock speed, I don’t think it’s a problem of the code execution, but tomorrow for sure I will check the speed of the void loop()…
I tried initializing the current sensing on the three phases as well, but at the moment although currentSense.driverAlign() seems to work fine, the current control doesn’t work. I’ll fix it after have a good ctr performances with the voltage mode.
Just to mention the application, the idea is to use this driver with SimpleFOC to implement a joint control of a lower limb exoskeleton (open-source for research purposes)
Thank you for the help!
#include <Arduino.h>
#include <board_vesc_6.h>
#include <SimpleFOC.h>
const int motorPolePairs = 7;
BLDCMotor motor = BLDCMotor(motorPolePairs);
BLDCDriver6PWM driver(H1, L1, H2, L2, H3, L3, EN_GATE);
//InlineCurrentSense currentSense = InlineCurrentSense(0.0005, 20, CURRENT_1, CURRENT_2, CURRENT_3);
// encoder instance
HallSensor sensor = HallSensor(HALL_1, HALL_2, HALL_3, motorPolePairs);
// Interrupt routine intialisation
// channel A and B callbacks
void doA() {sensor.handleA();}
void doB() {sensor.handleB();}
void doC() {sensor.handleC();}
float target = 0; // angle set point variable
Commander command = Commander(Serial); // instantiate the commander
void onMotor(char* cmd) {
command.motor(&motor, cmd);
}
void doTarget(char* cmd) {
command.scalar(&target, cmd);
}
void setup() {
sensor.init(); // initialize sensor hardware
sensor.enableInterrupts(doA, doB, doC);
driver.voltage_power_supply = 24; // power supply voltage [V]
driver.init();
motor.phase_resistance = 0.053; // [Ohm]
//motor.voltage_limit = 0.5; // [V] - if phase
motor.current_limit = 65; // [Amps] - if phase resistance defined
motor.velocity_limit = 200; // [rad/s] 5 rad/s cca 50rpm
// link the motor to the sensor
motor.linkSensor(&sensor);
// link the motor and the driver
motor.linkDriver(&driver);
// aligning voltage [V]
motor.voltage_sensor_align = 1.5;
// index search velocity [rad/s]
motor.velocity_index_search = 10;
//currentSense.init(); // current sensing
//currentSense.driverAlign(&driver, motor.voltage_sensor_align);
//currentSense.skip_align = true;
//motor.linkCurrentSense(¤tSense);
// set motion control loop to be used
motor.controller = MotionControlType::velocity;
//motor.torque_controller = TorqueControlType::foc_current;
//motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// contoller configuration
// default parameters in defaults.h
// motor.PID_current_q.P = 0.3f;
// motor.PID_current_q.I = 1;
// motor.PID_current_q.D = 0;
// motor.PID_current_q.output_ramp = 100;
// motor.LPF_current_q.Tf = 0.005f;
// motor.PID_current_d.P = 0.3f;
// motor.PID_current_d.I = 1;
// motor.PID_current_d.D = 0;
// motor.PID_current_d.output_ramp = 100;
// motor.LPF_current_d.Tf = 0.1f;
motor.PID_velocity.P = 0.2;
motor.PID_velocity.I = 1;
motor.PID_velocity.D = 0;
motor.PID_velocity.output_ramp = 1000;
motor.LPF_velocity.Tf = 0.01f;
// angle P controller
// motor.P_angle.P = 5;
// motor.P_angle.I = 1;
// maximal velocity of the position control
// motor.velocity_limit = 50;
// use monitoring with serial
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);
motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE; // default _MON_TARGET | _MON_VOLT_Q | _MON_VEL | _MON_ANGLE
motor.monitor_downsample = 10000;
motor.motion_downsample = 10;
// initialize motor
Serial.println(F("Motor init."));
motor.init();
// align encoder and start FOC
// Serial.println(F("Motor align."));
//motor.initFOC(3.14, Direction::CW);
motor.initFOC();
Serial.println(F("Init FOC"));
// add target command T
command.add('M', onMotor, "my motor");
command.add('T', doTarget, "target");
Serial.println(F("Motor ready."));
_delay(1000);
}
void loop() {
motor.loopFOC();
motor.move(target);
command.run();
motor.monitor();
}
Here the VESC 6 hardware configuration file
#include <Arduino.h>
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
// PORT #1: CAN
// =============
#define CAN_RX PB8
#define CAN_TX PB9
// PORT #2: HALL, ENCODER, I2C1 or USART6
// ======================================
#define HALL_1 PC6
#define HALL_2 PC7
#define HALL_3 PC8
// OR
#define ENC_A PC6
#define ENC_B PC7
#define ENC_I PC8
// OR
#define USART6_TX PC6
#define USART6_RX PC7
// AND
#define TEMP_MOTOR PC4
// PORT #3: USART3, I2C2 or SPI1
// =============================
#define USART3_TX PB10
#define USART3_RX PB11
// OR
#define I2C2_SCL PB10
#define I2C2_SDA PB11
// OR
#define SPI1_NSS PA4
#define SPI1_SCLK PA5
#define SPI1_MISO PA6
#define SPI1_MOSI PA7
// PORT #4: SWD
// ============
#define SWDIO PA13
#define SWCLK PA14
// PORT #5: SERVO
// ==============
#define SERVO PB6
// PORT #6: USB
// ============
#define USB_DM PA11
#define USB_DP PA12
// #7: INTERNAL PINS
// =================
#define VOLTAGE_1 PA0
#define VOLTAGE_2 PA1
#define VOLTAGE_3 PA2
#define ADC_TEMP PA3
#define H1 PA8
#define H2 PA9
#define H3 PA10
#define CURRENT_1 PC0
#define CURRENT_2 PC1
#define CURRENT_3 PC1
#define L1 PB13
#define L2 PB14
#define L3 PB15
#define AN_IN PC3
#define LED_GREEN PB0
#define LED_RED PB1
#define EN_GATE PB5
#define FAULT PB7
const PinMap PinMap_PWM[] = {
// {PA_0, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
{PA_0, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1
// {PA_1, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2
{PA_1, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2
// {PA_2, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3
{PA_2, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3
// {PA_2, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1
// {PA_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4
{PA_3, TIM5, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4
// {PA_3, TIM9, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2
{PA_5, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
// {PA_5, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N
// {PA_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
{PA_6, TIM13, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1
// {PA_7, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N
// {PA_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
// {PA_7, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N
{PA_7, TIM14, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1
{PA_8, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1
{PA_9, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2
{PA_10, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3
{PA_11, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4
{PA_15, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
// {PB_0, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N
// {PB_0, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3
{PB_0, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N
// {PB_1, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N
// {PB_1, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4
{PB_1, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N
{PB_3, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2
{PB_4, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
{PB_5, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
{PB_6, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1
{PB_7, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2
{PB_8, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3
// {PB_8, TIM10, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM10, 1, 0)}, // TIM10_CH1
{PB_9, TIM4, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4
// {PB_9, TIM11, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM11, 1, 0)}, // TIM11_CH1
// {PB_10, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3
// {PB_11, TIM2, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4
{PB_13, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N
{PB_14, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N
// {PB_14, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N
// {PB_14, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 1, 0)}, // TIM12_CH1
{PB_15, TIM1, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N
// {PB_15, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N
// {PB_15, TIM12, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 2, 0)}, // TIM12_CH2
{PC_6, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
// {PC_6, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 0)}, // TIM8_CH1
// {PC_7, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
{PC_7, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 0)}, // TIM8_CH2
{PC_8, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3
// {PC_8, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 0)}, // TIM8_CH3
// {PC_9, TIM3, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4
{PC_9, TIM8, STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 4, 0)}, // TIM8_CH4
{NC, NP, 0}
};