How to find BLDC motor settings

Hi all. I’m new.
I’m trying to connect the Maxon motor to the SimpleShield.
I need the motor to smoothly accelerate to 3500 rpm, but at a speed of more than 1500 rpm, the motor stops rotating and starts to vibrate.
I wanted to connect to the WebController to find the appropriate PID settings, but when connecting, it stops at “Waiting for connection…”)
I use ArduinoMega2560 and SimpleFOCShield V2.0.4
Maxon BLDC motor 8 pairs, Max speed-4390rpm 12V 2A. This motor with Maxon driver works well.

Tell me which direction should I go?
To increase the speed should I change the PID or something else?
Why can’t I connect to the Web Controller?
Are there any tips?

 #include <SimpleFOC.h>
 BLDCMotor motor = BLDCMotor(8, 1.16, 50);
 BLDCDriver3PWM driver = BLDCDriver3PWM(5, 9, 6, 8); 
 float target_velocity = 0;
 Commander command = Commander(Serial);
 void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }
 void doLimit(char* cmd) { command.scalar(&motor.voltage_limit, cmd); }
void doMotor(char* cmd) { command.motor(&motor, cmd); }
 
 void setup() {
  driver.voltage_power_supply = 12;
  driver.voltage_limit = 6;
  driver.init();
  motor.linkDriver(&driver);
  motor.velocity_limit = 450;
  motor.voltage_limit = 12;
  motor.current_limit = 1;
  motor.controller = MotionControlType::velocity_openloop;
  motor.foc_modulation = FOCModulationType::SinePWM;
  motor.PID_velocity.P = 0;
  motor.PID_velocity.I = 0;
  motor.PID_velocity.D = 0;
  motor.PID_velocity.output_ramp = 1;
  motor.LPF_velocity.Tf = 0;
  motor.init();
   command.add('T', doTarget, "target velocity");
   command.add('L', doLimit, "voltage limit");
   Serial.begin(115200);
   Serial.println("Motor ready!");
   Serial.println("Set target velocity [rad/s]");
   _delay(1000);
 
   char motor_id = 'M';
   command.add(motor_id,doMotor,'motor');
   motor.useMonitoring(Serial);
   motor.monitor_start_char = motor_id;
   motor.monitor_end_char = motor_id;
 }
 void loop() {
   motor.monitor();
   motor.move(target_velocity);
   command.run();
 }

Hi @Sladek

If I am not wrong you are missing the following lines in your code in order to make it work with Web Controller

// configuring the monitoring to be well parsed by the webcontroller
   motor.monitor_start_char = motor_id; // the same latter as the motor id in the commander 
   motor.monitor_end_char = motor_id; // the same latter as the motor id in the commander 
   commander.verbose = VerboseMode::machine_readable; // can be set using the webcontroller - optional

Welcome to the community :). I wish I could help more directly as JorgeMaker does, however I can only say that I had similar issues and I think that using the debug tools of Atmel Studio through the SWD port etc. appears to be critical. There are a great many things to go wrong and the main thing that always gave me results was to have a look in there and watch everything as it moved and operated, the issue would often quickly become apparent, although there always seemed to be something waiting for me around the corner, if you are undertaking things that are worth doing, know that you can do it if you persist :slight_smile:

Using print statements arduino style was too slow and added complications which would themselves cause failures sometimes. The SWD thing accesses the memory of the controller with less complications, I gather?

Welcome to SimpleFOC :slight_smile:

Not sure, but you may have hit the limit of the Arduino Mega. It’s not the fastest MCU. How many pole pairs does your motor have?

[Edit]

8PP and 1500RPM would be 12000 electrical revolutions per minute, or about 200 e-rev/s. Each e-rev will need several “samples” (at least 6) output to make the sine waves driving the motor. Each iteration through the main loop calls move() and outputs one new level to the PWM. So 200 e-rev means you need a main loop iteration speed of at least 1200 iterations/s, probably more. If you drop below this iteration rate, the values output will no longer approximate the sine wave sufficiently smoothly for the motor to follow it.

Another limit of course can be the motor itself - what is its KV value? Is it really 50KV? Because then you would not expect to hit such high speeds at 12V?

The uno got 1khz update rate when I tried it in open loop. I think the mega is about the same speed.

It always bothers me when they say x voltage and y amps for a motor, unless it has integrated electronics, those figures are not really what you care about. Resistance, power dissipation capability etc. those would be more useful. Whatever.

I think it might be kind to put a little warning somewhere that the uno is rather underpowered for motor control. I also stepped in this like a year ago when I started my explorations and I’m sure others will.

however fortunately it is also easily remedied if you aren’t on a super tight budget though, I suggest a nucleo board, especially the g431 one as the processor I know works ok with arduino and all the pieces of simplefoc I tried it with, at least. It is fast and has the floating point hardware too.

