Skip to content

Commit 7b3685a

Browse files
committed
docs: Improve motor control documentation details and cross-references
- Corrected Back-EMF measurement CV from CV63 to CV61. - Rewrote 'Startup Controller' section for clarity and accuracy. - Added Sphinx C cross-references for get_kp(), init_controller(), and speed_helper() functions.
1 parent d4b2a7a commit 7b3685a

1 file changed

Lines changed: 17 additions & 15 deletions

File tree

docs/sphinx/source/software/sw_description.rst

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ The *Speed Helper* block effectively sets the setpoint of the controller accordi
7272
For feedback the back EMF voltage *V_EMF* is measured via voltage divider and ADC. *V_EMF* is proportional to the motor speed.
7373

7474

75-
While the central component is the PID controller, there is an additional block called `Feed-forward <https://en.wikipedia.org/wiki/Feed_forward_(control)>`_ that has an impact on the control output variable. The Feed-forward block adds an additional offset to the output depending on the setpoint; this is done to achieve better control. A more detailed explanation regarding Feed-forward can be found below. The speed helper block corresponds to the ``speed_helper()`` function, which delays changing the setpoint according to the configured deceleration/acceleration rates.
75+
While the central component is the PID controller, there is an additional block called `Feed-forward <https://en.wikipedia.org/wiki/Feed_forward_(control)>`_ that has an impact on the control output variable. The Feed-forward block adds an additional offset to the output depending on the setpoint; this is done to achieve better control. A more detailed explanation regarding Feed-forward can be found below. The speed helper block corresponds to the :c:func:`speed_helper()` function, which delays changing the setpoint according to the configured deceleration/acceleration rates.
7676

7777
.. figure:: ../../../svg/sw/Block_Diagram_Digital_Controller.svg
7878
:alt: Block Diagram - Digital Controller
@@ -93,30 +93,32 @@ The benefit of doing this is that the PID controller does not have to work in th
9393
Speed Table Initialization
9494
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9595

96-
The speed table is a crucial component of the motor control system, as it translates the 128 speed steps received from the DCC controller into specific setpoints for the PID controller. This table is initialized once at startup in the `init_controller` function. The shape of the speed curve can be configured using three CV values: `V_min` (CV2), `V_mid` (CV6), and `V_max` (CV5).
96+
The speed table is a crucial component of the motor control system, as it translates the 128 speed steps received from the DCC controller into specific setpoints for the PID controller. This table is initialized once at startup in the :c:func:`init_controller` function. The shape of the speed curve can be configured using three CV values: `V_min` (CV2), `V_mid` (CV6), and `V_max` (CV5).
9797

9898
- **V_min (CV2):** Defines the starting voltage (setpoint) for the first speed step.
9999
- **V_mid (CV6):** Sets the voltage at the midpoint of the speed range (speed step 64).
100100
- **V_max (CV5):** Determines the maximum voltage at the highest speed step (126).
101101

102102
The speed table is calculated with two linear interpolations: one from `V_min` to `V_mid` and another from `V_mid` to `V_max`. This creates a two-segment linear speed curve, which allows for a non-linear relationship between the speed step and the motor voltage. For example, you can have a gentle acceleration at low speeds and a more aggressive one at higher speeds.
103103

104-
The `speed_helper` function then uses this table to gradually adjust the setpoint based on the configured acceleration and deceleration rates.
104+
The :c:func:`speed_helper` function then uses this table to gradually adjust the setpoint based on the configured acceleration and deceleration rates.
105105

106106

107107
Startup Controller
108108
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109109

110-
Used on startup, meaning when the motor is not moving. First the startup controller retrieves the last `BASE_PWM_ARR_LEN` base PWM levels.
111-
The base pwm levels are not retained on a power cycle. That means when there is no previous base PWM level saved, the startup controller will start ramping up from 0.
112-
When there is less than `BASE_PWM_ARR_LEN` base PWM levels saved, the startup controller will ramp up from the average of the saved base PWM levels.
110+
The startup controller is used when the motor is stationary to find the minimum PWM level required to overcome static friction. This process is not retained on a power cycle.
113111

