Running Motor Open-Loop

Hello all!

Just started playing around with the library - soldered up a L6234 breakout board, picked up an AS5048A board, and got everything wired up and working on a Teensy 3.1. Very impressed with how easy it was to configure things.

However, I’ve got a bit of an odd question - can SimpleFOC be convinced to run a motor open-loop? In effect, the code would step through the sine tables at a prescribed rate, assuming that the rotor is following along - a glorified sensorless speed control, if you will.

By way of explanation, in my application, I’m closing the velocity loop with a sensor outside the core SimpleFOC structure - thus being able to set the step-through rate directly would represent less overhead compared to measuring the velocity outside the SimpleFOC loop, then passing a velocity setpoint to the loopFOC object, which then reads its own sensor to do a motor-level loop closure.

I suppose alternatively, I could just inject my external velocity sensor data into the SimpleFOC structure (sensor.getVelocity()), and accomplish the same thing - perhaps this is actually easier than trying to run open-loop?

Any thoughts on either approach would be greatly appreciated.

Regards,
-Luke

Hey @Luke_Ionno,

I just pushed a new version of the library to the dev branch which implements velocity and angle control in open loop mode.

You can find the examples in:

examples
     > motion_control
               > open_loop_motor_control

I have superficially tested the code and both seem to work well. The open loop functions will be included in the next release of the library.

I understand what you mean. I had a project in which I wanted to use gyro as velocity sensor and encoder for FOC and position. Until this point the library doesn’t have support for external velocity sensing( one sensor for foc + one sensor for velocity ), but it might be one of the features for the future.

The good news is that you can do it yourself relatively easily. :smiley:
Basically run the motor(+sensor for FOC) in voltage mode (torque control) and then adapt the voltage set to the motor based on the velocity error in each moment. The simplest possible code could be:

void loop(){
     // foc iterative execution
     motor.loopFOC();

     // set the target voltage to the motor proportional to the velocity measured 
     // K > 0
     // This is P controller equation
     motor.move( K * (calculateExternalVelocity() - tartet_velocity) );
}

If you wish to use the open loop mode directly, the performance willl not be as good, but it might be good enough depending of application and time you put into tuning :smiley:
In general in open loop velocity control the motor doesn’t have any choice but to follow the velocity you are setting, if it doesn’t follow it it means it skips steps.
Here is the library example for openloop velocity control:

// Open loop motor control example 
 #include <SimpleFOC.h>

// motor instance
BLDCMotor motor = BLDCMotor(3, 10, 6, 11, 7);

void setup() {
  
  // power supply voltage
  // default 12V
  motor.voltage_power_supply = 12;

  // init motor hardware
  motor.init();
}

float target_velocity= 2; // rad/s
float target_voltage = 3; // V
void loop() {
  // set velocity in open loop
  // - velocity - rad/s
  // - voltage  - V
  motor.velocityOpenloop(target_velocity, target_voltage);

  // a bit of delay
  _delay(1);
}

The last thing you could do maybe is to set the phase angle directly. This would be most similar to iterating through the sine table. Here is an example of the code:

// Open loop motor control example 
 #include <SimpleFOC.h>

// motor instance
BLDCMotor motor = BLDCMotor(3, 10, 6, 11, 7);

void setup() {

  // power supply voltage
  // default 12V
  motor.voltage_power_supply = 12;

  // init motor hardware
  motor.init();

}

// target voltage to be set to the motor
float target_voltage = 2;
// target voltage to be set to the motor
float target_angle = 0;

void loop() {
  // integrating the angle in real time
  // the larger the constant added the faster the movement
  target_angle += 0.001;

  // set open loop voltage
  motor.setPhaseVoltage(target_voltage, target_angle);
} 

And then I suppose you could change the constant 0.001 proportional to your tracking error. This might work also.

Thanks so much! I’ll give these a try this evening.

Incidentally, you hit the nail on the head - I’ve got a gyro providing the rate data, relegating the magnetic sensors to pose estimation. Just after I posted the original message, I realized that voltage mode would probably be a good starting point - good to know that I’m pointed in generally the right direction.

-Luke

Ok, so I finally got around to giving the new code a test, and it works very nicely - I added my gyro reading routine to the open-loop example, and closed the loop; not perfect, but a pretty solid start.

However, I notice that the motor is a little ‘coggier’ than I recall it being when I was using it with a COTS gimbal driver; it isn’t visibly perceptible, but holding the motor, you can distinctly feel the cogging action. My total loop time is on the order of 800-900 us, but even if I drop the gyro read (reducing it to ~90 us), I can still feel the cogging. Any thoughts on possible improvements?

Also, while I took a cursory look through the source, could you point me to where the base PWM frequency is set? I’d like to try and damp down some of the coil noise, by increasing the frequency, if possible.

-Luke

PWM frequency is set in the _setPwmFrequency in FOCUtils.cpp. This is one of the few areas that is very mcu specific, i.e. different implementations for different mcu’s.

Can you tell us a bit more about your setup? Motor size, pole pairs, control mode, sensor ( do you have an shaft angle sensor as well as a gyro), etc.

What you are doing should very interesting. Do you have any photos?

Thanks for the pointer! Last night, I figured out that with the Teensy 3.1, I can use the analogWriteFrequency function to change the PWM frequency during setup, just like a normal Arduino Uno, et al. - this addresses the coil noise issue.

The motor is an RCTimer GBM2804 019-100T - something I picked up a few years ago, and now seems to be out-of-production, but it’s a 12N14P configuration, 10 ohm resistance. According to the SimpleFOC utility, it’s 7 pole pairs. I have an AS5048A connected (and fully tested in closed-loop operation) but I’m not using it right now. I’ve got an MPU6050 strapped to the output side of the motor, talking over I2C. The control mode is velocity_openloop; I then close this using the gyro (a rate-based P-only loop) - at this point, it just tries to keep the gyro (and motor output) at zero angular rate (with respect to the world), though it can of course accept a non-zero angular rate setpoint.

If you’ve seen a quadrotor camera gimbals, this should seem pretty familiar, and with good reason - I’m trying to build a SimpleFOC-based quadrotor gimbal controller. I have a few parameters I’d like to have full control over, so using a COTS gimbal driver isn’t the best option.

Not much to photograph just yet, but once I have something presentable, I’ll grab a few pictures.

-Luke