There will still be all these other questions, but it should help…

Thank you.
I have already added these lines.
SimpleFOCWebController still won’t connect, but now I can easily connect using https://simplefoc.besson.co
I can change the parameters there, but I have not yet been able to spin the motor up to sufficient speed.

Thanks for the welcome.
Today I will definitely try Atmel Studio.
I don’t understand yet what it means through the SWD port. At the canopy, SimpleFOCShield is connected to the ArduinoMega2560 board. and it is connected to the computer via USB. I am using Arduino IDE

Motor Features:

VALUES AT NOMINAL VOLTAGE
Nominal voltage							12 V
No load speed	     					4390 rpm
No load current							164 mA
Nominal speed							3050 rpm
Nominal torque (max. continuous torque)	57.1 mNm
Nominal current (max. continuous current)2.16 A
Stall torque            				263 mNm
Stall current							10.3 A
Max. efficiency							77 %
CHARACTERISTICS
Terminal resistance						1.16 Ω
Terminal inductance						0.403 mH
Torque constant							25.5 mNm/A
Speed constant							375 rpm/V
Speed / torque gradient					17.1 rpm/mNm
Mechanical time constant				16.6 ms
Rotor inertia							92.5 gcm²
THERMAL DATA
Thermal resistance housing-ambient		6.57 K/W
Thermal resistance winding-housing		3.92 K/W
MECHANICAL DATA
Bearing type	ball bearings
Max. speed								10000 rpm
Number of pole pairs						8
Number of phases							3

I am confident in its capabilities, because it now works well with the Maxon board. We want to switch to SimpleFOC and Arduino (or another) because we want to connect a few simple sensors and work indication lights.
I use Arduino because the Arduino IDE is easier to use.
I also have a Nucleo STM32F746 and a Nucleo STM32L476, but the STM CubeIDE is much more difficult to use and I will look into it if it is not possible to use Arduino.
As I understand it, I need a board with a higher frequency? Like for example STM32F7 (216MHz)?

Mega has the same processor frequency as UNO, probably the refresh rate is similar.

Unfortunately, I know only part of the electrical characteristics of the motor.

I completely agree with you about UNO.

I have several Nucleo STM32F746 and a Nucleo STM32L476 boards, I also have the X-Nucleo-IHM07M1 driver. And with them, I was able to get the motor to rotate at a sufficient speed, but I need to control the position, rotation speed and current. STM32 with its libraries cannot control these parameters at the same time.

I can use any boards, but I would like to use ArduinoIDE, because it is much simpler than for example STM32CubeIDE

Hi @Sladek,

The KV value for the motor should then be around 375, and not 50 as in the code you posted. So then the problem is almost certainly the speed the Mega can go at. As an 8bit MCU it isn’t so fast.

If you have all this gear, why not use it with SimpleFOC?

The STM32F746 I think will not support current sensing with SimpleFOC at the moment, but it is very powerful, and open-loop mode should work fine. But even the L476 is already many times faster than the Arduino Mega, and on the L476 you can also run current sensing if you need it.

Both these Nucleo boards should work with Arduino IDE or with PlatformIO to program them using Arduino framework.

And you can also use the X-Nucleo-IHM07M1 with SimpleFOC. It is a 3-PWM driver board, there is no reason really it should not work.

1 Like

You can use the nucleo board with arduino :). There are tutorials. You need an adapter called an st-link, cheap knock off devices are like $16, and in my experience worked pretty good although if you are serious i have heard the good ones are worth it, it connects to the swd port on the board, and then to the usb port. Then you tell arduino to send the compiled program to the stm32cube thing, which sends it through the st-link device to load the binary file into the memory of the microcontroller on the board. However as I noted the problem is debugging. In arduino you generally just use print statements. However this is too slow I think, in this context.

The best way is imo to determine maximal heat dissipation capability and deal with that but the motor driver can’t know how much efficiency you are getting easily, until you get to the point of monitoring the angular position of the rotor at least, using a sensor or back emf or current observers or whatever,.

On a second look, it looks like in this case you should get about 6 watts of power that can be safely dissipated by the motor, so if you are driving it open loop and the terminal resistance is 1.16 ohm, then 2.25 amps or so is the max stall current (6 watts divided by 1.16 ohms, the square root of that for current, because VI=P and V=RI so P=I^2*R). However at higher efficiencies you can put more power into the motor because some gets shipped out as mechanical energy, not heat.

Nucleo boards have this built-in…

1 Like

Thanks, I’ll fix KV.

I have already connected the SimpleFOCShield to the Nucleo STM32L476 and the motor. I installed stm32duino and was able to flash Nucleo STM32L476 with ArduinoIDE. Now the motor is spinning at low speed.

But the code that worked with the Arduino board, when trying to flash it in Nucleo, gives an error: “invalid conversion from ‘int’ to ‘char*’ [-fpermissive]”