114-
After the startup controller retrieved the average of the last base pwm levels :math:`\bar{b}` it sets a PWM duty cycle level of :math:`\frac{2}{3} \cdot \bar{b}` and then ramps up the duty cycle/PWM level until the motor starts moving.
115-
When no previous startup PWM levels are saved the startup controller begins ramping up from 0. The ramp-up is not a smooth, linear increase. Instead, the PWM level is incremented in steps, with the size of each step determined by the maximum possible PWM level (`max_level`) divided by 250. This `max_level` is a function of the PWM frequency.
112+
The initial PWM level for the startup sequence is determined as follows:
116113

117-
If the PWM level reaches `max_level` and the motor still hasn't moved, the startup controller will try again with a lower starting PWM level (half of the initial `get_initial_level()` value). This prevents the motor from receiving excessive power if it's stalled.
114+
- If previous successful startup levels are saved in memory, the controller calculates their average, :math:`\bar{b}`, and sets the initial PWM level to :math:`\frac{2}{3} \cdot \bar{b}`.
115+
- If no previous levels are saved, the ramp-up starts from a PWM level of 0.
118116

119-
Once the motor starts moving (detected by a back-EMF voltage greater than 7.5), the current PWM `level` is saved as a new base PWM value. This value is then multiplied by `K_FF` (a configurable factor from CV47) and used as the feed-forward term for the PID controller.
117+
From this starting point, the controller progressively ramps up the duty cycle until motor movement is detected. The ramp-up is not smooth but occurs in steps, with the step size determined by the maximum PWM level (which is a function of the PWM frequency).
118+
119+
If the PWM level reaches its maximum without motor movement, the controller reduces the starting level by half and retries, preventing excessive power to a stalled motor.
120+
121+
Once movement is detected (via back-EMF voltage), the current PWM `level` is saved as a new base value for future startups. This value is also multiplied by `K_FF` (from CV47) and used as the feed-forward term for the PID controller.
120122

121123

122124

@@ -173,9 +175,9 @@ Gain Scheduling
173175

174176
Another aspect to consider is the implementation of `gain scheduling <https://en.wikipedia.org/wiki/Gain_scheduling>`_. K\ :sub:`P` is a function of the current setpoint. Often it is favorable to have a higher proportional gain K\ :sub:`P` for slow speeds, achieving better control results. The illustration above shows the default setting for K\ :sub:`P`. CV_54 & CV_55 are used to set K\ :sub:`P` @ x\ :sub:`0`, CV_56 & CV_57 for K\ :sub:`P` @ x\ :sub:`1`, and CV_58 & CV_59 for K\ :sub:`P` @ x\ :sub:`2`. Additionally, CV_60 is used to shift x\ :sub:`1` from the leftmost point (0% = 0/255) to the rightmost point (100% = 255/255).
175177

176-
The `get_kp()` function implements this gain scheduling. It calculates the proportional gain `K_p` based on the current setpoint `sp`. The function uses two different linear equations to determine `K_p`, depending on whether the setpoint is above or below the `k_p_x_1` threshold. This creates a piecewise linear function for `K_p`, allowing for different gain characteristics at different speed ranges.
178+
The :c:func:`get_kp()` function implements this gain scheduling. It calculates the proportional gain `K_p` based on the current setpoint `sp`. The function uses two different linear equations to determine `K_p`, depending on whether the setpoint is above or below the `k_p_x_1` threshold. This creates a piecewise linear function for `K_p`, allowing for different gain characteristics at different speed ranges.
177179

