Is Simple FOC an alternative to BGMC2 from RoverTec

Hi together,
I have good news. Last thursday I soldered a 5V step up to 12V module between my powerbank and the control board and it works. At the beginning the control with the onboard potentiometer was very rough and I integrated a parameter “i” in the code at the weekend and set it first to 100 and then to 200. In the last command, the range of the onboard potentiometer is then greatly reduced, more or less calculated by this 200. I can now use the potentiometer much better to control the speed and feel that I am using the entire rotation of the potentiometer to set between 0 and 100rmp (I didnt count the rpms).
Here is the code for this:

so far so good, I still have 3 questions:

-1- The motor and the control card get very warm, around 50-60 °C I guess, and this causes a lot of power to be lost from the battery. Is it possible to reduce the power of the motor or is there another way of preventing heat build-up? I was thinking of changing the PID values, but I don’t know if this works with this board/combination:

// Set the PID values for the controll loop
motor.PID_velocity.P = 1.0;
motor.PID_velocity.I = 10;
motor.PID_velocity.D = 0.0001;
motor.LPF_velocity.Tf = 0.05;

-2- I would like to use a separate poti with an integrated switch for the board. Is it possible to solder an additional poti to the existing onboard poti, i.e. to connect it in parallel, so that the speed can be controlled? I didn’t want to unsolder the existing 10kohm poti first.

-3- What does the command “motor.voltage_limit” do? At 4V the motor starts to make noise

Hey @Thomas , glad to hear it is working better!!

It is because you’re using open-loop mode, this is very inefficient. By integrating a position sensor in the system and using closed loop control, the energy effiency will dramatically increase under light loads. If the motor is lightly loaded, your current consumption in closed loop can drop to a few hundred mA, and this will be a level where nothing gets hot any more.
In open-loop, the best you can do is reduce the voltage to the minimum needed, and this will represent the minimum energy consumption you can achieve in this mode under a given load.

  1. In principle, yes. You can set the first poti to its max resistance, the second one will form a parallel resistor to the first one. You can use basic Kirchoff’s laws to work out the effective resistance of the two parallel resistors, and adjust your ADC conversion values accordingly.

  2. motor.voltage_limit limits the Q axis voltage (see “theory corner” in our docs). It is a bit different from the driver.voltage_limit, which is an absolute limit on the voltage output by the driver.

Do you mean the voltage of the “driver.voltage_power_supply = 12V” in the code lets say to 5V or less depends on the motor load or do you mean the powerbank voltage of the step up board from 5V to a minimum of 9V, because the board starts to working with 8V?
Or do you mean reduce the “motor.voltage_limit =3V” to lets say 2V or 1V.

The PID values dont change anything?

Hi Thomas,

I just mean using the minimum voltages you can - so probably around 8V or 9V PSU voltage, or your driver will not work.
And then you can use driver.voltage_limit and motor.voltage_limit to further lower the effectively used voltage, although of course if you lower it too much the motor will stop to turn (or not turn well).
So within these constraints, by making the voltage as low as you can, you minimise the energy used by the system, and hence the heat.

The PIDs are used for closed loop modes.

Ok thank you verry much :slight_smile: I will test it and if all else fails, I will try an encoder but it depends on how many hours I can run it with a powerbank.

Hi runger,
I have set now “motor.voltage_limit = 1,2V” and the “driver.voltage_power_supply = 9V” and it seems to be better with the heat of the board and the motor.
Now I’ll see how long the 5,000mAh battery lasts.
There is a button on the B-G431B-ESC1 board. Could I use it to change the direction of rotation of the motor? What could be the code for this?

Yes. The button is connected to PC10. The potentiometer is connected to PB12. Read PC10 as digital IO and PB12 as analog IO.

Is it a push-button or a toggle-button?

This is a push button

SW1
SWITCH TACTILE SPST-NO 0.05A 32V switch_SMT_4_2x2_8mm
C&K
KMR211GLFS

Ok, it’s NO (normally open), so when pressed it will read 1, when not pressed 0.

You can read it with
int buttonState = digitialRead(PC10);

Thing is, your main loop will (and needs to) execute at 1000s of iterations per second, so when you press the button, buttonState will be ‘1’ for many iterations. How to know when to change the direction?

I would handle this by implementing a timer variable, and not permit the change to happen too often. Something like this:

int lastState = 0;              // last button state
long timestamp = millis();     // timestamp
int direction = 1;              // 1 or -1

void loop() {

  long deltaT = millis() - lastState;
  if (deltaT>=500) {
    int buttonState = digitalRead(PC10);
    timestamp = millis();
    if (buttonState!=lastState) {
      lastState = buttonState;
      if (buttonState==1)
        direction = direction * -1;
    }
  }

  // ...
}

I have now tested the battery and with 5,000mAh the bruhless motor runs about 15 hours. That is too little for me. It boils down to the fact that I need an encoder. So it looks, open loop needs a lot of power at slow speeds. I read on the forum that it’s the other way around with closed loop. Now I have looked around for very cheap encoders or is there something more favorable here?

On one side of the encoder you have 5V, GND and a pwm connection, can I use that for the closed loop? On the other side there are more connections but they are so small that I’m afraid I won’t get it soldered.

I have found another similar with a white board. However, this has only a 3.3V input but the B-G431B-ESC1 supplies 5V.

@runger thanks for the code. I will try that out :slight_smile:

does it have to be a magnet that is diametrically magnetized?

Those are very cheap offers. But the AS5600 is not a great sensor to begin with, and these ones might be clones of some kind at that price. Mouser sells the sensor chips for EUR1.50 or so, if you buy 5000 pieces. LCSC has it as low as $1.20 for 1000+ units. But that’s without the PCB, other components, headers, etc…

AS5600 is I2C - which is really too slow for doing effective motor control. It will limit your loop speed to about 1kHz or so. If you only need to turn the motor slowly, it could be enough.

In theory, we have a PWM Sensor. In practice, this signal is 1kHz frequency, so again it will limit your loop speed by a lot, even more than the I2C. I’d really advise against it, the performance won’t be good.

Here you’re actually limited a bit by the choice of driver… it has inputs for Hall sensors, so if you can find a motor with halls then you can use those directly. Otherwise, you have to find some pins to connect a sensor to, and IIRC, SPI isn’t possible. So then that leaves I2C and PWM anyway, or Analog, or an encoder (ABI type interface) which can work on any IO pins that support interrupts (which I think is pretty much all of them on STM32).

I’ve actually just made a new sensor board - this one would support SSI, ABI, Analog and I2C all in one :slight_smile: of course that’s only if it works :rofl: it should arrive here end of next week, and if it works I could send you one…

Yes, this is very important. If it is not diametrical, it won’t work. Or it will appear to work when you turn it by hand, but immediately fail at faster speeds. It will be super-confusing and cause you much pain if you don’t have a good magnet.

These offers are so cheap, it is hard to believe… I’d be suspicious. But at that price, it also can’t hurt to try them out. :rofl: But be sure to test the magnet carefully, if buying from AliExpress or eBay. There’s a real chance that its the wrong kind of magnet, based on other user’s experiences.

I’d like to try the AS5600 since it’s so cheap and I won’t be driving more than 100rpm with the motor. If that doesn’t work, I’ll have to see what I do, the next better ones are already more expensive.
@runger: thanks for your offer, but I would like to build a few more turntables later though if that works then :slight_smile: the costs are very important to me here
I have now integrated the code for the button in my program and had to add a code line that the input from the button is recognized. Unfortunately, the rotation reversal has not yet worked but I’m sticking to it. When pressing the button, a “hello” is shown here, when releasing it seems to come into the loop again.


EDIT: the “buttonPin” is still defined with the PC10 above. This is not visible in the picture.

1 Like

You have to use the ‘direction’ variable somehow, maybe like this:
motor.move(analogRead(POTENTIOMETER)/i * direction)

The code always goes back to the loop, but there are two checks to make the button work well:

  • firstly, we only do the direction change if the button is in a different state since the last time we checked. So you have to press and release the button before you can press it again. Just keeping the button held down won’t cause many direction changes
  • and secondly, we do at most 2 checks on the button per second (by comparing our timestamp to 500ms) so even if there is some electrical noise the button won’t go crazy (this is called “debouncing”)

Changing the direction of rotation works just as you described. Thank you runger :slight_smile: I still had to define the value “i” as float. If it is defined as int, the motor hums when the button is pressed. I have also now received the diametral magnets with a diameter of 5mm and a height of 2mm. this fits exactly into the bore of the bruchless motor and I have now also received the encoder from the picture above. the next few days I will try to get the encoder reasonably under the motor.