#include <SimpleFOC.h>
 BLDCMotor motor = BLDCMotor(8, 1.16, 50);
 BLDCDriver3PWM driver = BLDCDriver3PWM(5, 9, 6, 8); 
 float target_velocity = 0;
 Commander command = Commander(Serial);
 void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }
 void doLimit(char* cmd) { command.scalar(&motor.voltage_limit, cmd); }
void doMotor(char* cmd) { command.motor(&motor, cmd); }
 
 void setup() {
  driver.voltage_power_supply = 12;
  driver.voltage_limit = 6;
  driver.init();
  motor.linkDriver(&driver);
  motor.velocity_limit = 450;
  motor.voltage_limit = 12;
  motor.current_limit = 1;
  motor.controller = MotionControlType::velocity_openloop;
  motor.foc_modulation = FOCModulationType::SinePWM;
  motor.PID_velocity.P = 0;
  motor.PID_velocity.I = 0;
  motor.PID_velocity.D = 0;
  motor.PID_velocity.output_ramp = 1;
  motor.LPF_velocity.Tf = 0;
  motor.init();
   command.add('T', doTarget, "target velocity");
   command.add('L', doLimit, "voltage limit");
   Serial.begin(115200);
   Serial.println("Motor ready!");
   Serial.println("Set target velocity [rad/s]");
   _delay(1000);
 
   char motor_id = 'M';
   command.add(motor_id,doMotor,'motor');
   motor.useMonitoring(Serial);
   motor.monitor_start_char = motor_id;
   motor.monitor_end_char = motor_id;
   commander.verbose = VerboseMode::machine_readable;
 }
 void loop() {
   motor.monitor();
   motor.move(target_velocity);
   command.run();
 }

Because on the simplefoc.com, the shield installed on the Arduino is more common. In addition, working with ArduinoIDE and Arduino boards is much easier. :slight_smile:

I already tried, but their software does not allow you to control the position, speed and current at the same time. I think that it is more convenient to use the SimpleFOC program with SimpleFOCShield. In addition, I need about 100 such boards, by purchasing them I will thank the SimpleFOC developers :slight_smile:

Thanks for the tip. I was able to connect the shield to the STM and flash it from the ArduinoIDE.

Yes, this motor can spin fast, I already checked it with the original driver. But it is much more expensive, and does not allow you to connect sensors and indicators to it.

Now I’m trying to overcome a few errors that the ArduinoIDE gives out. I wrote about them earlier.

If you cross reference the examples that use a commander and try to zero in on the difference, does that help? Get one that at least runs and replies to your serial commands etc. Then cross check and weave together the programs to get the desireable chars of each.

I think the char* is doing more than one thing at once, honestly the commander worked ok for me so I never had to figure it out, but if you can’t solve this in a reasonable time frame you can try using a simpler approach to modify the global variables directly using the serial port, using the code posted by Deku in the “programming the lepton…” thread. It did what I needed it to do. If you only have one motor etc. it’s a reasonable approach.

For which line is it giving this error? Did you get it working in the meantime?

I connected SimpliFOC to Nucleo-L476RG. I picked up the parameters of the motor and now it does not rotate perfectly, but quite well. Now I can control speed, angle and measure current. I figured out how to program Nucleo with ArduinoIDE and now I use this method.

I still couldn’t connect to SimpleFOCwebcontroller due to that error.

#include <SimpleFOC.h>
BLDCMotor motor = BLDCMotor(8, 1.16, 375); 
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8); 
Encoder encoder = Encoder(2, 3, 256);
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
float target_velocity = 25;
Commander command = Commander(Serial);
void doMotor(char* cmd) { command.motor(&motor, cmd); }
void setup() {
  encoder.init();
  encoder.enableInterrupts(doA, doB);
  motor.linkSensor(&encoder);
  driver.init();
  motor.linkDriver(&driver);
  driver.voltage_power_supply = 12;
  driver.voltage_limit = 12; 
  motor.velocity_limit = 350;
  motor.voltage_limit = 12;
  motor.current_limit = 2;
  motor.controller = MotionControlType::velocity; 
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM; 
  motor.PID_velocity.output_ramp = 12; 
  motor.PID_velocity.P = 0.01;
  motor.PID_velocity.I = 0; 
  motor.PID_velocity.D = 0; 
  motor.LPF_velocity.Tf = 0.1; 
  Serial.begin(115200);
  motor.useMonitoring(Serial);
  motor.init();
  char motor_id = 'M';
  command.add(motor_id,doMotor,'motor');
  motor.useMonitoring(Serial);
  motor.monitor_start_char = motor_id;                       //This line is red
  motor.monitor_end_char = motor_id; 
  commander.verbose = VerboseMode::machine_readable; 
  motor.initFOC();
  command.add('T', doTarget, "target velocity");       //This line is red
  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target velocity using serial terminal:")); //This line is red
  _delay(1000);
}
void loop() {
  motor.loopFOC();   
  motor.monitor();
  motor.move(target_velocity); 
  command.run();
}