178-
The parameters for these linear equations (`k_p_m_1`, `k_p_m_2`, `k_p_y_0`, `k_p_y_1`) are pre-calculated in the `init_controller` function based on the corresponding CV values.
180+
The parameters for these linear equations (`k_p_m_1`, `k_p_m_2`, `k_p_y_0`, `k_p_y_1`) are pre-calculated in the :c:func:`init_controller` function based on the corresponding CV values.
179181

180182

181183
.. _feed_forward:
@@ -191,17 +193,17 @@ The base PWM level is set by the startup controller and is the PWM level at whic
191193
Speed Helper
192194
^^^^^^^^^^^^^^^^^^
193195

194-
The `speed_helper` function is responsible for implementing smooth acceleration and deceleration. It is called by a repeating timer, with the interval configured by CV175. This function acts as a temporal filter for the speed setpoint.
196+
The :c:func:`speed_helper` function is responsible for implementing smooth acceleration and deceleration. It is called by a repeating timer, with the interval configured by CV175. This function acts as a temporal filter for the speed setpoint.
195197

196-
Instead of instantly changing the motor's setpoint to the new target speed step, the `speed_helper` function gradually increments or decrements the current setpoint based on the acceleration (CV3) and deceleration (CV4) rates. These CVs determine how many calls to `speed_helper` are needed for a single speed step change. For example, if the acceleration rate is set to 5, the `speed_helper` must be called 5 times before the setpoint is incremented to the next speed step. This creates a time-based acceleration/deceleration curve.
198+
Instead of instantly changing the motor's setpoint to the new target speed step, the :c:func:`speed_helper` function gradually increments or decrements the current setpoint based on the acceleration (CV3) and deceleration (CV4) rates. These CVs determine how many calls to :c:func:`speed_helper` are needed for a single speed step change. For example, if the acceleration rate is set to 5, the :c:func:`speed_helper` must be called 5 times before the setpoint is incremented to the next speed step. This creates a time-based acceleration/deceleration curve.
197199

198200
The function also handles direction changes. If a direction change is detected, it will immediately jump to the new target speed without any delay, ensuring a responsive change in direction.
199201

200202

201203
Back-EMF voltage measurement
202204
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
203205

204-
To provide a feedback signal proportional to the motor speed, the ADC is used to measure the `Back-EMF voltage <https://en.wikipedia.org/wiki/Counter-electromotive_force>`_. The measurement works by setting the PWM duty cycle to 0%, waiting for a certain delay time (CV_62), and then measuring x times (x = CV_63). The ADC input channel is selected based on the motor's direction (forward or reverse). While measuring, the array with measurement values is sorted using insertion sort. Afterwards, y elements (y = CV_63) from the left (lowest values) and z elements (z = CV_64) from the right (highest values) will be dismissed to mitigate the impact of potential outliers in measurement. The average value of the remaining values will be computed and fed back into the control algorithm. Considering default settings (100us delay, 100 samples, ~2µs sampling time), the complete measurement run, including averaging, takes about 0.3ms to 0.35ms, which effectively reduces the maximum possible duty cycle to about 93% to 94%.
206+
To provide a feedback signal proportional to the motor speed, the ADC is used to measure the `Back-EMF voltage <https://en.wikipedia.org/wiki/Counter-electromotive_force>`_. The measurement works by setting the PWM duty cycle to 0%, waiting for a certain delay time (CV_62), and then measuring x times (x = CV_61). The ADC input channel is selected based on the motor's direction (forward or reverse). While measuring, the array with measurement values is sorted using insertion sort. Afterwards, y elements (y = CV_63) from the left (lowest values) and z elements (z = CV_64) from the right (highest values) will be dismissed to mitigate the impact of potential outliers in measurement. The average value of the remaining values will be computed and fed back into the control algorithm. Considering default settings (100us delay, 100 samples, ~2µs sampling time), the complete measurement run, including averaging, takes about 0.3ms to 0.35ms, which effectively reduces the maximum possible duty cycle to about 93% to 94%.
205207

206208
DCC signal decoding
207209
------------------------------

0 commit comments

Comments
 (0)