Hoverboard main board with simpleFOC

I want to post another working example for the splitboard controller with the STM32F030 MCU.
The main parameters are 24V@50kHz, velocity mode with voltage-torque control.
This time I took the motor parameters from @OiD-W
I found that the PID values have a very small work-zone. A bit off and the motor runs crazy.
That’s why I added the accel2target ramp up in the main loop. It allows you to watch the motor going through the paces. Enough time to pull the plug when it gets funny

/* 
  10" hoverboard splitboard with STM32F030C8T6 MCU and hall sensors
*/
#include <SimpleFOC.h>      //  has to be dev-branch for both libs
#include <SimpleFOCDrivers.h>
#include <encoders/smoothing/SmoothingSensor.h>

// Hall sensor instance
//  - hallA, hallB, hallC    - HallSensor A, B and C pins
//  - pp                     - pole pairs
HallSensor sensor = HallSensor(PA0, PF1, PC15, 15); //  blue, green, yellow, 15PP

// Interrupt routine intialisation
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}


BLDCMotor motor = BLDCMotor(15, 0.75, 19.0, 0.00119);  // 0.00036858); 0.75, 19, 0.00119
// BLDCDriver6PWM driver = BLDCDriver6PWM(UH, UL, VH, VL, WH, WL);
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8,PB13,PA9,PB14,PA10,PB15);  //  blue, green, yellow gate driver pins

// instantiate the smoothing sensor, providing the real sensor as a constructor argument
SmoothingSensor smooth = SmoothingSensor(sensor, motor);

// instantiate the commander
float target_velocity = 0;
float accel2target = 0;
bool LED = true;
void SerialComm()
{
  switch(Serial2.read())
  {
  case '?':
    Serial2.print("sensor_direction ");
    Serial2.print(motor.sensor_direction);
    Serial2.print(", zero_electric_angle ");
    Serial2.println(motor.zero_electric_angle);
    break;
  case 's': Serial2.print("shaft_velocity "); Serial2.println(motor.shaft_velocity); break;
  case 'a':
    Serial2.print("shaft_angle ");
    Serial2.print(motor.shaft_angle);
    Serial2.print(", electric_rotations ");
    Serial2.print(sensor.electric_rotations);
    Serial2.print(", electric_sector ");
    Serial2.println(sensor.electric_sector);
    break;

  case 'T': target_velocity = Serial2.parseFloat(); Serial2.print("Set ");
  case 't': Serial2.print("target "); Serial2.println(target_velocity);  break;

  case 'V': motor.voltage_limit = Serial2.parseFloat(); Serial2.print("Set ");
  case 'v': Serial2.print("motor.voltage_limit "); Serial2.println(motor.voltage_limit); break;
  
  case 'O': motor.PID_velocity.output_ramp = Serial2.parseFloat(); Serial2.print("Set ");
  case 'o': Serial2.print("motor.PID_velocity.output_ramp "); Serial2.println(motor.PID_velocity.output_ramp); break;
  
  case 'F': motor.LPF_velocity.Tf = Serial2.parseFloat(); Serial2.print("Set ");
  case 'f': Serial2.print("motor.LPF_velocity.Tf "); Serial2.println(motor.LPF_velocity.Tf); break;
  case 'P': motor.PID_velocity.P = Serial2.parseFloat(); Serial2.print("Set ");
  case 'p': Serial2.print("motor.PID_velocity.P "); Serial2.println(motor.PID_velocity.P); break;
  case 'I': motor.PID_velocity.I = Serial2.parseFloat(); Serial2.print("Set ");
  case 'i': Serial2.print("motor.PID_velocity.I "); Serial2.println(motor.PID_velocity.I); break;
  case 'D': motor.PID_velocity.D = Serial2.parseFloat(); Serial2.print("Set ");
  case 'd': Serial2.print("motor.PID_velocity.D "); Serial2.println(motor.PID_velocity.D); break;

  case 'W': motor.P_angle.P = Serial2.parseFloat(); Serial2.print("Set ");
  case 'w': Serial2.print("motor.P_angle.P "); Serial2.println(motor.P_angle.P); break;

// motor.zero_electric_angle
  case 'Z': motor.zero_electric_angle = Serial2.parseFloat(); Serial2.print("Set ");
  case 'z': Serial2.print("motor.zero_electric_angle "); Serial2.println(motor.zero_electric_angle); break; 
  
  case ' ': target_velocity = 0; motor.voltage_limit = 0;
  }
}

void setup() {
  pinMode(PB9,OUTPUT);  //  onboard LED for heartbeat signal

// monitoring port
  Serial2.begin(115200);
  while(!Serial2){};
 
  digitalWrite(PB9,LED);

  // initialise encoder hardware
  sensor.init();
  // hardware interrupt enable
  sensor.enableInterrupts(doA, doB, doC);

  // set SmoothingSensor phase correction for hall sensors
  //smooth.phase_correction = -_PI_6;
  motor.linkSensor(&smooth); // link the motor to the smoothing sensor
 
  // driver config
  // power supply voltage [V]
  driver.pwm_frequency = 50000;
  driver.voltage_power_supply =24;
  driver.voltage_limit = 24;
  driver.dead_zone = 0.1f;  // default 0.05f
  driver.init();
  // link the motor and the driver
  motor.linkDriver(&driver);

  // aligning voltage [V]
  motor.voltage_sensor_align = 6;
    
// set motion control loop to be used
  motor.torque_controller     = TorqueControlType::voltage;
  // motor.foc_modulation = FOCModulationType::Trapezoid_120;
  motor.foc_modulation        = FOCModulationType::SinePWM; 
  // motor.controller     = MotionControlType::torque;    // set motion control loop to be used
  motor.controller     = MotionControlType::velocity;
  
  
  // controller configuration 
  // default parameters in defaults.h
 
  // velocity low pass filtering time constant
  motor.PID_velocity.P  = 0.3f;
  motor.PID_velocity.I  = 0.3f;
  motor.LPF_velocity.Tf = 0.04f;  //  0.05

  // default voltage_power_supply
  motor.voltage_limit = 0.5f * driver.voltage_limit;
  motor.current_limit = 10;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 1000;

  // comment out if not needed
 motor.useMonitoring(Serial2);

  // initialize motor
  motor.init();
  // align sensor and start FOC
  motor.zero_electric_angle  = 0.00f; // rad
  motor.sensor_direction = Direction::CCW; // CW or CCW
  motor.initFOC();

  _delay(1000);
  
 }

void loop() {
  digitalWrite(PB9,LED);
  if (LED == true){
	  LED = false;}
	else {LED = true;}
  
  motor.loopFOC();  
  //motor.monitor();  
  motor.move(accel2target);
  // user communication
  if(Serial2.available() > 0){
    SerialComm();
  };
  if (target_velocity != accel2target){
    if (target_velocity < accel2target) {accel2target -= 0.01f;}
    else {accel2target += 0.01f;}
  }
  //Serial2.println(motor.shaft_velocity);
}

1 Like