Error

C:\BORIS\_Arduino\SimpleFOC\StepByStep_MotorEncoderParamTest_PlusWeb\StepByStep_MotorEncoderParamTest_PlusWeb.ino: In function 'void setup()':
C:\BORIS\_Arduino\SimpleFOC\StepByStep_MotorEncoderParamTest_PlusWeb\StepByStep_MotorEncoderParamTest_PlusWeb.ino:35:32: error: invalid conversion from 'int' to 'char*' [-fpermissive]
   35 |   motor.monitor_start_char = motor_id; // the same latter as the motor id in the commander
      |                                ^~~~~~~
      |                                |
      |                                int
In file included from c:\BORIS\_Arduino\libraries\Simple_FOC\src/SimpleFOC.h:115,
                 from C:\BORIS\_Arduino\SimpleFOC\StepByStep_MotorEncoderParamTest_PlusWeb\StepByStep_MotorEncoderParamTest_PlusWeb.ino:1:
c:\BORIS\_Arduino\libraries\Simple_FOC\src/communication/Commander.h:94:57: note:   initializing argument 3 of 'void Commander::add(char, CommandCallback, char*)'
   94 |     void add(char id , CommandCallback onCommand, char* label = nullptr);
      |                                                   ~~~~~~^~~~~~~~~~~~~~~
C:\BORIS\_Arduino\SimpleFOC\StepByStep_MotorEncoderParamTest_PlusWeb\StepByStep_MotorEncoderParamTest_PlusWeb.ino:39:3: error: 'commander' was not declared in this scope; did you mean 'Commander'?
   39 |   command.add('T', doTarget, "target velocity");
      |   ^~~~~~~~~
      |   Commander
C:\BORIS\_Arduino\SimpleFOC\StepByStep_MotorEncoderParamTest_PlusWeb\StepByStep_MotorEncoderParamTest_PlusWeb.ino:41:20: error: 'doTarget' was not declared in this scope
   41 |   Serial.println(F("Set the target velocity using serial terminal:"));
      |                    ^~~~~~~~
exit status 1
Compilation error: invalid conversion from 'int' to 'char*' [-fpermissive]

Now I’m working on a control algorithm:

  1. Current parameters come too often and with ripple. I need to get a smoother graph and with a frequency of 10-100 times per second. I want to use this data for emergency stop in case of overcurrent.
  2. The motor must move back and forth a certain distance with a smooth acceleration at the beginning and a smooth deceleration at the end.
  3. The movement must start on command from the button.

You have several small errors in the code:

command.add('T', doTarget, "target velocity");

  • you don’t have a “doTarget” function, so remove this line (or add the function)

commander.verbose = VerboseMode::machine_readable;

  • try: command.verbose = VerboseMode::machine_readable;

command.add(motor_id,doMotor,'motor');

  • try: command.add(motor_id, doMotor, "motor");

motor.monitor_start_char = motor_id;

  • I’m not sure why you’re seeing this error, it doesn’t make sense to me. Perhaps it will go away if you fix the other problems…

Let me know if this helps :slight_smile:

1 Like

I modified the code as per your recommendation and added a few lines of my own. Now the Web interface is connected. HOORAY. THANK YOU.
SimplyFOC site developers need to fix this on the site.

Now with the buttons I can change modes and change the speed with commands on the command line, but the sliders do not work. I guess I still need to figure out the interface.

I’m attaching the code, maybe it will help someone.

#include <SimpleFOC.h>
BLDCMotor motor = BLDCMotor(8, 1.16, 375); 
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8); 
Encoder encoder = Encoder(2, 3, 256);
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
float target_velocity = 25;
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }
void doMotor(char* cmd) { command.motor(&motor, cmd); }
void setup() {
  encoder.init();
  encoder.enableInterrupts(doA, doB);
  motor.linkSensor(&encoder);
  driver.init();
  motor.linkDriver(&driver);
  motor.controller = MotionControlType::velocity; 
  Serial.begin(115200);
  motor.useMonitoring(Serial);
  motor.init();
  char motor_id = 'M';
  command.add(motor_id, doMotor, "motor");
  motor.useMonitoring(Serial);
  motor.monitor_start_char = motor_id; 
  motor.monitor_end_char = motor_id; 
  command.verbose = VerboseMode::machine_readable; 
  motor.initFOC();
  command.add('T', doTarget, "target velocity");
  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target velocity using serial terminal:"));
  _delay(1000);
}
void loop() {
  motor.loopFOC();  
  motor.monitor();
  motor.move(target_velocity);
  command.run();
}