Open Loop Control Problem

Hi
I’m trying do open loop control. While I’m using this code with values inside motor.move(), motor is running perfectly. But I cant control with serial monitor. I have to maintain the motor.move(target_postion) and change position values in the serial monitor. While I’m using the code with serial monitor the current is changing without motor running. What should I do for that? Can anyone help. I’m attaching the code below.

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

// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(2);
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);

// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6, 8);

//target variable
float target_position = 0;

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_position, cmd); }
void doLimit(char* cmd) { command.scalar(&motor.voltage_limit, cmd); }
void doVelocity(char* cmd) { command.scalar(&motor.velocity_limit, cmd); }

void setup() {

// driver config
// power supply voltage [V]
driver.voltage_power_supply =12;
// limit the maximal dc voltage the driver can set
// as a protection measure for the low-resistance motors
// this value is fixed on startup
driver.voltage_limit =6 ;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);

// limiting motor movements
// limit the voltage to be set to the motor
// start very low for high resistance motors
// currnet = resistance*voltage, so try to be well under 1Amp
motor.voltage_limit = 3; // [V]
// limit/set the velocity of the transition in between
// target angles
motor.velocity_limit = 5; // [rad/s] cca 50rpm
// open loop control config
motor.controller = MotionControlType::angle_openloop;

// init motor hardware
motor.init();

// add target command T
command.add(‘T’, doTarget, “target angle”);
command.add(‘L’, doLimit, “voltage limit”);
command.add(‘V’, doLimit, “movement velocity”);

Serial.begin(115200);
// motor.useMonitoring(Serial);
Serial.println(“Motor ready!”);
Serial.println(“Set target position [rad]”);

_delay(1000);
}

void loop() {
// open loop angle movements
// using motor.voltage_limit and motor.velocity_limit

motor.move(target_position);

// user communication
command.run();
}

Hi, welcome to SimpleFOC @asna ,

At first glance this code looks ok. Do you see any output on the Serial console? Does it print back the value you have entered (verbose mode)?

Have you changed other values in the code perhaps also?

As a side question, may I ask what kind of motor you are using?

HI runger

Thank you for your reply, I’m running BLDC motor. With this code there is no output on serial monitor. So I changed my code and tried after that whatever values I’m putting it is coming on the serial monitor. But still motor is not running. I’m attaching that changed code also for your reference.

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

// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(2);
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);

// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6, 8);

//target variable
float target_position = 0;

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) {
command.scalar(&target_position, cmd);
}
void doLimit(char* cmd) {
command.scalar(&motor.voltage_limit, cmd);
}
void doVelocity(char* cmd) {
command.scalar(&motor.velocity_limit, cmd);
}

void setup() {

// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
// limit the maximal dc voltage the driver can set
// as a protection measure for the low-resistance motors
// this value is fixed on startup
driver.voltage_limit = 6 ;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);

// limiting motor movements
// limit the voltage to be set to the motor
// start very low for high resistance motors
// currnet = resistance*voltage, so try to be well under 1Amp
motor.voltage_limit = 5; // [V]
// limit/set the velocity of the transition in between
// target angles
motor.velocity_limit = 5; // [rad/s] cca 50rpm
// open loop control config
motor.controller = MotionControlType::angle_openloop;

// init motor hardware
motor.init();

// add target command T
command.add(‘T’, doTarget, “target angle”);
command.add(‘L’, doLimit, “voltage limit”);
command.add(‘V’, doLimit, “movement velocity”);

Serial.begin(115200);
motor.useMonitoring(Serial);

Serial.println(“Motor ready!”);
Serial.println(“Set target position [rad]”);
_delay(1000);

}

void loop() {
// open loop angle movements
// using motor.voltage_limit and motor.velocity_limit
while(Serial.available() == 0) {}
target_position=Serial.parseFloat();

Serial.println(target_position);

motor.move(target_position);

// user communication
command.run();
}

Hi,

Still not sure what is going on, but in this example:
while(Serial.available() == 0) {}
this cannot work.
This code will block until data becomes available, and this isn’t allowed, because the motor.move() function should be called very frequently - ideally 10000x per second. So you cannot write code in the main loop that causes long delays or waits for input like this one.

Hi @asna ,

I see what you’re trying to do with waiting for serial input, and then trying to take the value as the target, however you can’t accomplish it this way. To expand on @runger 's comment, motor.move(target_position) is not a one time run that will move the motor where you want, what it does is calculate the right values to send to your driver in order to properly run your BLDC. Every loop it is doing calculations in order to get to the right speed and position. Once it has reached the target_position, it will stop on it’s own even if it is constantly called.

In fact, you should get rid of the following section completely, as the commander that is defined in the example code, along with command.run() in the loop will handle serial input commands.

while(Serial.available() == 0) {}
target_position=Serial.parseFloat();

Serial.println(target_position);

If you take a look at the section

command.add(‘T’, doTarget, “target angle”);
command.add(‘L’, doLimit, “voltage limit”);
command.add(‘V’, doLimit, “movement velocity”);

Those are the commands that it is set to recognize, and then run that function. What the commander does is check for the first character, and if found, strip it, and then pass on the rest to the function called.
So for example, in the serial monitor you type in “T6” it will run doTarget with the value “6”, which sets the target_position to 6 for your. It is the same with using “L3” to change the voltage limit to 3, or “V2” to change the velocity limit to 2.

If you want to write your own serial parsing, you can do so. But you’ll have to comment out the commander along with all references. What I would do then is change

while(Serial.available() == 0) {}
target_position=Serial.parseFloat();

to

if(Serial.available() > 0){
    target_position=Serial.parseFloat();
}

This way it won’t block the loop, so that motor.run() can be ran as quick as possible

Thank you Ivan

Now I got the result.