How to tuning pid for hoverboard motor using drv8302 board

Hello, I am new to this group and new to use simplefoc. I am trying to use drv8302 board to drive the hoverboard hub motor. It is working in torque mode but not looking good with velocity mode.
When in velocity mode, the motor is initially moving well but it is slowly moving slower and slower and eventually it stops after about 30 seconds. Looks to me is that pid is not tuned. What would you experts set for ?
Currently p is 0.2, I is done from 10 to 60 and d is 0.0001

Looks like there is some problem with the library. I found the following topic in the forum. Has the problem been fixed ?
https://community.simplefoc.com/t/errors-with-motor-angle-insufficient-precision-of-float/312/11

Hey @pinegem,
This might be the same issue, but maybe also so other issue due to the sensor.

What is the sensor youre using?
What is the velocity that you’re setting?
Does it happen also in voltage mode?

Can you check that one the motor stops in velocity mode, if you change the mode to voltage mode, the motor will work normally. You can do this using the simplefocstudio or just with the commander.

@Antun_Skuric. Thank you for your response. It’s incremental encoder with 800 ppr. So the quad is 3200. Velocity is set from 2, 3, 4, 5, 6. Haven’t tried any larger numbers yet. The problem above shows up more quickly when you change the velocity settings. Ie. change from A2 to A3. It happens to closed loop control now whether it is torque or velocity. I did test it with studio or standalone hard coded mode. It appears to behave the same way. I have a short video for the motor but dont know how to upload to this forum. Open loop is no issue.

Do try to make sure that you do not lose the steps in your encoder. I had some issues like that.
Maybe you need a pull-up for your encoder channels?

Test your encoder sensor by manually spinning it and using the encoder test example. Make sure that for example 10 turns of the motor are exactly 62.8 rad.

The floati g point issue will not be the problem for such a low velocity and such a short time. It happens after 32000 rad = 5000 rotations.

@Antun_Skuric, thank you again on your suggestions. The encoder does need pull resistors and that is taken care of. Did manual testing using your encoder test utility and it came out clean. One full turn(2 pi) it generates 1600 which is half quad. Once the motor stops, the only way to have it move again is to power off/on the drv8302 board and reboot esp32 which is used for driving the board.

Hey @pinegem,
Try a lot more than 2pi, try 100 rotations. Or even better see if when the motor stops due to this issue you’re having, is the position ok.
I really think this is the issue.

What are the pull-up values you’re using?

Thy changing the esp32 pins for the interrupts, sometimes the pins themselves can be an issue.

@Antun_Skuric thank you for your quick suggestions. Will try to run open loop along with the encoder and see if that stops at certain point. Pull-ups are 10k each. The gpios for encoder are tested on 32, 34, 35, 39 . But nothing changed. Will update the test on open loop with encoder output. BTW, is PCNT better suited here for interruption for esp32 ?
Thanks.

@Antun_Skuric. with open loop mode, the motor won’t stop by itself. And I can see the angle and velocity is also valid,

Below is the test code,

#include “freertos/FreeRTOS.h”
#include “freertos/task.h”
#include <SimpleFOC.h>

// DRV8302 pins connections
// don’t forget to connect the common ground pin
#define INH_A GPIO_NUM_14
#define INH_B GPIO_NUM_27
#define INH_C GPIO_NUM_26

#define EN_GATE GPIO_NUM_12
#define M_PWM GPIO_NUM_25
#define M_OC A2
#define OC_ADJ A3

#define YELLOW_ENCODER_A GPIO_NUM_34
#define BLUE_ENCODER_B GPIO_NUM_39
//#define BLUE_ENCODER_B GPIO_NUM_35
#define GREEN_HALLPIN GPIO_NUM_36

// skateboard 7 pairs , hoverboard 15 pairs
#define PP_MOTOR 15

// RoboWheel Encoder configuration
// RoboWheel Pulse Per Revolution 800 instead of stated 3200
#define PPR 800

// Motor instance
BLDCMotor motor = BLDCMotor(PP_MOTOR);
BLDCDriver3PWM driver = BLDCDriver3PWM(INH_A, INH_B, INH_C, EN_GATE);

// encoder instance
Encoder encoder = Encoder(YELLOW_ENCODER_A, BLUE_ENCODER_B, PPR);

// Interrupt routine intialisation
// channel A and B callbacks
void doA(){encoder.handleA();}
void doB(){encoder.handleB();}

// velocity set point variable
float target_velocity = 0;

// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }
//void doTarget(char* cmd){ command.scalar(&target_velocity, cmd); }

