High current at high speed and vibrations at low speed

Hello everyone,

I want to drive a cubemars GL40 Kv 70: GL40 - GL Series Outrunner Gimbal Motor - Gimbal System - Application - CubeMars.
This motor has a nominal voltage of 16V, no load speed around 106 rad/s and no load torque arround 0.3A I don’t intend to use it over 2 amps and has internal phase resistance of 4.5 ohm. It has an encoder AS5048A (magnetic SPI single turn). It has 14 pairs of poles.

I am not sure of the kind of control I am looking for, so I searched for drivers that can do current control as well.
I purchased the simple FOC mini as the regular was not available at the time. I use this library on an Arduino Uno rev3.

I use a potentiometer to regulate the speed (open or closed loop) ( calling motor.move(targetVelocity) ). I set min value to 0 and max to no load speed (106 rad/s). Driver limit is 16V.
In open loop, I have a motor that behave correctly with at low speed (< 5 tr/s) with the motor.current limit set to 0.5A. If I set it to 2A it starts vibrating a lot.
Is this indicating a specific problem ?

In closed loop, I don’t have the 0.5->2A different behavior.
I had to reduce the gains quite a bit (P = 0.01, I = 0.1) in order to get a smooth low speed behavior. Otherwise, It was just vibrating terribly. I expected the gains to be closer to the regular ones, but as it is project specific, its ok.

At “high speed” (target around 50rad/s), It is not working as intended.
High current (1.6A, even more) are drawn by the system (I can check that from the lab supply). Vibrations occur when it is at high current.

I read from this forum that the cause might be the computation time of the controller. I ran tests and got the following results (got a pin switched every loop call) :
Open loop condition : 350 us
Closed loop condition : 1800 us.
Closed loop with downsampling : 900 us or 1800 us.

The loop frequency is around 1 Khz. Match the data I found in the doc.
Do you see any other reason that can explain the current drawn ?
Do you have a board suggestion ?

Don’t worry about the open loop. It’s probably just jumping strongly to cogging positions when you raise the current. Open loop is only used for testing and during calibration.

EDIT: Realized that’s 14 pole pairs, not 14 magnets. Deleted my original advice.

You definitely need a faster CPU. 50rad/s with 14 pole pairs is about 111 electrical revolutions per second, so with 1800us loop time you only get about 5 updates per electrical revolution. 6 is the bare minimum to work, and ideally you want a lot more than that.

ESP32 and STM32 are the most popular. I’m not too familiar with the available boards and their compatibility with SimpleFOCMini, so hopefully someone else can give advice on exactly what to buy.

Hi,
Thanks for your answer. I understand better the link between computationnal freq and max speed of the motor.
I just tried using a nano rp2040 connect. The MCU is supposed to have a 133 Mhz clock so I expected it to be almost 10 times faster.
I was able to communicate with the sensor using a different library than magnetic encoder SPI (cannot with magnetic encoder SPI), drive the PWM of the SIMPLE FOC mini (I tried setting different voltage value for the outputs and it works).

I am able to drive the motor in open loop. The loop takes 60us without the call for motor.loopFOC() and It works similar to the UNO setup. If I add the motor.loopFOC(), it takes 46 MS ! And I am not able to get a smooth behavior.

Compilation time is realy long compared to uno board.
I tried with a version of Arduino : GitHub - earlephilhower/arduino-pico: Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards. I already worked with it and liked the ease of use of the two cores.
I tried with the Arduino Mbed OS :
Not able to get the magnetic SPI Work.
From what I read on this forum, rp2040 might not be the perfect mcu but it shouldn’t be that bad.

Are you using Arduino IDE or PlatformIO? Would you mind sharing your code and configuration so people can understand what’s going on?

I use the RP2040 connect myself and I have good results. Using SPI sensors in closed loop, I get around 5kHz using mbed core, and around 8kHz using earlephilhower core on the main loop iteration speed…

So your 46ms result - there is something wrong there.

Thanks for your reply, here is the code


#include <SimpleFOC.h>

#define PIN_IN_1 D5 //17//D5
#define PIN_IN_2 D6 //18//D6
#define PIN_IN_3 D7 //19//D7
#define PIN_EN D8 //20//D8
#define PIN_GND_1 D9 //21//D9
#define PIN_GND_2 D10 //5//D10
#define PIN_CS  D2 //25//D2

#define PIN_POT_GND A0 //26//A0
#define PIN_POT_SGN A1 //27//A1
#define PIN_POT_5V A2 //28//A2
#define PIN_STATE_TOGGLE D4 //16//D4 

#define PHASE_RESISTANCE 4.5 //Ohm
#define KV 70 //RPM/V
#define PHASE_INDUCTANCE 0.001800//[H]

// BLDC motor & driver instance
// BLDCMotor( pp number , phase resistance, KV rating)
BLDCMotor motor = BLDCMotor(14,PHASE_RESISTANCE , KV,PHASE_INDUCTANCE);
//BLDCMotor motor = BLDCMotor(14);
BLDCDriver3PWM driver = BLDCDriver3PWM(PIN_IN_1, PIN_IN_2, PIN_IN_3, PIN_EN);
// Magnetic sensor instance
MagneticSensorSPI AS5x4x = MagneticSensorSPI(AS5048_SPI, PIN_CS);
// instantiate the commander
//Commander command = Commander(Serial);
unsigned int potV = 0;
unsigned int POT_MIN = 0;
unsigned int POT_MAX = 1024;
float SPEED_MIN = 0; //Rad/s
float SPEED_MAX = 106; //rad/s
float POS_MIN = 0;
float POS_MAX = 6.28;
float mappedV = 0;

