# ESC Calibration

Source: https://forum.modalai.com/topic/2522/esc-calibration
Category: ESCs, Sensors and Accessories (https://forum.modalai.com/category/15/escs-sensors-and-accessories)
Tags: esc
Posted: 2023-08-01 20:30:52 UTC by dlee
Replies: 10 · Views: 3670

## dlee · 2023-08-01 20:30:52 UTC

Hello,
I am trying to calibrate ESC on VOXL2. I am using 1804-2800kv motors. When I run `voxl-esc-calibrate.py` for each motors, I got some params. 

```
# Motor 1
    pwm_vs_rpm_curve_a0 = 112.878194918
    pwm_vs_rpm_curve_a1 = 0.336081465707
    pwm_vs_rpm_curve_a2 = 7.53669159958e-06

# Motor 2
    pwm_vs_rpm_curve_a0 = 35.6265065345
    pwm_vs_rpm_curve_a1 = 0.37353561309
    pwm_vs_rpm_curve_a2 = 2.9479165331e-06

# Motor 3
    pwm_vs_rpm_curve_a0 = 132.362831923
    pwm_vs_rpm_curve_a1 = 0.3256003514
    pwm_vs_rpm_curve_a2 = 8.8413818561e-06

# Motor 4
    pwm_vs_rpm_curve_a0 = -98.2189291548
    pwm_vs_rpm_curve_a1 = 0.405821707061
    pwm_vs_rpm_curve_a2 = 7.1523119742e-07
```

But I know that in order to use VOXL-ESC parameters in the XML file, I need to put only one value. I put 4 sets of parameters for each motor, how do I make them into one parameter set?

## Reply by Alex Kushleyev (ModalAI staff) · 2023-08-02 14:16:24 UTC

@dlee 

First, please make sure that you are running the calibration with propellers installed (and use safety precautions). 

Next, if you are doing several calibration tests (which sometimes makes sense) and want to use an average value, you have to be a little careful. Keep in mind that you cannot just average four a0 values and use it for a0_average (and so on). Also, even though the a0, a1, a2 numbers may look different, it is difficult to just look at the numbers and see how similar or different the curves are - the answer is to plot them.

I have written a short script to plot your four results using python. You can run it and take a look (first you may need to install `numpy` and `plotly` python packages using `pip3 install numpy plotly`.

```
import numpy as np
import plotly.graph_objects as go

rpms = np.arange(0,20000) #rpm range for the quadratic fit

cals = []
fits = []

cals.append([7.53669159958e-06, 0.336081465707, 112.878194918])
cals.append([2.9479165331e-06,  0.37353561309,  35.6265065345])
cals.append([8.8413818561e-06,  0.3256003514,   132.362831923])
cals.append([7.1523119742e-07,  0.405821707061, -98.2189291548])

fig = go.Figure()

for idx in range(len(cals)):
    fit = np.polyval(cals[idx], rpms)
    fits.append(fit)
    fig.add_trace(go.Scatter(x=rpms, y=fits[idx], name='Fit %d'%idx))

fig.update_layout(title='Motor Voltage vs. RPM')
fig.update_xaxes(title_text="RPM")
fig.update_yaxes(title_text="Motor Voltage (mV)")
fig.show()
```

The resulting plot looks like below, the four plots are not quite the same. But i have a feeling you might not have used propellers on during calibration? please confirm.

![4c98e125-8fb0-4b0b-9350-d9b7f42e1fc7-image.png](https://forum.modalai.com/assets/uploads/files/1690985698809-4c98e125-8fb0-4b0b-9350-d9b7f42e1fc7-image.png)

## Reply by dlee · 2023-08-02 20:14:58 UTC (in reply to Alex Kushleyev)

@Alex-Kushleyev 
It seems that when I run the script once, it only calibrates for one motor. So I ran the script 4 times to calibrate 4 motors. The motors spinned when I ran each script. Is there something I'm doing wrong? 
I ran that script inside the drone, so I commented out the code to draw the plot.

## Reply by Alex Kushleyev (ModalAI staff) · 2023-08-02 22:32:01 UTC (in reply to dlee)

@dlee , the calibration script indeed only spins one motor at a time, by design. Can you please confirm that you calibrated with propellers on?

## Reply by dlee · 2023-08-03 23:18:14 UTC (in reply to Alex Kushleyev)

@Alex-Kushleyev Yes, I calibrated with propellers on.

## Reply by Alex Kushleyev (ModalAI staff) · 2023-08-03 23:19:39 UTC (in reply to dlee)

@dlee 

Got it. Can you tell me what was the maximum rpm reached during the calibration? I think i may have used too high rpm in the plot.

## Reply by dlee · 2023-08-03 23:28:22 UTC (in reply to Alex Kushleyev)

@Alex-Kushleyev Maximum RPM was reached at 13,000. I am using 2800kv motors.

## Reply by Alex Kushleyev (ModalAI staff) · 2023-08-03 23:35:06 UTC (in reply to dlee)

@dlee 

Thanks. If you look at the plot at 13K rpm, the plots look much closer together. Also please note that there are two curves that are close together and another two that are also close together. I think they may correspond to CW and CCW rotating propellers. Sometimes the CW and CCW propellers are not exactly the same and could result in slightly different calibration..

I think for your initial testing you can use either of the calibration curves. However i am wondering whether your propellers are not symmetric CW and CCW.

You can also use a calibration that is an average. I will follow up soon how to calculate that.

## Reply by dlee · 2023-08-03 23:38:19 UTC (in reply to Alex Kushleyev)

@Alex-Kushleyev I checked that all of propellers spin right side (top-left & bottom-right: CCW; top-right & bottom-left : CW).

## Reply by dlee · 2023-08-15 19:58:40 UTC (in reply to Alex Kushleyev)

@Alex-Kushleyev Is there any update?

## Reply by Alex Kushleyev (ModalAI staff) · 2023-08-16 19:43:27 UTC (in reply to dlee)

@dlee , sorry for the delay.

Just to clarify, it is possible that your CW and CCW propellers are not exactly the same, therefore the CW and CCW motors are showing slightly different response to calibration. In this case we can calculate an average for this calibration and use that for all 4 motors. I modified the script to calculate the quadratic fit for all four calibration results together. 

```
import numpy as np
import plotly.graph_objects as go

rpms = np.arange(0,13000) #rpm range for the quadratic fit

cals = []
fits = []
all_fits = []

#enter the calibration results from each motor
cals.append([7.53669159958e-06, 0.336081465707, 112.878194918])
cals.append([2.9479165331e-06,  0.37353561309,  35.6265065345])
cals.append([8.8413818561e-06,  0.3256003514,   132.362831923])
cals.append([7.1523119742e-07,  0.405821707061, -98.2189291548])

fig = go.Figure()

for idx in range(len(cals)):
    fit = np.polyval(cals[idx], rpms)
    fits.append(fit)
    fig.add_trace(go.Scatter(x=rpms, y=fits[idx], name='Fit %d'%idx))  #plot each fit

#create an array that contains points sampled from each curve
#and perform a polynomial fit on all the data to find the average
all_data = np.array(fits).flatten('C')
all_rpms = np.array([rpms,rpms,rpms,rpms]).flatten('C')

#evaluate the average poly fit
ply = np.polyfit(all_rpms, all_data, 2)
av_fit = np.polyval(ply, rpms)

#print the average fit coefficients
print('Average Fit coefficients:')
print('    pwm_vs_rpm_curve_a0 = ' + str(ply[2]))
print('    pwm_vs_rpm_curve_a1 = ' + str(ply[1]))
print('    pwm_vs_rpm_curve_a2 = ' + str(ply[0]))

#plot the average
fig.add_trace(go.Scatter(x=rpms, y=av_fit, name='Average Fit'))

#finalize and show the figure
fig.update_layout(title='Motor Voltage vs. RPM')
fig.update_xaxes(title_text="RPM")
fig.update_yaxes(title_text="Motor Voltage (mV)")
fig.show()
```

It results in the following plot and average coefficients. You can enter these coefficients into your custom esc parameters xml file.
```
Average Fit coefficients:
    pwm_vs_rpm_curve_a0 = 45.66215105517507
    pwm_vs_rpm_curve_a1 = 0.36025978431449995
    pwm_vs_rpm_curve_a2 = 5.01030529655002e-06
```
![2dd75e2f-f722-464d-be82-5548568ec25b-image.png](https://forum.modalai.com/assets/uploads/files/1692214971344-2dd75e2f-f722-464d-be82-5548568ec25b-image.png)