void task_encoder_monitor_cmd(void * pvParameters) {

// initialize encoder sensor hardware

// enable/disable quadrature mode
encoder.quadrature = Quadrature::ON;

// check if you need internal pullups
encoder.pullup = Pullup::USE_EXTERN;

encoder.init();
encoder.enableInterrupts(doA, doB);
// link the motor to the sensor
//motor.linkSensor(&encoder);

for(;:wink: {
Serial.print(encoder.getAngle());
Serial.print("\t");
Serial.println(encoder.getVelocity());
vTaskDelay(1000/portTICK_PERIOD_MS);

}

}

void setup() {

xTaskCreatePinnedToCore(
task_encoder_monitor_cmd, /* Function to implement the task /
“task_monitor_cmd”, /
Name of the task /
4096, /
Stack size in words /
NULL, /
Task input parameter /
0, /
Priority of the task /
NULL, /
Task handle. /
0); /
Core where the task should run */

// DRV8302 specific code
// M_OC - enable overcurrent protection
//pinMode(M_OC,OUTPUT);
//digitalWrite(M_OC,LOW);
// plug M_OC to GND

// M_PWM - enable 3pwm mode
//pinMode(M_PWM,OUTPUT);
//digitalWrite(M_PWM,HIGH);
// plug M_PWM to 3.3v

// OD_ADJ - set the maximum overcurrent limit possible
// Better option would be to use voltage divisor to set exact value
//pinMode(OC_ADJ,OUTPUT);
//digitalWrite(OC_ADJ,HIGH);
// plug OC_ADJ to 3.3v

// driver config
// power supply voltage [V]
driver.voltage_power_supply = 36;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);

// choose FOC modulation
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

// set control loop type to be used
//motor.controller = MotionControlType::torque;
motor.controller = MotionControlType::velocity_openloop;

// aligning voltage [V]

motor.voltage_sensor_align = 3;
// index search velocity [rad/s]
motor.velocity_index_search = 1;

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

// contoller configuration
// default parameters in defaults.h

// velocity PI controller parameters
motor.PID_velocity.P = 0.0;
motor.PID_velocity.I = 0;
//motor.PID_velocity.D = 0.0001;
// default voltage_power_supply
motor.voltage_limit = 6;
motor.velocity_limit = 10;
// jerk control using voltage voltage ramp
// default value is 300 volts per sec ~ 0.3V per millisecond
motor.PID_velocity.output_ramp = 0;

// velocity low pass filtering time constant
motor.LPF_velocity.Tf = 0.1;

// 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
// open loop no initFOC
//motor.initFOC();

// set the inital target value
//motor.target = 4;

// define the motor id
command.add(‘A’, onMotor, “motor”);
//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() {
// 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(target_velocity);
motor.move();
//motor.monitor();

// user communication
command.run();
}

***** Below is the log for encoder printout,

0.00 0.00
0.01 0.00
0.01 0.00
0.01 0.00
0.01 0.00
0.01 0.00
0.01 0.00
Warn: \r detected!
Target: 2.000
0.88 0.15
2.90 1282.82
4.88 1282.82
6.89 1056.55
8.89 2906.77
10.89 1795.75
12.88 2793.57
14.88 2060.46
16.88 1649.79
18.86 1649.79
20.86 992.95
22.88 992.95
24.87 2610.26
26.89 1107.36
28.88 1107.36
30.88 1211.52
32.86 1447.61
34.86 1447.61
36.85 1749.55
38.85 1280.05
40.86 1280.05
42.85 778.64
44.84 778.64
46.84 1885.99
48.84 1798.69
50.81 1797.49
52.83 2177.43
54.82 1438.57
56.81 2312.81
58.82 2312.81
60.83 1446.12
62.82 1766.27
64.83 1955.85
66.83 1544.15
68.82 1544.15
70.83 2298.62
72.81 2493.17
74.81 1598.19
76.81 1171.43
78.81 1171.43
80.80 2484.47
82.78 1965.44
Warn: \r detected!
Target: 3.000
85.24 2001.87
88.23 1714.40
91.24 2903.63
94.23 2875.25
97.23 4783.67
100.21 2661.24
103.22 2422.70
106.19 4302.07
109.19 3766.86
112.18 2834.30
115.17 2324.23
118.16 3187.27
121.16 4823.51
124.16 1944.41
127.15 4371.93
130.15 3458.74
133.14 2205.67
136.15 3422.16
139.13 2541.98
142.12 2888.39
145.11 3276.80
148.11 4175.50
151.09 2877.15
154.11 2795.89
157.08 2955.99
160.08 2930.85
163.06 3955.60
166.08 1948.27
169.06 3114.16
172.08 3268.23
175.07 3831.33
178.06 2310.71
181.03 4952.84
184.02 3234.24
187.02 2377.68
190.02 3071.11
193.01 4144.55
196.00 2066.69
199.00 2670.35
201.99 3499.84
205.01 3693.58
207.99 4055.22
210.99 2789.37
213.98 2498.70
216.99 3332.72
219.97 3156.95
222.99 2306.02
225.96 4088.82
228.98 2522.15
231.96 2683.44
234.96 2663.25
237.95 5513.73
240.96 2306.54
243.95 2306.54
246.96 2275.63
249.95 2827.51
252.94 2468.95
255.94 2339.61
258.93 4542.81
261.93 2199.40
264.93 4760.46
267.93 2768.47
270.92 2750.34
273.93 2836.98
276.90 2836.98
279.91 2423.54
282.89 2654.65
285.91 2176.15
288.88 2176.15
291.90 1815.64
294.89 3424.86
297.87 2574.02
300.85 2574.02
303.87 3691.18
306.85 1774.27
309.85 4199.24
312.84 3745.14
315.83 2176.58
318.80 2835.74
321.81 4447.68
324.81 2443.18
327.80 3428.25
330.81 4411.38
333.80 3270.35
336.79 2532.09
339.76 2269.03
342.77 3790.98
345.75 2314.12
348.76 2976.35
351.74 2737.38
354.75 4466.73
Warn: \r detected!
Target: 0.000
355.06 0.00
355.06 0.00
355.06 0.00
355.06 0.00
355.06 0.00
355.06 0.00
355.06 0.00
355.06 0.00
355.06 0.00

After making changes (adding a pcnt based encoder class), the motor is working correctly with closed loop velocity control. Esp32 is notoriously bad on fast and continuous gpio pin based interruption.

1 Like

Also bldc motor class is changed to adapt to that new encoder class.