-
Notifications
You must be signed in to change notification settings - Fork 2
Add encoder calibration documentation #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
anirudhupadhyaya
wants to merge
62
commits into
add-control-content
Choose a base branch
from
add-enc-anirudh
base: add-control-content
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
Show all changes
62 commits
Select commit
Hold shift + click to select a range
084135b
initial commit
anirudhupadhyaya d2652bf
Add content
anirudhupadhyaya 1f1b8a0
Update docs
anirudhupadhyaya d81c691
Update doc
anirudhupadhyaya e0fbf68
Update docs
anirudhupadhyaya cbc72d1
Update docs
anirudhupadhyaya 655f2b1
Update doc
anirudhupadhyaya cbd2100
Update block diagram
anirudhupadhyaya d971d20
Apply suggestions from code review
anirudhupadhyaya 63600c6
Update doc to address review comments
anirudhupadhyaya 3a1ca7b
Add line on low pass filter
anirudhupadhyaya 04c3490
Update source/getting-started/control-with-amdc/encoder-fb/index.md
anirudhupadhyaya 7bdd0aa
Edit background
elsevers c249ab3
Fix file name type-o
elsevers 52556e6
Fix type-os
elsevers 5ac7ce6
Add config instructions
elsevers 1532f0a
Edit first 1/3 of document
elsevers 5b5a78b
add simulink model of pll
elsevers 1086a13
Add pll test files
noguchi-takahiro 93cf84e
Change indexme file
Daehoon-Sung eab8281
Update index.md
Daehoon-Sung 196297a
Edit finding offset and step 1
elsevers b27375c
Edit finding the offset section
elsevers 36971f0
Add encoder angle diagram, first edits of text to use it.
elsevers 8dc006b
Add latex source for motor cross section
elsevers cb1c257
add test code
elsevers d515467
Merge branch 'add-control-content' into add-enc-anirudh
elsevers 41096e6
- Edit everything before finding the offset
elsevers f2ed019
Merge branch 'add-enc-anirudh' into user/Daehoon-Sung/update-offset-r…
elsevers 9e7a82b
change image naming to dash-case
elsevers 600fc24
Improve typesetting around the image
elsevers cc7f038
Add torque characteristic and update step 1 instructions.
elsevers 5e845e7
Make motor cross-section plot 2 poles, add phave v and w axes
elsevers a86055f
Merge branch 'add-enc-anirudh' into user/Daehoon-Sung/update-offset-r…
elsevers d0d86d6
Add clarifying comment to torque characteristic
elsevers 9341c81
Update index.md
Daehoon-Sung fc88ad4
Update the encoder offset plot
Daehoon-Sung 2747e11
Update index.md
Daehoon-Sung 24ff6a8
Update index.md
Daehoon-Sung 4a8698a
Update source/getting-started/control-with-amdc/encoder-fb/index.md
Daehoon-Sung ae4a93f
Update index.md
Daehoon-Sung 99a620f
Update index.md
Daehoon-Sung 783a3a2
Update index.md
Daehoon-Sung 281f09d
Fix rendering of equation
noguchi-takahiro dc92a10
Fix rendering issue of image
noguchi-takahiro 655ec82
Update the encoder image
Daehoon-Sung 0775c96
Merge branch 'user/Daehoon-Sung/update-offset-report' of https://gith…
Daehoon-Sung b5fe0f8
Update index.md
Daehoon-Sung bc7db65
Update the figure
Daehoon-Sung 59b8863
Clarify terminology for mechanical angle in documentation
Daehoon-Sung e0e3223
Enhance encoder offset determination section
Daehoon-Sung 64578a3
Clarify voltage equation with angular velocity note
Daehoon-Sung 5ac71e2
Clarify voltage vector description in index.md
Daehoon-Sung 39163c8
Fix voltage vector equation formatting
Daehoon-Sung b56bbdf
Refine description of encoder offset estimation process
Daehoon-Sung 02d299b
Fix minor grammatical error in encoder offset section
Daehoon-Sung ed8f8ad
Fix formatting in encoder offset determination section
Daehoon-Sung 2d0d0b1
Revise current command notation in encoder equations
Daehoon-Sung 78f9611
Fix rendering issues for images
noguchi-takahiro a826e60
Clarify angle calculation and encoder offset procedure
Daehoon-Sung f28d03d
Revise encoder offset section contents (#146)
elsevers 92cb825
Merge pull request #139 from Severson-Group/user/Daehoon-Sung/update-…
elsevers File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,85 +2,96 @@ | |
|
|
||
| ## Background | ||
|
|
||
| Encoders provide the rotor position feedback to the control system in a motor drive. This document describes a method to convert the raw readings of an encoder into meaningful position information which can be used by the contrl algorithm. Consequently, few techniques to derive the rotor speed from the measured position is also proposed. For more information on how an encoder works and how they may be interfaced with the AMDC please refer to this [document](https://docs.amdc.dev/hardware/subsystems/encoder.html#). | ||
| Encoders provide rotor position feedback to the control system in a motor drive. This document describes a method to convert the raw readings of an encoder into meaningful position information which can be used by the contrl algorithm. Consequently, few techniques to derive the rotor speed from the measured position are also proposed. For more information on how an encoder works and how they may be interfaced with the AMDC please refer to this [document](https://docs.amdc.dev/hardware/subsystems/encoder.html#). | ||
|
|
||
| ## Calibration | ||
|
|
||
| Incremental encoders which are typically used with AMDC have a fixed number of counts per revolution (for example, 1024) and is denoted by `CPR`. The user needs needs to convert the count into usable angular information which maybe used in the code. | ||
| Incremental encoders which are typically used with AMDC have a fixed number of counts per revolution (for example, 1024) and is denoted by `CPR`. The user needs needs to write some code to obtaine the encoder count at a given instance and tconvert the count into usable angular information which can be used within the control code. | ||
anirudhupadhyaya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ### Converting from raw counts to angle information | ||
| ### Obtaining encoder count and translating it into rotor position | ||
|
|
||
| As a first step, the user may use the AMDC `enc` driver function `encoder_get_position()` to get the count of the encoder reading. Next, the user needs to verify if the encoder count is increasing or decreasing with counter-clock wise rotation of shaft. This may be done by manually rotating the shaft, if it is feasible. This document assumes a positive rotor angular position in the counter clockwise (CCW) direction of shaft rotation. Using this information, along with the offset and total encoder counts per revolution, the obtained count can be translated into angular position using a simple linear equation. Care must be taken by the user to ensure that angle is within the bounds of `0` and `2 $\pi$` by appropriately wrapping the variable. | ||
| <img src="./resources/EncoderCodeBlockDiargam.svg" width="100%" align="center"/> | ||
|
|
||
| Example code for when encoder count is increasing with CCW rotation of shaft: | ||
| As a first step, the user may use the AMDC `enc` driver function `encoder_get_position()` to get the count of the encoder reading. Next, the user needs to verify if the encoder count is increasing or decreasing with counter-clock wise rotation of shaft. This may be done by manually rotating the shaft and observing the trend of the reported position with respect to the direction of rotation. This document follows the convention of a positive rotor angle in the counter clockwise (CCW) direction of shaft rotation. Using this information, along with the offset and total encoder counts per revolution, the obtained count can be translated into angular position using a simple linear equation. The user must ensure that angle is within the bounds of 0 and 2 $\pi$ by appropriately wrapping the variable using the `mod` function. | ||
anirudhupadhyaya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Example code to convert encoder to angular position in radians: | ||
| ```C | ||
| double task_get_theta_m(void) | ||
| { | ||
| // Get raw encoder position | ||
| uint32_t position; | ||
| encoder_get_position(&position); | ||
|
|
||
| // Encoder count per revolution | ||
| int ENCODER_COUNT_PER_REV, CCW; | ||
| double enc_theta_m_offset; | ||
|
|
||
| // User to set encoder count per revolution | ||
| ENCODER_COUNT_PER_REV = 1024; | ||
|
|
||
| // Set 1 if encoder count increases with CCW rotation of shaft, Set 0 if encoder count increases with CW rotation of shaft | ||
| CCW = 1; | ||
|
|
||
| // Angular position to be computed | ||
| double theta_m_enc; | ||
|
|
||
| // User to set encoder offset | ||
| enc_theta_m_offset = 100; | ||
|
|
||
| // Convert to radians | ||
| theta_m_enc = (double) PI2 * ( ( (double)position - enc_theta_m_offset )/ (double) ENCODER_COUNT_PER_REV); | ||
|
|
||
| // Wrapping to ensure within bounds | ||
| while (theta_m_enc < 0) { | ||
| theta_m_enc += PI2; | ||
| // Convert to radians | ||
| if (CCW){ | ||
| theta_m_enc = (double) PI2 * ( ( (double)position - enc_theta_m_offset )/ (double) ENCODER_COUNT_PER_REV); | ||
| } | ||
| else{ | ||
| theta_m_enc = (double) PI2 * ( ( (double)ENCODER_COUNT_PER_REV - (double)1 -(double)position + enc_theta_m_offset )/ (double) ENCODER_COUNT_PER_REV); | ||
| } | ||
|
|
||
| // Mod by 2 pi | ||
| theta_m_enc = fmod(theta_m_enc,PI2 ); | ||
| return theta_m_enc; | ||
| } | ||
| ``` | ||
|
|
||
| Example code for when encoder count is decreasing with CCW rotation of shaft: | ||
| ```C | ||
| double task_get_theta_m(void) | ||
| { | ||
| // Get raw encoder position | ||
| uint32_t position; | ||
| encoder_get_position(&position); | ||
|
|
||
| // Encoder count per revolution | ||
| ENCODER_COUNT_PER_REV = 1024; | ||
|
|
||
| // Angular position to be computed | ||
| double theta_m_enc; | ||
| ### Finding the offset | ||
|
||
|
|
||
| enc_theta_m_offset = 100; | ||
| The example code shown above makes uses of an encoder offset value. It is necessary for the user to find this offset experimentally for their machine. For synchronous machines, this offset is the count value measured by the encoder when the d-axis of the rotor is aligned with the phase U winding of the stator. | ||
anirudhupadhyaya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // Convert to radians | ||
| theta_m_enc = (double) PI2 * ( ( (double)ENCODER_COUNT_PER_REV - (double)1 -(double)position + enc_theta_m_offset )/ (double) ENCODER_COUNT_PER_REV); | ||
| To get the rotor to align with the phase U winding, the user may have some current flow through phase U and out of phase V and phase W. This can done by using a DC supply, with phase U connected to the positive terminal and phases V and W connected to the negative terminal. Alternately, the user may also inject some current along the d-axis using the AMDC injection function, but with the rotor position overridden by the user to 0. After obtaining the offset, the user needs to set the variable `enc_theta_m_offset` to the appropirate value in the `task_get_theta_m()` function. | ||
anirudhupadhyaya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| To ensure that the obtained encoder offset is correct, the user may perform additional validation. For a permanent magnet synchronous motor, this can be done as follows: | ||
|
|
||
| // Wrapping to ensure within bounds | ||
| while (theta_m_enc > PI2) { | ||
| theta_m_enc -= PI2; | ||
| } | ||
| return theta_m_enc; | ||
| } | ||
| ``` | ||
| 1. Spin the motor up-to a steady speed under no load conditions | ||
| 1. Measure the d-axis voltage commanded by the current regulator | ||
| 1. Repeat the experiment for a few different motor speeds | ||
| 1. Plot the d-axis voltage against the motor speed | ||
| 1. The d-axis voltage if the offset is tuned correctly, should be close to zero for all speeds. | ||
| 1. In-case there is an error in the offset value, a significant speed dependent voltage will appear on the d-axis voltage | ||
|
|
||
| ### Finding the offset | ||
|
|
||
| The example code shown above makes uses of an encoder offset value. It is necessary for the user to find this offset experimentally for their machine. For synchronous machines, this offset is the count value measured by the encoder when the rotor d-axis is aligned with the phase U of the stator. | ||
|
|
||
| To get the rotor to align with the phase U of stator the user may have some current flow through phase U and out of phase V and phase W. Alternately, the user may also inject some Id current with the AMDC injection function but with the rotot position set to 0. | ||
| ## Computing Speed from Position | ||
|
|
||
| - Converting from raw counts to "theta" | ||
| - Direction: +/- depending on phase connections | ||
| - Sync machines: dq offset | ||
| The user needs to compute a rotor speed signal from the obtained position signal to be used in the control algorithm. There are several ways to do this. A simple and straightforward way to do this would be to compute the discrete time derivative of the position signal in the controller as shown below. This can be referred to as $\Omega_{raw}$. | ||
anirudhupadhyaya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Computing Speed from Position | ||
| $$ | ||
| \Omega_\text{raw}[k] = \frac{\theta_m[k] - \theta_m[k-1]}{T_s} | ||
| $$ | ||
|
|
||
|
|
||
| $\Omega_\text{raw}$ will be a choppy and noisy signal due to the derivative operation. A low pass filter may be applied to this signal as shown below to get a filtered speed, $\Omega_\text{lpf}$. The user may select an appropriate bandwidth, $\omega_b$ for the low pass filter to eliminate the noise introduced by the derivative operation. However, this signal will always be a lagging estimate of the actual rotor speed due to the characterstics of a low pass filter. | ||
anirudhupadhyaya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| $$ | ||
| \Omega_\text{lpf}[k] = \Omega_\text{raw}[k](1 - e^{\omega_b T_s}) + \Omega_\text{lpf}[k-1]e^{\omega_b T_s} | ||
| $$ | ||
|
|
||
| An observer which implements a mechanical model of the rotor as shown below will produce a no-lag estimate of the rotor speed, denoted by $\Omega_\text{sf}$. To implement an observer, the user needs to know the system parameters - `J` - the inertia of the rotor shaft and `b` - the damping coefficient of the rotor shaft. Further, to obtain a no-lag estimate it is necessary to provide the electromechanical torque, $T_{em}$ as input to the mechanical model. The `P-I` part of the observer closes the loop on the speed with $\Omega_\text{raw}$ being the reference input. The recommended tuning approach is as follows: | ||
anirudhupadhyaya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
anirudhupadhyaya marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| $$ | ||
| K_p = \omega_{sf}b, K_i = \omega_{sf}J | ||
| $$ | ||
anirudhupadhyaya marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| - LPF | ||
| - State Filter | ||
| - Observer | ||
| This tuning ensures a pole zero cancellation in the closed transfer function, resulting in a unity transfer function for speed tracking under ideal parameter estimates of `J` and `b` | ||
|
|
||
| Anirudh will added content here... | ||
| <img src="./resources/ObserverFigure.svg" width="100%" align="center"/> | ||
anirudhupadhyaya marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.