Hello all,
I tried yesterday to get the closed loop to run. The code ran through without error message in arduino and sent it to the board. After a few seconds the motor turns left and right briefly and gives an error message that there is no response from the sensor running with PWM. I soldered the PWM signal from the sensor to the A+/H1 pin of the board.
Is the line in the code correct for this? Or do I still need a definition that PB6 works as input?

// Magnetic sensor instance
MagneticSensorPWM sensor = MagneticSensorPWM(PB6, 4, 904);

Is it possible to find out with an example code if the sensor works/is soldered correctly if I turn the motor manually with the magnet and display the result from the sensor?

#include <SimpleFOC.h>

// motor instance, number of pole pairs, not poles
BLDCMotor motor = BLDCMotor(7);

// driver instance, must use 6PWM FOR B-G431 driver
BLDCDriver6PWM driver = BLDCDriver6PWM(PHASE_UH, PHASE_UL, PHASE_VH, PHASE_VL, PHASE_WH, PHASE_WL); 

// Magnetic sensor instance
MagneticSensorPWM sensor = MagneticSensorPWM(PB6, 4, 904);

// buttom config
const int buttonPin = PC10;
int lastState = 0;               // last button state
long timestamp = millis();       // timestamp
int direction = 1;               // 1 or -1

// gear
float i = 200;


void setup() {

  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
 
  // initialize magnetic sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);
  
  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 9;
  driver.init();
  motor.linkDriver(&driver);

  // set motion control loop to be used
  motor.controller = MotionControlType::velocity;

  // controller configuration based on the control type 
  // velocity PID controller parameters
  // default P=0.5 I = 10 D =0
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;
  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;

  // maximal voltage to be set to the motor
  motor.voltage_limit = 6;

  // 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;

  // since the phase resistance is provided we set the current limit not voltage
  // default 0.2
  motor.current_limit = 1; // Amps

  // use monitoring with serial 
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialize motor
  motor.init();
  // align sensor and start FOC
  motor.initFOC();

  Serial.println("Motor ready.");

//  Serial.println("Sensor ready.");
 
  _delay(1000);
}

void loop() {
  // main FOC algorithm function
  motor.loopFOC();

  // Motion control function
  motor.move(analogRead(POTENTIOMETER)/i*direction);

  // buttom change direction
  long deltaT = millis() - lastState;
  if (deltaT>=500) {
    int buttonState = digitalRead(buttonPin);
    timestamp = millis();
    if (buttonState!=lastState) {
      lastState = buttonState;
      if (buttonState==1)
        direction = direction * -1;
    }
  }
}

Unbenannt

According to the data sheet, A+ pin is PB6, so this line looks ok. You’re using the AS5600 in PWM mode?

No, this is done in the sensor initialization…

I think this is the example you’re looking for:

Adapt to your pins, of course.

Looks like you’re missing the doPWM() function in your code to use the sensor in interrupt mode, but that isn’t strictly needed (though probably better).

Hi runger,
yes, I want to use the sensor in PWM mode first because I can solder it better.
I have used your posted code and it seems, that the sensor get some information from the magnet. In the monitor I can see that, if I turn the motor faster, the left numbers are getting smaller. The slower I turn the motor, the higher are the numbers. But I can’t do much with it. Something is still wrong. I have also used a bigger diametrical magnet and the result is the same.


Unbenann2t

Hi Runger,
do you have any idea, what could be wrong or should I try to control the encoder with I2C?
BR Thomas

Hi @Thomas,

To be honest, it is hard to say what is wrong.

For PWM, you have to be sure the circuit is reliable and not subject to interference/noise. Once you have a clean signal, it should work, but since the sensor PWM freq is only 1kHz, this will limit your performance quite a lot.

For I2C, the communication can be simpler to set up reliably, withe the right pull-up resistors it usually works well. But also with I2C you won’t break any speed records… but if you’re controlling a gimbal type motor, and don’t need high performance, it can work quite well.

The left-hand numbers should be the absolute angle, in radians. So these numbers seem a little high unless you were running the motor a litte while? The right-hand numbers should be the velocity. When moving the motor by hand, it is normal to show 0 or near 0 most of the time.