Hello everyone,
I have been trying to implement a closed angle control loop using a stepper motor but have run into some unexpected behavior. My current setup includes an Arduino Mega 2560, L298N motor driver, a 0.9 deg/step bipolar stepper motor and an AMT103-V capacitive encoder. I have the motor driver powered at 12v from a variable benchtop power supply. I have set my encoder for 512 ppr.
I have an application that requires a positional control loop and backdrivability. When attempting to run this example from the SimpleFOCDocs I have encountered erratic jittering when using MotionControlType::angle
and no motion or holding torque when attempting to use MotionControlType::torque
. When calculating the pole pair number for my motor, I used the following equation: pole_pair = (steps/rotation) / 4;
In my case, (400 steps/rev) / 4 = 100 PP
, however when I set StepperMotor motor = StepperMotor(100);
I get a failed PP check when running the code shown below, and a changing estimation that is always higher than the calculated value.
Assuming I had miscalculated the PP number, I tried using find_pole_pairs_number
under Simple FOC>utils>calibration>find_pole_pair_number>encoder>find_pole_pairs_number. This yields something like this:
When using StepperMotor motor = StepperMotor(102);
(or whatever the estimated PP) I still get the erratic behavior, as seen in the clip below:
https://youtu.be/bVqnWa4HgVQ
The motor heats up, and when the rotor is moved it begins to jump erratically until it settles again, usually in a random angle. Additionally, the index search I believe should be one full rotation, but as you can see in the clip is far less than that.
I have tried running the same setup with MotionControlType::angle_openloop
and MotionControlType::velocity_openloop
, using the same setup and both worked as expected.
I have also tried:
- Running the setup with/without index pin on encoder
- Running the example using a Nucleo-64 board (as in the example)
- Changing encoder resolution (tried 2048 PPR and 512 PPR)
- Changing the PID gains
I believe that I am misunderstanding something about the functionality seen in the code I am running below. If anyone has any ideas on why this is happening, let me know!
#include <SimpleFOC.h>
// Stepper motor instance
StepperMotor motor = StepperMotor(102);
// Stepper driver instance
StepperDriver4PWM driver = StepperDriver4PWM(5, 6, 9, 10);
// encoder instance
Encoder encoder = Encoder(2, 3, 512, 21);
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}
void doIndex(){encoder.handleIndex();}
// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }
void setup() {
// initialize encoder sensor hardware
encoder.init();
encoder.enableInterrupts(doA, doB, doIndex);
// link the motor to the sensor
motor.linkSensor(&encoder);
// choose FOC modulation
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.init();
// link the motor to the sensor
motor.linkDriver(&driver);
// set control loop type to be used
motor.controller = MotionControlType::angle;
// controller configuration based on the control type
motor.PID_velocity.P = 0.2;
motor.PID_velocity.I = 10;
motor.PID_velocity.D = 0;
// default voltage_power_supply
motor.voltage_limit = 12;
// velocity low pass filtering time constant
motor.LPF_velocity.Tf = 0.01;
// angle loop controller
motor.P_angle.P = 20;
// angle loop velocity limit
motor.velocity_limit = 50;
// use monitoring with serial for motor init
// monitoring port
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);
// initialise motor
motor.init();
// align encoder and start FOC
motor.initFOC();
// set the initial target value
motor.target = 1;
// define the motor id
command.add('M', onMotor, "motor");
// Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
Serial.println(F("Motor commands sketch | Initial motion control > torque/voltage : target 2V."));
_delay(1000);
}
// set the initial target value
float target_angle = 1;
long timestamp_us = _micros();
void loop() {
// iterative setting FOC phase voltage
motor.loopFOC();
// iterative function setting the outter loop target
// velocity, position or voltage
// if tatget not set in parameter uses motor.target variable
motor.move();
// real time monitoring calls
//motor.monitor();
// user communication
//command.run();
}
Thank you!
Michael L.