unsigned long currentTime = 0;
unsigned long previousMillis = 0;  // will store last time LED was updated
unsigned long timeDifferenceMS = 0;
unsigned long DISPLAY_TIMER_MS = 2000;
int ledState = LOW;  // ledState used to set the LED
bool stateToggle = LOW;

float mapFloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void setup() {

  pinMode(PIN_GND_1, OUTPUT);
  pinMode(PIN_GND_2, OUTPUT);
  pinMode(PIN_POT_GND,OUTPUT);
  pinMode(PIN_POT_5V,OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(PIN_STATE_TOGGLE,OUTPUT);
  
  digitalWrite(PIN_GND_1, LOW);
  digitalWrite(PIN_GND_2, LOW);
  digitalWrite(PIN_POT_GND, LOW);
  digitalWrite(PIN_POT_5V, HIGH);
  digitalWrite(LED_BUILTIN, HIGH);
  digitalWrite(PIN_STATE_TOGGLE,stateToggle);

  Serial.begin(9600);
  while (!Serial);
  
  Serial.println("Start of setup");
  //Serial.println("Arduino MbedOS");
  Serial.println("Arduino-pico");
  digitalWrite(LED_BUILTIN, LOW);
  // initialize magnetic sensor hardware
  AS5x4x.init();
  // link the motor to the sensor
  motor.linkSensor(&AS5x4x);
  Serial.println("sensor done");
  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 16;
  driver.init();
  // link the motor and the driver
  motor.linkDriver(&driver);
  Serial.println("driver done");
  
  // set motion control loop to be used
  // open loop control config
  //motor.controller = MotionControlType::velocity_openloop;
  motor.controller = MotionControlType::velocity;
  //motor.controller = MotionControlType::angle;
  
  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SinePWM; //(default)
  //motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  //motor.foc_modulation = FOCModulationType::Trapezoid_120;
  //motor.foc_modulation = FOCModulationType::Trapezoid_150;

  // velocity PID controller parameters
  // default P=0.5 I = 10 D =0
  motor.PID_velocity.P = 0.01;// 0.01//0.5;
  motor.PID_velocity.I = 0.1;//1 //10;
  motor.PID_velocity.D = 0;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 1000;
  //In case of ANGLE controller
  // angle P controller
  motor.P_angle.P = 20;
  //  maximal velocity of the position control
  motor.velocity_limit = 106;//6.28;
  // velocity low pass filtering
  // default 5ms - try different values to see what is the best.
  // the lower the less filtered
  motor.LPF_velocity.Tf = 0.01;
  // downsampling value
  motor.motion_downsample = 0; // - times (default 0 - disabled)
  // init motor hardware
  // limiting motor current (provided resistance)
  motor.current_limit = 0.5; //2 // [Amps]
  //motor.voltage_limit = motor.current_limit*PHASE_RESISTANCE;
  //driver.enable();
  motor.init();
  Serial.println("motor init done");
  motor.initFOC();
  Serial.println("motorInitFOC done");
  
  Serial.println("End of setup");
  //digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
}

void loop() {  
  stateToggle = !stateToggle;
  digitalWrite(PIN_STATE_TOGGLE,stateToggle);
  motor.loopFOC();
  potV = analogRead(PIN_POT_SGN);
  potV = (potV < 10)?0:potV;
  if(motor.controller == MotionControlType::angle){
    mappedV = mapFloat(potV,POT_MIN,POT_MAX,POS_MIN,POS_MAX);
  }
  else{
    mappedV = mapFloat(potV,POT_MIN,POT_MAX,SPEED_MIN,SPEED_MAX);
  }
  //Serial.println(mappedV);
  motor.move(mappedV); 
  //driver.setPwm(8, 4, 2);
}

It is the same as the one I was running on the Arduino Uno, except for some pins.

As I said, I am not able to communicate with the encoder using the MagneticSensorSPI class, even though I am able to do this using code :
AS5048A Arduino library

I use Arduino IDE 2.3.3, earlephilhower arduino pico 3.1.1, simple FOC 2.3.4 .
Target is a Arduino nano rp2040 connect.
As you can see every loop function call toggles a pin, that I monitor from an oscilloscope.

I will try later on an raspberry pi pico.
I also ordered different mcu, will try on a teensy 4.0.

How long does the analog read take? If you remove the analogRead and just use a fixed target value, how does it look for the loop speed?

I see you have commented out the println, but if you print once per loop it’s much too often, you have to limit the amount of serial output to make sure you don’t cause blocking IO.

The prints are not used as they slow too much the loop.
The analogRead() + maptofloat() takes around 10 us.
The analogRead() + motor.move() takes around 28 us.
The analogRead() + motor.move() + motor.loopFOC() takes around 47-48 ms.

edit : I ran the same sketch on a second nano rp2040, and on a raspberry pi pico (changed pins).
Got the same values.
What is the arduino-pico version you use and the simple foc version ?