From 9658e69c2b129e61f8e66a77c609f60842dd7625 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Wed, 19 Jun 2024 09:36:23 -0600 Subject: [PATCH 01/14] Added initial estimator stucture and overview. --- .../estimator_full_ros_interactions.png | Bin 0 -> 63378 bytes .../estimator_ros_input_output.png | Bin 0 -> 43000 bytes .../controller/controller-general-overview.md | 2 +- .../rosplane/estimator/estimator-base.md | 28 ++++++ .../rosplane/estimator/estimator-example.md | 0 .../rosplane/estimator/estimator-overview.md | 95 ++++++++++++++++++ mkdocs.yml | 4 + 7 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 docs/assets/estimator_assets/estimator_full_ros_interactions.png create mode 100644 docs/assets/estimator_assets/estimator_ros_input_output.png create mode 100644 docs/developer-guide/rosplane/estimator/estimator-base.md create mode 100644 docs/developer-guide/rosplane/estimator/estimator-example.md create mode 100644 docs/developer-guide/rosplane/estimator/estimator-overview.md diff --git a/docs/assets/estimator_assets/estimator_full_ros_interactions.png b/docs/assets/estimator_assets/estimator_full_ros_interactions.png new file mode 100644 index 0000000000000000000000000000000000000000..6ce411896ceb3ff17bf443a5a73a6eab65fb9598 GIT binary patch literal 63378 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 Xlb-P-_DrpTe>#Vb9(-`XI`Dr0Se{=y literal 0 HcmV?d00001 diff --git a/docs/assets/estimator_assets/estimator_ros_input_output.png b/docs/assets/estimator_assets/estimator_ros_input_output.png new file mode 100644 index 0000000000000000000000000000000000000000..a31629a304437509cbc49e691d61672bb6b6314e GIT binary patch literal 43000 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 literal 0 HcmV?d00001 diff --git a/docs/developer-guide/rosplane/controller/controller-general-overview.md b/docs/developer-guide/rosplane/controller/controller-general-overview.md index 6d8f607..d8c2210 100644 --- a/docs/developer-guide/rosplane/controller/controller-general-overview.md +++ b/docs/developer-guide/rosplane/controller/controller-general-overview.md @@ -83,7 +83,7 @@ A table of arguments and parameter files that work out of the box is given in th !!! note Filepaths will need to be altered to work. !!! note - The most common way of running the controller is in through a launch file with the rest of the ROSplane pipeline running as well. + The most common way of running the controller is through a launch file with the rest of the ROSplane pipeline running as well. See the ROSplane Overview in the Developer and User Guides for more details. diff --git a/docs/developer-guide/rosplane/estimator/estimator-base.md b/docs/developer-guide/rosplane/estimator/estimator-base.md new file mode 100644 index 0000000..3af1e74 --- /dev/null +++ b/docs/developer-guide/rosplane/estimator/estimator-base.md @@ -0,0 +1,28 @@ +# Estimator Base + +## Overview + +The estimator base implements the basic ROS interfaces for the estimator. +This includes setting up subscribers, publishers and initializing parameter management. +The idea of the base class, is that all interfacing with ROS and shared resources across all inheritance levels happens or are contained in this class. + +## ROS Interfaces + +The estimator has the following ROS interfaces. + +| ![Diagram of Estimator ROS Sensors](../../../assets/estimator_assets/estimator_ros_input_output.png "Estimator ROS Sensors") | +|:--:| +|*Figure 1: Estimator's ROS interactions.*| + +The estimator has several ROS interfaces that are tracked as member variables of the `estimator_base` class. +They are summarized in the table below: + +| ROS Interface | Topic | Explanation | Message Type | +|:------:|:-------:| :---: | :---: | +|
`vehicle_state_pub_`
| `/estimated_state` | Publishes the estimated state of teh vehicle. | State.msg | +|
`gnss_fix_sub_`
| `/navsat_compat/fix` | Subcribes to the GNSS position information. | NavSatFix.msg | +|
`gnss_vel_sub_`
| `/navsat_compat/vel` | Subcribes to the GNSS velocity information. | TwistStamped.msg | +|
`imu_sub_`
| `/imu/data` | Subcribes to the IMU data (both Gyro and Accel). | Imu.msg | +|
`baro_sub_`
| `/baro` | Subcribes to the barometer pressure information. | Barometer.msg | +|
`airspeed_sub_`
| `/airspeed` | Subcribes to the differential pressure information. | Airspeed.msg | +|
`status_sub_`
| `/status` | Subcribes to the aircraft status information. | Status.msg | diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/developer-guide/rosplane/estimator/estimator-overview.md b/docs/developer-guide/rosplane/estimator/estimator-overview.md new file mode 100644 index 0000000..5006d8c --- /dev/null +++ b/docs/developer-guide/rosplane/estimator/estimator-overview.md @@ -0,0 +1,95 @@ +# Estimator Overview + +## Overview + +The estimator is a continuous-discrete Kalman Filter, a full treatment of the filter is found in section 8.5 of the [UAV book](https://github.com/randybeard/mavsim_public). +This filter essentially works by inverting a few sensor models and then using a two stage estimation of first the attitude and then the position state values. +This page will outline the states, their meaning and any general notes on the states. +For a more in depth look at which states are estimated in which way visit the [Estimator Base](./estimator-base.md) and [Estimator Example](./estimator-example.md) pages. + +## ROS Interactions + +The estimator takes in sensor information from `rosflight_io` computes an estimate and publishes it to the rest of ROSplane. + + +| ![Diagram of Estimator ROS Interactions](../../../assets/estimator_assets/estimator_ros_input_output.png "Diagram of Estimator ROS Interactions") | +|:--:| +|*Figure 1: ROS network interactions for the estimator.*| + +### Input + +The inputs to the estimator are, accelerometer, rate gyro, barometer, differential pressure, GPS position, and GPS velocity estimates. +The table with the topic for each of the measures is below. + +| Measure | Explanation | Topic | +|:------:|:-------:| :---: | +| Accelerometer | This measures the specfic force applied to the aircraft in the body frame axes (see section 7.1 in the UAV book for more details). | `/imu/data/linear_acceleration` | +| Rate Gyro | This measures the angular velocity of the aircraft around the body frame axes. | `/imu/data/angular_velocity` | +| Barometer | The barometer measures the ambient air pressure. It is calibrated on arm to establish a "zero" altitude measurement. | `/baro/pressure` | +| Differential Pressure | The differential pressure sensor, measures the difference in pressure using a pitot tube due to forward velocity. | `/airspeed/differential_pressure` | +| GNSS Position | GNSS postion gives the position of the aircraft in latitude, longitude and altitude. | `/navsat_compat/fix` | +| GNSS Velocity | GNSS velocity gives the velocity of the aircraft in meters per second in the global NED frame. | `/navsat_compat/vel` | +| Status | Indicates whether the aircraft is armed (indicating a need to initialized position and altitude estimates). | `/status` | + +These topics provide the measures that are fused to create a state estimate. + +| ![Diagram of Estimator ROS IO](../../../assets/estimator_assets/estimator_ros_input_output.png "Diagram of Estimator ROS IO") | +|:--:| +|*Figure 1: ROS topic subscriptions and publications for the estimator.*| + +## Output + +Their are 20 states estimated by the estimator that are published to the rest of ROSplane. +These states cover the position, orientation and aerodynamic information for the aircraft. +There are more than 20 states listed in the following table, but this is because either Euler angles or quaternions can be used to express orientation. +Below is a table of the `/estimated_state` message and what each of the fields represents. +See the Frames and Derivation page for more information, or chapter 2 of the [UAV book](https://github.com/randybeard/mavsim_public). + +| State | Explanation | Range/Type/Units | +|:--:|:--:|:--:| +| postion[3] | A 3 vector of the NED position of the aircraft. | $(-\infty , \infty)$ (float)(meters) | +| va | The airspeed of the aircraft. Always positive because it is the magnitude. | $(0 , \infty)$ (float)(meters/second) | +| alpha | The angle of attack of the aircraft wing. | $(-\pi, \pi)$ (float)(radians) | +| beta | The side-slip angle of the aircraft. | $(-\pi, \pi)$ (float)(radians) | +| phi | The roll angle of the aircraft. | $(-\pi, \pi)$ (float)(radians) | +| theta | The pitch angle of the aircraft. | $(-\pi, \pi)$ (float)(radians) | +| psi | The yaw angle of the aircraft. | $(-\pi, \pi)$ (float)(radians) | +| chi | The course angle of the aircraft. | $(-\pi, \pi)$ (float)(radians) | +| u | The velocity in the body x axis. | $(-\infty, \infty)$ (float)(meters/second) | +| v | The velocity in the body y axis. | $(-\infty, \infty)$ (float)(meters/second) | +| w | The velocity in the body z axis. | $(-\infty, \infty)$ (float)(meters/second) | +| p | The angular velocity about the body x axis (rollrate). | $(-\infty, \infty)$ (float)(radians/second) | +| q | The angular velocity about the body y axis (pitchrate). | $(-\infty, \infty)$ (float)(radians/second) | +| r | The angular velocity about the body z axis (yawrate). | $(-\infty, \infty)$ (float)(radians/second) | +| vg | The groundspeed of the aircraft. Always positive because it is the magnitude. | $(0 , \infty)$ (float)(meters/second) | +| wn | The global north velocity of the wind. | $(-\infty , \infty)$ (float)(meters/second) | +| we | The global east velocity of the wind. | $(-\infty , \infty)$ (float)(meters/second) | +| _ | **The following entries are optional.** | _ | +| quat[4] | A 4 vector of the quaternion describing the orientation. | $(-1 , 1)$ (float) | +| quat_valid | A flag indicating whether the data in the quat entry is valid.| True/False (bool) | +| psi_deg | The yaw angle of the aircraft in degrees. | $(-180, 180)$ (float)(degrees) | +| chi_deg | The course angle of the aircraft in degrees. | $(-180, 180)$ (float)(degrees) | +| init_lat | The latitude of the aircraft when first armed. | $(-90, 90)$ (float)(DDS) | +| init_long | The longitude of the aircraft when first armed. | $(-180, 180)$ (float)(DDS) | +| init_alt | The altitude of the aircraft when first armed. | $(0, \infty)$ (float)(meters) | + +!!! note + More states may be estimated in the estimator than listed, these states are just those useful to other parts of ROSplane. + +## Running the Estimator + +The estimator is in the main `rosplane` ROS package. +The ROS executable is `rosplane_estimator_node`, yielding the run command: + +`ros2 run rosplane rosplane_estimator_node` + +To pass a set of parameters for the controller from a yaml file using the `--ros-args` option. + +`ros2 run rosplane rosplane_estimator_node --ros-args --params-file path/to/params.yaml` + + +!!! note + Filepaths will need to be altered to work. +!!! note + The most common way of running the estimator is through a launch file with the rest of the ROSplane pipeline running as well. + See the ROSplane Overview in the Developer and User Guides for more details. diff --git a/mkdocs.yml b/mkdocs.yml index 798ae44..484053b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -77,6 +77,10 @@ nav: - Controller State Machine: developer-guide/rosplane/controller/controller-state-machine.md - Successive Loop Closure Controller Outline: developer-guide/rosplane/controller/controller-outline.md - Total Energy Controller: developer-guide/rosplane/controller/controller-total-energy.md + - Estimator: + - Estimator Overview: developer-guide/rosplane/estimator/estimator-overview.md + - Estimator Base: developer-guide/rosplane/estimator/estimator-base.md + - Estimator Example: developer-guide/rosplane/estimator/estimator-example.md - Parameter Management: developer-guide/rosplane/parameter-management.md - Path Planning: - Path Planning Overview: developer-guide/rosplane/path-planning/path-planning-overview.md From 688983cea8069abf7da741fbaaddaf7e31bc3f55 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Wed, 19 Jun 2024 12:39:39 -0600 Subject: [PATCH 02/14] Added propgation documentation for the estimator. --- .../rosplane/estimator/estimator-base.md | 13 +++ .../rosplane/estimator/estimator-example.md | 92 +++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/docs/developer-guide/rosplane/estimator/estimator-base.md b/docs/developer-guide/rosplane/estimator/estimator-base.md index 3af1e74..4bf6976 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-base.md +++ b/docs/developer-guide/rosplane/estimator/estimator-base.md @@ -26,3 +26,16 @@ They are summarized in the table below: |
`baro_sub_`
| `/baro` | Subcribes to the barometer pressure information. | Barometer.msg | |
`airspeed_sub_`
| `/airspeed` | Subcribes to the differential pressure information. | Airspeed.msg | |
`status_sub_`
| `/status` | Subcribes to the aircraft status information. | Status.msg | + +!!! note + The NavSatFix, TwistStamped and Imu messages are from standard ROS message packages. Barometer, Airspeed and Status messages are from `rosflight_msgs`. + +## Parameters + +Update when all estimator params are implemented. + +## Modifying the Estimator + +Update when full state estimator and continuous-discrete are both implemented and a swap between them works. + + diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index e69de29..c662764 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -0,0 +1,92 @@ +# Estimator Example + + + +## Overview + +The `estimator_example` class implements a continuous-discrete Kalman filter as described in section 8.5 of the [UAV book](https://github.com/randybeard/mavsim_public) or 8.6 and 8.7 of volume one of the same book. +It utilizes a two stage estimation process along with low pass filtering the inversion of a few sensor models and direct measures. +The roll and pitch of the aircraft are estimated first, this is called the attitude estimation step though not all of the attitude is estimated here. +The other states are then estimated as a whole, this is called the position estimation step, though more than position is estimated during this step. +The estimator runs on a set timer with a configurable frequency (see Parameters section for details). + +## Nomenclature + +| Symbol | Meaning | Range | +|:------:|:-------:| :---: | +|$\large{\chi}$| Course/Heading | $[-\pi,\pi)$ | +|$\large{\phi}$| Roll | $[-\pi,\pi)$ | +|$\large{\theta}$| Theta | $[-\pi,\pi)$ | +|$\large{\psi}$| Yaw | $[-\pi,\pi)$ | +|$\large{h}$| Altitude | - | +|$\large{p}$| Roll Rate | - | +|$\large{q}$| Pitch Rate | - | +|$\large{r}$| Yaw Rate | - | +|$\large{V_a}$| Airspeed | $\geq 0$ | + +## Sensor Model Inversion + +The roll, pitch and yaw rates are directly measured by the rate gyro and low pass filtered. +The low pass filter is a simple alpha filter described by: + +$$ + a_{n} = a_{n-1} \alpha + (1 - \alpha) a_{measured} +$$ + +Where $a$ is the state. +This filter technique is used on the measurements before they are used in an estimate throughout the estimator. + +The following are calculated directly from a model of the sensor: + +
+ +| State | Measured Value | Model Equation | Inversion Equation | +|:--:|:--:|:--:|:--:| +| $h$ - altitude | $P$ - absolute pressure (Pa) | $P = \rho_{air} gh$ | $h = \frac{\rho_{air} g}{P}$| +| $V_a$ - airspeed | $\Delta P$ - differential pressure (Pa) | $\Delta P = \frac{1}{2} \rho_{air} V_a^2$ | $V_a = \sqrt{\frac{2}{\rho_{air} g} \Delta P}$| + +
+ +These values are then used in the first step of the estimator. + +## Attitude Estimation + +### Propagation + +At each call of the estimation algorithm, the estimate from the previous time step is propagated to the next time step. +It is propagated a number of times, `N_`, to yield and estimate for the current time step. +`N_` is typically 10, meaning that the previous estimate that was updated by a measurement is updated in 10 steps to get what the estimate at the current time step. +The attitude estimation is propagated according to the equations: + +$$ + \dot{\phi} = p + (q \sin{\phi} + r \cos{\phi}) \tan{\theta} \\ + \dot{\theta} = q \cos{\phi} + r \sin{\phi}) +$$ + +This is called `f_a_` in the code. + +This propagated estimate is then used in the calculation of the Jacobian. +The Jacobian matrix, `A_a_` is: + +\begin{bmatrix} + (q \cos{\phi} - r \sin{\phi})\tan{\theta} & \frac{q\sin{\phi} + r\cos{phi}}{\cos^2{\theta}} \\ + 0 & -q \sin{\phi} - r \cos{\phi} \\ +\end{bmatrix} + +This Jacobian is then used to find a second-order approximation of the matrix exponential, `A_d_`. +`A_d_` is then used to propagate the actual covariance of the estimate. + +The process noise due to model uncertainty is defined in the matrix `Q_a_`, but the process uncertainty due to the use of the rate gyro measures has not been adjusted for yet. +This is done with the use of the matrix `G` which takes into account the Coriolis effects of the measures. +The measurement variance is transformed into process noise due to gyro measures. +All of these contribute into finding the current covariance of our estimate, `P_a_`. +This is done by the following equation: + +`P_a_ = A_d_ * P_a_ * A_d_.transpose() + (Q_a_ + G * Q_g_ * G.transpose()) * pow(Ts/N_,2)` + +Where `Ts` is the time step between measurement updates. +With this propagated estimate and covariance we are now ready for a measurement update. + +### Measurement Update + + From 01f569d5728e0e1165ad9384e53a321832ba225a Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Thu, 20 Jun 2024 11:38:33 -0600 Subject: [PATCH 03/14] Finished first draft of attitude estimation. --- .../rosplane/estimator/estimator-example.md | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index c662764..a1f872e 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -5,6 +5,7 @@ ## Overview The `estimator_example` class implements a continuous-discrete Kalman filter as described in section 8.5 of the [UAV book](https://github.com/randybeard/mavsim_public) or 8.6 and 8.7 of volume one of the same book. +Specifically this is using algorithm 2 of chapter 8 in Volume 1. It utilizes a two stage estimation process along with low pass filtering the inversion of a few sensor models and direct measures. The roll and pitch of the aircraft are estimated first, this is called the attitude estimation step though not all of the attitude is estimated here. The other states are then estimated as a whole, this is called the position estimation step, though more than position is estimated during this step. @@ -51,6 +52,10 @@ These values are then used in the first step of the estimator. ## Attitude Estimation +The first step in estimating the attitude is understanding how we propagate our guess between measurements. +Our estimates are on roll angle, $\phi$, and on pitch angle, $\theta$. +These estimates are part of the state $\hat{x}_a$, where the hat over the variable indicates an estimate. + ### Propagation At each call of the estimation algorithm, the estimate from the previous time step is propagated to the next time step. @@ -89,4 +94,70 @@ With this propagated estimate and covariance we are now ready for a measurement ### Measurement Update +A measurement update provides a check on our estimate and we take this new information and fuse it into our estimate. +The Kalman filter allows us to optimally adjust our estimate given the measurement, our tuned process noises and the noise characteristics of our sensor. +These noise characteristics are captured in a diagonal matrix, $R_{sensor}$. + +Using our estimate and a model set of equations $h$, we predict the measurements the accelerometer will produce. +We will then compare the actual and predicted measures and adjust our estimate optimally to the new information. +The set of equations, $h$, that predict the 3 measurements of the accelerometer, $y$, is given by: + +\begin{equation} + h = + \begin{bmatrix} + q V_a \sin{\theta} + g \sin{\theta} \\ + r V_a \cos{\theta} - p V_a \sin{\theta} - g \cos{\theta} \sin{\phi} \\ + -q V_a \cos{\theta} - g \cos{\theta} \cos{\phi} \\ + \end{bmatrix} +\end{equation} + +This yields a Jacobian $C$: + +\begin{equation} + C = + \begin{bmatrix} + 0 & q V_a \cos{\theta} + g \cos{\theta} \\ + -g \cos{\phi}\cos{\theta} & -r V_a \sin{\theta} - p V_a \cos{\theta} + g \sin{\phi} \sin{theta} \\ + g \sin{\phi}\cos{\theta} & (q V_a + g \cos{\phi}) \sin{\theta} + \end{bmatrix} +\end{equation} + +Which is used in finding the Kalman gain $L$. +An intermediate value is calculated called d $S^{-1}$. +This value is: + +\begin{equation} + S^{-1} = (R_{accel} + CPC^\top)^{-1} +\end{equation} + +This intermediate value is then used to find $L$: + +\begin{equation} + L = PC^\top S^{-1} +\end{equation} + +The optimum estimate is then found: + +\begin{equation} + \hat{x}_a^+ = \hat{x}_a^- + L (y - h) +\end{equation} + +Finally, we update the covariance from our new estimate: + +\begin{equation} + P^+ = (I - LC) P^- (I - LC)^\top + LR_{accel}L^\top +\end{equation} + +We repeat this cycle until termination of the program. +This estimation scheme split into two parts allows for a clear set of equations and how the estimates affect one another. +We will now move on to the next portion of the estimator that estimates the rest of the states. + +## Position Estimation + +The position estimation step follows the same algorithm as previous. +Only new values are used for each of the matrices. +Those new entries are shown here, but reference the previous section for details on implementation. + +### Propagation + From e17735f79194b5abf4a39d082c5f82516245f9e1 Mon Sep 17 00:00:00 2001 From: JMoore5353 Date: Thu, 20 Jun 2024 12:50:23 -0600 Subject: [PATCH 04/14] initial look over --- .../rosplane/estimator/estimator-example.md | 33 +++++++++++-------- .../rosplane/estimator/estimator-overview.md | 6 ++-- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index a1f872e..65b48b6 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -5,10 +5,13 @@ ## Overview The `estimator_example` class implements a continuous-discrete Kalman filter as described in section 8.5 of the [UAV book](https://github.com/randybeard/mavsim_public) or 8.6 and 8.7 of volume one of the same book. -Specifically this is using algorithm 2 of chapter 8 in Volume 1. -It utilizes a two stage estimation process along with low pass filtering the inversion of a few sensor models and direct measures. -The roll and pitch of the aircraft are estimated first, this is called the attitude estimation step though not all of the attitude is estimated here. -The other states are then estimated as a whole, this is called the position estimation step, though more than position is estimated during this step. +Specifically, this estimator uses algorithm 2 of chapter 8 in Volume 1. +It utilizes a two stage estimation process along with low pass filtering the inversion of a few sensor models and direct measurements. +The roll and pitch of the aircraft are estimated first. +This is called the attitude estimation step though not all of the attitude is estimated here. + +The other states are then estimated as a whole. +This is called the position estimation step, though more than just position is estimated during this step. The estimator runs on a set timer with a configurable frequency (see Parameters section for details). ## Nomenclature @@ -59,8 +62,10 @@ These estimates are part of the state $\hat{x}_a$, where the hat over the variab ### Propagation At each call of the estimation algorithm, the estimate from the previous time step is propagated to the next time step. -It is propagated a number of times, `N_`, to yield and estimate for the current time step. -`N_` is typically 10, meaning that the previous estimate that was updated by a measurement is updated in 10 steps to get what the estimate at the current time step. +The propagation step is broken up into `N_` smaller steps to yield an estimate for the current time step. +`N_` is typically 10, meaning that the previous estimate that was updated by a measurement is updated in 10 steps instead of a single step to calculate the estimate at the current time step. +The length of each of the `N_` steps is 1/`N_` the original time step. + The attitude estimation is propagated according to the equations: $$ @@ -81,9 +86,9 @@ The Jacobian matrix, `A_a_` is: This Jacobian is then used to find a second-order approximation of the matrix exponential, `A_d_`. `A_d_` is then used to propagate the actual covariance of the estimate. -The process noise due to model uncertainty is defined in the matrix `Q_a_`, but the process uncertainty due to the use of the rate gyro measures has not been adjusted for yet. -This is done with the use of the matrix `G` which takes into account the Coriolis effects of the measures. -The measurement variance is transformed into process noise due to gyro measures. +The process noise due to model uncertainty is defined in the matrix `Q_a_`, but the process uncertainty due to the use of the rate gyro measurements has not been adjusted for yet. +This is done with the use of the matrix `G` which takes into account the Coriolis effects of the measurements. +The measurement variance is transformed into process noise due to gyro measurements. All of these contribute into finding the current covariance of our estimate, `P_a_`. This is done by the following equation: @@ -94,12 +99,12 @@ With this propagated estimate and covariance we are now ready for a measurement ### Measurement Update -A measurement update provides a check on our estimate and we take this new information and fuse it into our estimate. -The Kalman filter allows us to optimally adjust our estimate given the measurement, our tuned process noises and the noise characteristics of our sensor. +A measurement update provides a check on our propagated estimate and we take this new information and fuse it into our estimate. +The Kalman filter allows us to optimally adjust our estimate, our tuned process noises, and the noise characteristics of our sensor given the measurement. These noise characteristics are captured in a diagonal matrix, $R_{sensor}$. Using our estimate and a model set of equations $h$, we predict the measurements the accelerometer will produce. -We will then compare the actual and predicted measures and adjust our estimate optimally to the new information. +We will then compare the actual and predicted measurements and optimally adjust our estimate with the new information. The set of equations, $h$, that predict the 3 measurements of the accelerometer, $y$, is given by: \begin{equation} @@ -123,7 +128,7 @@ This yields a Jacobian $C$: \end{equation} Which is used in finding the Kalman gain $L$. -An intermediate value is calculated called d $S^{-1}$. +An intermediate value is calculated called $S^{-1}$. This value is: \begin{equation} @@ -136,7 +141,7 @@ This intermediate value is then used to find $L$: L = PC^\top S^{-1} \end{equation} -The optimum estimate is then found: +The optimal estimate is then found: \begin{equation} \hat{x}_a^+ = \hat{x}_a^- + L (y - h) diff --git a/docs/developer-guide/rosplane/estimator/estimator-overview.md b/docs/developer-guide/rosplane/estimator/estimator-overview.md index 5006d8c..f67909f 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-overview.md +++ b/docs/developer-guide/rosplane/estimator/estimator-overview.md @@ -29,7 +29,7 @@ The table with the topic for each of the measures is below. | Differential Pressure | The differential pressure sensor, measures the difference in pressure using a pitot tube due to forward velocity. | `/airspeed/differential_pressure` | | GNSS Position | GNSS postion gives the position of the aircraft in latitude, longitude and altitude. | `/navsat_compat/fix` | | GNSS Velocity | GNSS velocity gives the velocity of the aircraft in meters per second in the global NED frame. | `/navsat_compat/vel` | -| Status | Indicates whether the aircraft is armed (indicating a need to initialized position and altitude estimates). | `/status` | +| Status | Indicates whether the aircraft is armed (indicating a need to initialize position and altitude estimates). | `/status` | These topics provide the measures that are fused to create a state estimate. @@ -39,10 +39,10 @@ These topics provide the measures that are fused to create a state estimate. ## Output -Their are 20 states estimated by the estimator that are published to the rest of ROSplane. +There are 20 states estimated by the estimator that are published to the rest of ROSplane. These states cover the position, orientation and aerodynamic information for the aircraft. -There are more than 20 states listed in the following table, but this is because either Euler angles or quaternions can be used to express orientation. Below is a table of the `/estimated_state` message and what each of the fields represents. +Note that there are more than 20 states listed in the following table, but this is because either Euler angles or quaternions can be used to express orientation. See the Frames and Derivation page for more information, or chapter 2 of the [UAV book](https://github.com/randybeard/mavsim_public). | State | Explanation | Range/Type/Units | From 2964e547395fa5bcc6d438d4324052357c61fb03 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Thu, 20 Jun 2024 14:51:17 -0600 Subject: [PATCH 05/14] Changed the code snippets to latex equations. --- .../rosplane/estimator/estimator-example.md | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index 65b48b6..9ad57d5 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -9,8 +9,7 @@ Specifically, this estimator uses algorithm 2 of chapter 8 in Volume 1. It utilizes a two stage estimation process along with low pass filtering the inversion of a few sensor models and direct measurements. The roll and pitch of the aircraft are estimated first. This is called the attitude estimation step though not all of the attitude is estimated here. - -The other states are then estimated as a whole. +The other states are then estimated as a all at once. This is called the position estimation step, though more than just position is estimated during this step. The estimator runs on a set timer with a configurable frequency (see Parameters section for details). @@ -63,38 +62,46 @@ These estimates are part of the state $\hat{x}_a$, where the hat over the variab At each call of the estimation algorithm, the estimate from the previous time step is propagated to the next time step. The propagation step is broken up into `N_` smaller steps to yield an estimate for the current time step. -`N_` is typically 10, meaning that the previous estimate that was updated by a measurement is updated in 10 steps instead of a single step to calculate the estimate at the current time step. -The length of each of the `N_` steps is 1/`N_` the original time step. +$N$ is typically 10, meaning that the previous estimate that was updated by a measurement is updated in 10 steps instead of a single step to calculate the estimate at the current time step. +The length of each of the $N$ steps is 1/$N$ the original time step. -The attitude estimation is propagated according to the equations: +The attitude estimation is propagated according to the model $f$: -$$ - \dot{\phi} = p + (q \sin{\phi} + r \cos{\phi}) \tan{\theta} \\ - \dot{\theta} = q \cos{\phi} + r \sin{\phi}) -$$ +\begin{equation} + f = + \begin{bmatrix} + \dot{\phi} = p + (q \sin{\phi} + r \cos{\phi}) \tan{\theta} \\ + \dot{\theta} = q \cos{\phi} + r \sin{\phi}) + \end{bmatrix} +\end{equation} -This is called `f_a_` in the code. +This propagated estimate is then used in the calculation of the Jacobian $A$. -This propagated estimate is then used in the calculation of the Jacobian. -The Jacobian matrix, `A_a_` is: +\begin{equation} + A = + \begin{bmatrix} + (q \cos{\phi} - r \sin{\phi})\tan{\theta} & \frac{q\sin{\phi} + r\cos{phi}}{\cos^2{\theta}} \\ + 0 & -q \sin{\phi} - r \cos{\phi} \\ + \end{bmatrix} +\end{equation} -\begin{bmatrix} - (q \cos{\phi} - r \sin{\phi})\tan{\theta} & \frac{q\sin{\phi} + r\cos{phi}}{\cos^2{\theta}} \\ - 0 & -q \sin{\phi} - r \cos{\phi} \\ -\end{bmatrix} +This Jacobian is then used to find a second-order approximation of the matrix exponential, $A_d$. + +\begin{equation} + A_d = I + \frac{T_s}{N} A + \frac{1}{2} \frac{T_s^2}{N^2} A^2 +\end{equation} -This Jacobian is then used to find a second-order approximation of the matrix exponential, `A_d_`. -`A_d_` is then used to propagate the actual covariance of the estimate. +Where $T_s$ is the length of a time step. +$A_d$ is then used to propagate the actual covariance of the estimate. -The process noise due to model uncertainty is defined in the matrix `Q_a_`, but the process uncertainty due to the use of the rate gyro measurements has not been adjusted for yet. -This is done with the use of the matrix `G` which takes into account the Coriolis effects of the measurements. +The process noise due to model uncertainty is defined in the matrix $Q$, but the process uncertainty due to the use of the rate gyro measurements $Q_g$, has not been adjusted for yet. +This is done with the use of the matrix $G$ which takes into account the Coriolis effects of the gyro measurements. The measurement variance is transformed into process noise due to gyro measurements. -All of these contribute into finding the current covariance of our estimate, `P_a_`. +All of these contribute into finding the current covariance of our estimate, $P$. This is done by the following equation: -`P_a_ = A_d_ * P_a_ * A_d_.transpose() + (Q_a_ + G * Q_g_ * G.transpose()) * pow(Ts/N_,2)` +$$P_a = A_d P A_d^\top + (Q + G Q_g G^\top) \frac{T_s^2}{N^2}$$ -Where `Ts` is the time step between measurement updates. With this propagated estimate and covariance we are now ready for a measurement update. ### Measurement Update From 602d724bd101992f0ee58aeef85a7f3fa4b93089 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Thu, 20 Jun 2024 15:16:23 -0600 Subject: [PATCH 06/14] Added the propgation documentation for the position step. --- .../rosplane/estimator/estimator-example.md | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index 9ad57d5..599b0af 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -61,7 +61,7 @@ These estimates are part of the state $\hat{x}_a$, where the hat over the variab ### Propagation At each call of the estimation algorithm, the estimate from the previous time step is propagated to the next time step. -The propagation step is broken up into `N_` smaller steps to yield an estimate for the current time step. +The propagation step is broken up into $N$ smaller steps to yield an estimate for the current time step. $N$ is typically 10, meaning that the previous estimate that was updated by a measurement is updated in 10 steps instead of a single step to calculate the estimate at the current time step. The length of each of the $N$ steps is 1/$N$ the original time step. @@ -172,4 +172,56 @@ Those new entries are shown here, but reference the previous section for details ### Propagation +The attitude estimation is propagated according to the model $f$: + +\begin{equation} + f = + \begin{bmatrix} + V_g \cos{\chi} \\ + V_g \sin{\chi} \\ + \dot{V_g} \\ + 0 \\ + 0 \\ + \dot{\psi} \\ + \end{bmatrix} +\end{equation} + +Where, + +\begin{equation} + \dot{\psi} = q \sin{\phi} + r \frac{\cos{\phi}}{\cos{\theta}} \\ + \dot{V_g} = \frac{V_a}{V_g} \dot{\psi} (w_e \cos{\psi} - w_n \sin{\psi}) +\end{equation} + +This propagated estimate is then used in the calculation of the Jacobian $A$. + +\begin{equation} + A = + \begin{bmatrix} + 0 & 0 & \cos{\chi} & -V_g \sin{\chi} & 0 & 0 & 0 \\ + 0 & 0 & \sin{\chi} & V_g \cos{\chi} & 0 & 0 & 0 \\ + 0 & 0 & -\frac{\dot{V_g}}{V_g} & 0 & -\dot{\psi} V_a \frac{\sin{\psi}}{V_g} & \dot{\psi} V_a \frac{\cos{\psi}}{V_g} & -\dot{\psi} V_a (w_n \cos{\psi} + w_e \sin{\psi}) \\ + 0 & 0 & -\frac{g}{V_g^2} \tan{\phi} & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ + \end{bmatrix} +\end{equation} +This Jacobian is then used to find a second-order approximation of the matrix exponential, $A_d$. + +\begin{equation} + A_d = I + \frac{T_s}{N} A + \frac{1}{2} \frac{T_s^2}{N^2} A^2 +\end{equation} + +Where $T_s$ is the length of a time step. +$A_d$ is then used to propagate the actual covariance of the estimate. + +The process noise due to model uncertainty is defined in the matrix $Q$ and is fused into the covariance. +This is done by the following equation: + +$$P_a = A_d P A_d^\top + Q \frac{T_s^2}{N^2}$$ + +With this propagated estimate and covariance we are now ready for a measurement update. + +### Measurement Update From f21adca427d3ff0f1fb493adc73051abc7d26c85 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Thu, 20 Jun 2024 15:54:44 -0600 Subject: [PATCH 07/14] Added the measurement update documentation for the positiion step. --- .../rosplane/estimator/estimator-example.md | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index 599b0af..bf9e024 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -13,6 +13,8 @@ The other states are then estimated as a all at once. This is called the position estimation step, though more than just position is estimated during this step. The estimator runs on a set timer with a configurable frequency (see Parameters section for details). + + ## Nomenclature | Symbol | Meaning | Range | @@ -109,9 +111,20 @@ With this propagated estimate and covariance we are now ready for a measurement A measurement update provides a check on our propagated estimate and we take this new information and fuse it into our estimate. The Kalman filter allows us to optimally adjust our estimate, our tuned process noises, and the noise characteristics of our sensor given the measurement. These noise characteristics are captured in a diagonal matrix, $R_{sensor}$. +The entries are the variances and for the attitude step this is defined as: + +\begin{equation} + R_{accel} = + \begin{bmatrix} + \sigma_{accel, x}^2 & 0 & 0 \\ + 0 & \sigma_{accel, y}^2 & 0 \\ + 0 & 0 & \sigma_{accel, z}^2 \\ + \end{bmatrix} +\end{equation} Using our estimate and a model set of equations $h$, we predict the measurements the accelerometer will produce. We will then compare the actual and predicted measurements and optimally adjust our estimate with the new information. +Since measurements come in much faster than the model propagates the measurement step is run every time the propagated estimate is calculated. The set of equations, $h$, that predict the 3 measurements of the accelerometer, $y$, is given by: \begin{equation} @@ -225,3 +238,84 @@ $$P_a = A_d P A_d^\top + Q \frac{T_s^2}{N^2}$$ With this propagated estimate and covariance we are now ready for a measurement update. ### Measurement Update + + + +Because the GPS measures come in slower than the model propagates, the measurement step is only run when their is new GPS information. +This process is identical to the measurement update in the attitude step. +This will likely change before release, but the only difference is that it is done one measurement at a time. +This has advantages for querying the values while debugging, but is on the whole less clear and is more error prone. +The math is the same but it is carried through, and expressed as the final sum and each row calculated separately. + +The measurement model, $h$ has only 6 entries instead of 7 since heading, $\psi$ is not measured. +A digital compass could be added and $h$ and $C$ expanded if desired, but control is operated on course, $\chi$, so this proves largely unnecessary. + +\begin{equation} + h = + \begin{bmatrix} + p_n \\ + p_e \\ + V_g \\ + \chi \\ + V_a \cos{\psi} + w_n - V_g \cos{\chi} \\ + V_a \sin{\psi} + w_e - V_g \sin{\chi} \\ + \end{bmatrix} +\end{equation} + +This yields a Jacobian $C$: + +\begin{equation} + C = + \begin{bmatrix} + 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ + 0 & 0 & -\cos{\chi} & V_g\sin{\chi} & 1 & 0 & -V_a\sin{\psi} \\ + 0 & 0 & -\sin{\chi} & -V_g\cos{\chi} & 0 & 1 & V_a\cos{\psi} \\ + \end{bmatrix} +\end{equation} + +Which is used in finding the Kalman gain $L$. + +The measurement noise matrix, $R_{position}$, is defined as: + +\begin{equation} + R_{position} = + \begin{bmatrix} + \sigma_{gps, n}^2 & 0 & 0 & 0 & 0 & 0 & 0 \\ + 0 & \sigma_{gps, e}^2 & 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & \sigma_{gps, V_g}^2 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & \sigma_{gps, \chi}^2 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 0 & \sigma_{psuedo, w_n}^2 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & \sigma_{psuedo, w_n}^2 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & \sigma_{psuedo, \psi}^2 \\ + \end{bmatrix} +\end{equation} + +An intermediate value is calculated called $S^{-1}$. +This value is: + +\begin{equation} + S^{-1} = (R_{position} + CPC^\top)^{-1} +\end{equation} + +This intermediate value is then used to find $L$: + +\begin{equation} + L = PC^\top S^{-1} +\end{equation} + +The optimal estimate is then found: + +\begin{equation} + \hat{x}_a^+ = \hat{x}_a^- + L (y - h) +\end{equation} + +Finally, we update the covariance from our new estimate: + +\begin{equation} + P^+ = (I - LC) P^- (I - LC)^\top + LR_{accel}L^\top +\end{equation} + +We repeat this cycle until termination of the program. From 4ffbb9f1a6631a26931fff14bcfe89375d458cc9 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Thu, 20 Jun 2024 16:23:06 -0600 Subject: [PATCH 08/14] Correcred typos and added pseudo measurement explanation. --- .../rosplane/estimator/estimator-example.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index bf9e024..aa439aa 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -13,13 +13,16 @@ The other states are then estimated as a all at once. This is called the position estimation step, though more than just position is estimated during this step. The estimator runs on a set timer with a configurable frequency (see Parameters section for details). - +The estimator makes large use of something called a pseudo-measurements. +These measures assume that the side slip angle is zero and the corresponding wind triangle solution. +This allows us to take these measures and then find the wind in the north and east directions along with the yaw of the aircraft. +They are more fully explored in section 8.11.4 of the UAV book. ## Nomenclature | Symbol | Meaning | Range | |:------:|:-------:| :---: | -|$\large{\chi}$| Course/Heading | $[-\pi,\pi)$ | +|$\large{\chi}$| Course | $[-\pi,\pi)$ | |$\large{\phi}$| Roll | $[-\pi,\pi)$ | |$\large{\theta}$| Theta | $[-\pi,\pi)$ | |$\large{\psi}$| Yaw | $[-\pi,\pi)$ | @@ -28,6 +31,8 @@ The estimator runs on a set timer with a configurable frequency (see Parameters |$\large{q}$| Pitch Rate | - | |$\large{r}$| Yaw Rate | - | |$\large{V_a}$| Airspeed | $\geq 0$ | +|$\large{w_n}$| Wind North | - | +|$\large{w_e}$| Wind East | - | ## Sensor Model Inversion @@ -287,9 +292,9 @@ The measurement noise matrix, $R_{position}$, is defined as: 0 & \sigma_{gps, e}^2 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & \sigma_{gps, V_g}^2 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & \sigma_{gps, \chi}^2 & 0 & 0 & 0 \\ - 0 & 0 & 0 & 0 & \sigma_{psuedo, w_n}^2 & 0 & 0 \\ - 0 & 0 & 0 & 0 & 0 & \sigma_{psuedo, w_n}^2 & 0 \\ - 0 & 0 & 0 & 0 & 0 & 0 & \sigma_{psuedo, \psi}^2 \\ + 0 & 0 & 0 & 0 & \sigma_{pseudo, w_n}^2 & 0 & 0 \\ + 0 & 0 & 0 & 0 & 0 & \sigma_{pseudo, w_n}^2 & 0 \\ + 0 & 0 & 0 & 0 & 0 & 0 & \sigma_{pseudo, \psi}^2 \\ \end{bmatrix} \end{equation} From 06914aa0b29a1a63cab9f13ec1a2fcb9c3016032 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Thu, 20 Jun 2024 16:35:30 -0600 Subject: [PATCH 09/14] Added software arch section along with code snippets. --- .../assets/estimator_assets/estimator_cmake.png | Bin 0 -> 38157 bytes .../estimator_override_function.png | Bin 0 -> 12586 bytes .../rosplane/estimator/estimator-example.md | 15 +++++++++++++++ 3 files changed, 15 insertions(+) create mode 100644 docs/assets/estimator_assets/estimator_cmake.png create mode 100644 docs/assets/estimator_assets/estimator_override_function.png diff --git a/docs/assets/estimator_assets/estimator_cmake.png b/docs/assets/estimator_assets/estimator_cmake.png new file mode 100644 index 0000000000000000000000000000000000000000..4e9e0f38c0a476e2c17652d7eabb674410a76143 GIT binary patch literal 38157 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%0DHp_pYXJTk*WSh!yRRV1bZU7?qoSVIQLdZ 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 literal 0 HcmV?d00001 diff --git a/docs/assets/estimator_assets/estimator_override_function.png b/docs/assets/estimator_assets/estimator_override_function.png new file mode 100644 index 0000000000000000000000000000000000000000..b3ffd1cf72fc57d0dbbf69ae75c9cb6d80e219ce GIT binary patch literal 12586 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­p=k!)V9>c>m3{<;L*;0uqZbAkkDmc5XcUmJq9d^2v!VW zrT#F-Fpdx}e>Fd2f-|wX51bmbfwhekoJ}9ALX`xU= z5lus_XM-S>YA6gK7xcQCw~ehK1)76>FRdwp7ciC2!K=i|8}&6_ko1b%KQE3nyaA!8 zI*ZG!5)Tdh*nw~S`wl?N6ntFh5Wm`wea%^VA6i=eQ1geGy*tf>h!+rex8>SMWur?! zkO7EF>8T9N8VFweNkgg&OVOC_9m1U2t@Sjw^G)8od0GmEufvP7JwhVjw`q2S$iF?myv=HS@)<2av4} zXw*`n%4{L?B(g}K&XIfEjptV~!stgkN2l)%+1?Y!;)uiu<_)g%VMI>ji_{&M0x!dK z!ne8p_SqMQl?{>t^7!n^!6R!uBQ&775Wb_ngR}ea0)cEOx>H8_1WmfC8wdbjTqrQ6 zW;mq0It2JP4~d`mGiLJO2=RLq8-~aB*&zL}qH>(DVoPvB|0b#>wh27H;-@}Zlcn&PH6-lI!#JX`ZLj0Am3VSgglB%ZeRf}IGEc?28{uMAEhH&BTM#L(w?8gFHe^RlPA9%>;D=E0v?*^l>=jU|>?|pp zaLAOP6;*M?GBO7O@%zcze9)eeaGIdBmNT8kqh9^{r=9)7J?k}= zljPcUEV{sL`z^T11Ebj9{yrm?u@D}%Of=et&X(S-hq)39hT(pAEIU#@B(Psn*oiv8 z*Ht*McgFWu?Y5sKjTIs=Om1Kqx4bf(sxti)45o#N9S8$akbq{rr>DhsSN3sJ->qzU z>DmCDJ~2LO;_68@Kc@)Ac4eB}&RZ~)HYw+bR9d+@D7jo4O}J>cdyf`;u@Io0k=f6Z zD57Bl4bzmQxKzlf`i`cm6;wcGavPN8ZAv=4*O+{J9G$6g#M`lWrO~~GWP4lF2J1MS z*5WKn#C&IR#>RGk-mSSZyCj;|-+%0-QYTJke~N=VUzclbgADUIE3~RmSJ<==%0?gK z!Hk^7OBiEeHi+~-)K>-p5`Ga*sm(PrSx^6l;pc+2EXPQo(r{N?jQyu#Jj7p#N-ZH= zZUzazlJF^vKiwRz!KEU;_R2{K6?gK%X+oQmJRT;(5a87QvV8B-(Z*kA1n5iQy|4{8 znrSJO&Q_PGbA!b1ym3RbPMSEC#_)viPc*Di z>74x1y8p(iv-I+pU9ZfekXZDv3?XFq&WOOt9DW^LHjbO~^yxww)hp)#xH1`o%;Y)j zLHp}MkgHz&vt_@>0mfPbp~JZ~nz{ntYnPc>`SD9lP^Hwm`>NN(ty@}48KKzhHYz; zbuRI4;91g-kl3qht{g|{q9wM-uLWy+x;(J@)L3Ye~6w7(Z`I(&0tOzkdW%Ln8)`CdgrKCpke12 zWrJ5RCd8+TdXGq|BtL@N6`=nY?fT<8`@g}Qeg!$_lyHD-f5EMhRULHxe@ER@|5~cV zFt)*bC0-WQWtWW++hNo(LjFY&Z)F%hy=QV`VWd)MuD}>9&9&Fn%fo-O^&e?D%W0+l zSY!)>_o(opvA)|$D563c=_PTAWaW?sDgRuN|6sN+1nQVI41q{i-M{}afB-~gMXH4K G1OGqOHE~)1 literal 0 HcmV?d00001 diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index aa439aa..3b42738 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -324,3 +324,18 @@ Finally, we update the covariance from our new estimate: \end{equation} We repeat this cycle until termination of the program. + +## Software Architecture + +To replace the estimator all that needs to be done is inherit from the `estimator_base` class and override the `estimate` method, as described in the .hpp file. + +| ![Estimator Override Function](../../../assets/estimator_assets/estimator_override_function.png "Estimator Override Function") | +|:--:| +|*Figure 1: The member method that must be overriden to use a new estimator.*| + +Next, replace `estimator_example.cpp` in the `CMakeLists.txt` with the newly created estimator file. + +| ![Estimator CMake Change Location](../../../assets/estimator_assets/estimator_cmake.png "Estimator CMake Change Location") | +|:--:| +|*Figure 1: The location to replace the file for the new estimator file.*| + From efe45074e4ca13faeac62fa51a62158fe24d3598 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Thu, 20 Jun 2024 16:37:55 -0600 Subject: [PATCH 10/14] Added parameters section. --- docs/developer-guide/rosplane/estimator/estimator-example.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index 3b42738..166fe3c 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -339,3 +339,6 @@ Next, replace `estimator_example.cpp` in the `CMakeLists.txt` with the newly cre |:--:| |*Figure 1: The location to replace the file for the new estimator file.*| +## Parameters + +Add Parameters when the estimator param update is complete. From 5a973d79d0d5fa5c2555f08ff89f3f11ce704512 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Mon, 24 Jun 2024 13:01:48 -0600 Subject: [PATCH 11/14] Added parameters to estimator base. --- .../rosplane/estimator/estimator-base.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/developer-guide/rosplane/estimator/estimator-base.md b/docs/developer-guide/rosplane/estimator/estimator-base.md index 4bf6976..fcb6161 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-base.md +++ b/docs/developer-guide/rosplane/estimator/estimator-base.md @@ -32,7 +32,15 @@ They are summarized in the table below: ## Parameters -Update when all estimator params are implemented. +| **Parameter** | **Explanation** | **Type** | **Range** | +| :---: | :---: | :---: | :---: | +| `rho` | The density of the air. | double | ~1.225 $\frac{kg}{m^3}$ | +| `gravity` | The acceleration due to gravity. | double | ~9.81 $\frac{m}{s^2}$ | +| `estimator_update_frequency` | The frequency that the estimator will run estimations. | double | $\geq 100$ Hz | +| `gps_ground_speed_threshold` | This determines when the aircraft is moving fast enough to get a course estimate. | double | $\geq$ 0.3 $\frac{m}{s}$ | +| `baro_measurement_gate` | The maximum allowable instantaneous change in barometer pressure measurement. | double | ~1 meter | +| `airspeed_measurement_gate` | The maximum allowable instantaneous change in differential pressure measurement. | double | ~5 $\frac{m}{s}$ | +| `baro_calibration_count` | The number of barometer measurements used to do calibration. | int | $\geq 100$ | ## Modifying the Estimator From b2c2ee245f4f3f1e0e8a478f6c7715fa1ccb625a Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Mon, 24 Jun 2024 14:27:31 -0600 Subject: [PATCH 12/14] Added parameters to the estimator-example. --- .../rosplane/estimator/estimator-example.md | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index 166fe3c..2dd682a 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -341,4 +341,33 @@ Next, replace `estimator_example.cpp` in the `CMakeLists.txt` with the newly cre ## Parameters -Add Parameters when the estimator param update is complete. +| **Parameter** | **Explanation** | **Type** | **Range** | +| :---: | :---: | :---: | :---: | +| `sigma_n_gps` | The standard deviation of gps measurements in the north axis. | double | ~0.01 meters | +| `sigma_e_gps` | The standard deviation of gps measurements in the east axis. | double | ~0.01 meters | +| `sigma_Vg_gps` | The standard deviation of gps ground speed measurements. | double | ~0.005 $\frac{m}{s}$ | +| `sigma_course_gps` | The standard deviation of gps ground course measurements. | double | ~0.00025 radians | +| `sigma_accel` | The standard deviation of accelerometer measurements. | double | ~0.025 $\frac{m}{s^2}$ | +| `sigma_pseudo_wind_n` | The standard deviation of pseudo-measurement along the north axis. | double | ~0.01 | +| `sigma_pseudo_wind_e` | The standard deviation of pseudo-measurement along the east axis. | double | ~0.01 | +| `sigma_heading` | The standard deviation of heading measurement. | double | ~0.01 radians | +| `lpf_a` | The lowpass filter cutoff frequency for the gyro and accelerometers. | double | ~50.0 Hz | +| `lpf_a1` | The lowpass filter cutoff frequency for the pressure sensors. | double | ~8.0 Hz | +| `gps_n_lim` | The limit of GPS measurements in the north direction. | double | $\geq 10000$ meters | +| `gps_e_lim` | The limit of GPS measurements in the east direction. | double | $\geq 10000$ meters | +| `roll_process_noise` | The process noise on the roll propagation. | double | ~0.0001 | +| `pitch_process_noise` | The process noise on the pitch propagation. | double | ~0.0000001 | +| `gyro_process_noise` | The process noise on the gyro inversion. | double | ~0.13 | +| `pos_process_noise` | The process noise on the position propagation. | double | 0.1 | +| `attitude_initial_cov` | Initial covariance entry for attitude. | double | 5.0 | +| `pos_n_initial_cov` | Initial covariance entry for position north. | double | 0.03 | +| `pos_e_initial_cov` | Initial covariance entry for position east. | double | 0.03 | +| `vg_initial_cov` | Initial covariance entry for groundspeed. | double | 0.01 | +| `chi_initial_cov` | Initial covariance entry for course. | double | 5.0 Degrees | +| `wind_n_initial_cov` | Initial covariance entry for wind north. | double | 0.04 | +| `wind_e_initial_cov` | Initial covariance entry for wind east. | double | 0.04 | +| `psi_initial_cov` | Initial covariance entry for heading. | double | 5.0 | +| `num_propagation_steps` | Number of propagation steps to run between measurements. | int | 10 | +| `max_estimated_phi` | The maximum roll estimate, over this and the estimator saturates. | double | ~90.0 degrees | +| `max_estimated_theta` | The maximum pitch estimate, over this and the estimator saturates. | double | ~80.0 degrees | +| `estimator_max_buffer` | The buffer that the esimator returns the estimate to after saturation. | double | ~3.0 degrees | From 630a3b32dd391439d34feca69470cbb3b7b58e8a Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Tue, 25 Jun 2024 16:59:36 -0600 Subject: [PATCH 13/14] Minor typo fixes. --- .../rosplane/estimator/estimator-base.md | 2 +- .../rosplane/estimator/estimator-example.md | 12 ++++++------ .../rosplane/estimator/estimator-overview.md | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/developer-guide/rosplane/estimator/estimator-base.md b/docs/developer-guide/rosplane/estimator/estimator-base.md index fcb6161..b7a88df 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-base.md +++ b/docs/developer-guide/rosplane/estimator/estimator-base.md @@ -19,7 +19,7 @@ They are summarized in the table below: | ROS Interface | Topic | Explanation | Message Type | |:------:|:-------:| :---: | :---: | -|
`vehicle_state_pub_`
| `/estimated_state` | Publishes the estimated state of teh vehicle. | State.msg | +|
`vehicle_state_pub_`
| `/estimated_state` | Publishes the estimated state of the vehicle. | State.msg | |
`gnss_fix_sub_`
| `/navsat_compat/fix` | Subcribes to the GNSS position information. | NavSatFix.msg | |
`gnss_vel_sub_`
| `/navsat_compat/vel` | Subcribes to the GNSS velocity information. | TwistStamped.msg | |
`imu_sub_`
| `/imu/data` | Subcribes to the IMU data (both Gyro and Accel). | Imu.msg | diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index 2dd682a..d8fa500 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -13,7 +13,7 @@ The other states are then estimated as a all at once. This is called the position estimation step, though more than just position is estimated during this step. The estimator runs on a set timer with a configurable frequency (see Parameters section for details). -The estimator makes large use of something called a pseudo-measurements. +The estimator makes large use of something called a pseudo-measurement. These measures assume that the side slip angle is zero and the corresponding wind triangle solution. This allows us to take these measures and then find the wind in the north and east directions along with the yaw of the aircraft. They are more fully explored in section 8.11.4 of the UAV book. @@ -36,7 +36,7 @@ They are more fully explored in section 8.11.4 of the UAV book. ## Sensor Model Inversion -The roll, pitch and yaw rates are directly measured by the rate gyro and low pass filtered. +The roll, pitch and yaw rates are directly measured by the rate gyro and then low pass filtered. The low pass filter is a simple alpha filter described by: $$ @@ -246,7 +246,7 @@ With this propagated estimate and covariance we are now ready for a measurement -Because the GPS measures come in slower than the model propagates, the measurement step is only run when their is new GPS information. +Because the GPS measures come in slower than the model propagates, the measurement step is only run when there is new GPS information. This process is identical to the measurement update in the attitude step. This will likely change before release, but the only difference is that it is done one measurement at a time. This has advantages for querying the values while debugging, but is on the whole less clear and is more error prone. @@ -337,7 +337,7 @@ Next, replace `estimator_example.cpp` in the `CMakeLists.txt` with the newly cre | ![Estimator CMake Change Location](../../../assets/estimator_assets/estimator_cmake.png "Estimator CMake Change Location") | |:--:| -|*Figure 1: The location to replace the file for the new estimator file.*| +|*Figure 2: The location to replace the file for the new estimator file.*| ## Parameters @@ -368,6 +368,6 @@ Next, replace `estimator_example.cpp` in the `CMakeLists.txt` with the newly cre | `wind_e_initial_cov` | Initial covariance entry for wind east. | double | 0.04 | | `psi_initial_cov` | Initial covariance entry for heading. | double | 5.0 | | `num_propagation_steps` | Number of propagation steps to run between measurements. | int | 10 | -| `max_estimated_phi` | The maximum roll estimate, over this and the estimator saturates. | double | ~90.0 degrees | -| `max_estimated_theta` | The maximum pitch estimate, over this and the estimator saturates. | double | ~80.0 degrees | +| `max_estimated_phi` | The maximum roll estimate before estimator saturation. | double | ~90.0 degrees | +| `max_estimated_theta` | The maximum pitch estimate before estimator saturation. | double | ~80.0 degrees | | `estimator_max_buffer` | The buffer that the esimator returns the estimate to after saturation. | double | ~3.0 degrees | diff --git a/docs/developer-guide/rosplane/estimator/estimator-overview.md b/docs/developer-guide/rosplane/estimator/estimator-overview.md index f67909f..ce25e43 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-overview.md +++ b/docs/developer-guide/rosplane/estimator/estimator-overview.md @@ -12,7 +12,7 @@ For a more in depth look at which states are estimated in which way visit the [E The estimator takes in sensor information from `rosflight_io` computes an estimate and publishes it to the rest of ROSplane. -| ![Diagram of Estimator ROS Interactions](../../../assets/estimator_assets/estimator_ros_input_output.png "Diagram of Estimator ROS Interactions") | +| ![Diagram of Estimator ROS Interactions](../../../assets/estimator_assets/estimator_full_ros_interactions.png "Diagram of Estimator ROS Interactions") | |:--:| |*Figure 1: ROS network interactions for the estimator.*| From 75d4c0f38e224f4173bf30536ed0ffbe0a3a2327 Mon Sep 17 00:00:00 2001 From: Ian Reid Date: Tue, 25 Jun 2024 17:15:55 -0600 Subject: [PATCH 14/14] Added explanation of estimator implementation and tuning. --- .../rosplane/estimator/estimator-example.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/developer-guide/rosplane/estimator/estimator-example.md b/docs/developer-guide/rosplane/estimator/estimator-example.md index d8fa500..5ba15c2 100644 --- a/docs/developer-guide/rosplane/estimator/estimator-example.md +++ b/docs/developer-guide/rosplane/estimator/estimator-example.md @@ -130,6 +130,9 @@ The entries are the variances and for the attitude step this is defined as: Using our estimate and a model set of equations $h$, we predict the measurements the accelerometer will produce. We will then compare the actual and predicted measurements and optimally adjust our estimate with the new information. Since measurements come in much faster than the model propagates the measurement step is run every time the propagated estimate is calculated. +!!! note + The estimator asssumes that measurements come in faster than/as fast the estimation timer is calls for estimation updates. + If this is not the case performance can actually go down for the estimation if you increase the frequency of the estimation updates. The set of equations, $h$, that predict the 3 measurements of the accelerometer, $y$, is given by: \begin{equation} @@ -327,6 +330,17 @@ We repeat this cycle until termination of the program. ## Software Architecture +### Estimator implementation Specifics + +The estimator calls the update of the estimate on a timer. +Between estimation updates, the measurements come in as they are published and are saved in the estimator. +This allows asynchronous measurements and for only the most recent measurements to be used. +It does mean however, that the propagation is reliant on the measurements being faster or as fast as the estimation updates. +It also means that turning up the estimation frequency will not always have the anticipated effect. +To increase estimator performance a combination of process noise tuning, sensor uncertainty characterization, sensor update speed increase estimate update speed increase will be needed. + +### Replacing the Estimator + To replace the estimator all that needs to be done is inherit from the `estimator_base` class and override the `estimate` method, as described in the .hpp file. | ![Estimator Override Function](../../../assets/estimator_assets/estimator_override_function.png "Estimator Override Function") |