-
Notifications
You must be signed in to change notification settings - Fork 26
Henrik/velocity/merge #697
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
base: main
Are you sure you want to change the base?
Changes from all commits
ab3bd3a
23fea72
1d1cb53
60dbb72
252ec54
58a87f9
2760cbe
fc5d99b
b962ad5
5e8e77a
2fb9d91
40eb88f
9141eca
064adef
7019787
bbd8564
e6ae145
4d22267
3f3e671
2688e27
798542a
3bb8926
3afca97
2f6c253
9ec7fd4
b7f63a9
ee303e7
c687343
314a60b
03560cf
66b252e
a36297a
a10e639
b2e632b
ef96e1e
8f15552
84ae150
76da1d9
cb4156b
5ce96ef
1305ea7
f5d698a
524a97e
b7805ea
8c61007
294ab77
edc7185
763f784
f073936
70d0bb3
65a37c2
7273d43
ab5a067
98d4faa
47b5121
a55e636
c79cee8
5099e51
6a13ca1
2baeae8
5d31409
2bd2c4e
52c919f
11e8d60
30568ab
73b460c
bb54545
29a5709
76f803e
6ecdc9f
4c59e21
b71f62c
3a10402
17d89c9
374230a
853741d
2476ace
0f4094a
a8bf5b4
820694d
bdb00db
1d8df3a
4beeab0
c8a1da7
a2927ad
7f7fdde
f64e566
4509286
7a39ece
3841172
0431417
ae31273
f495f8b
2e73cff
b6f144b
c6a2047
4818dae
ef4517e
1a9af09
c4e0770
44de4c7
77c69e2
17b261c
94b1d70
5b68001
b29e76d
ff2cdc5
07b3737
0acc8cb
32a51d2
a06855f
7ec9873
52b958b
b9e2d8a
b61a37a
3e6f6f1
df6aab0
182688f
e7a3eaa
f4d9c57
c018821
31a3a0e
cb88a38
e02dc47
de375d3
bbe0eaf
0c11cff
92a43c3
e198b16
6a90ce7
a42b6c3
6968952
6eb2d7e
786b98e
c106bbb
edf1e1b
c1ae0ac
e438f33
f080525
6b5e9ce
e29606d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| cmake_minimum_required(VERSION 3.8) | ||
| project(velocity_controller) | ||
|
|
||
| set(CMAKE_CXX_STANDARD 20) | ||
| set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||
|
|
||
| if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") | ||
| add_compile_options(-Wall -Wextra -Wpedantic) | ||
| endif() | ||
|
|
||
|
|
||
| find_package(ament_cmake REQUIRED) | ||
| find_package(rclcpp REQUIRED) | ||
| find_package(rclcpp_lifecycle REQUIRED) | ||
| find_package(rclcpp_components REQUIRED) | ||
| find_package(lifecycle_msgs REQUIRED) | ||
| find_package(std_msgs REQUIRED) | ||
| find_package(vortex_msgs REQUIRED) | ||
| find_package(vortex_utils REQUIRED) | ||
| find_package(Eigen3 REQUIRED) | ||
| find_package(geometry_msgs REQUIRED) | ||
| find_package(nav_msgs REQUIRED) | ||
| find_package(ct_optcon REQUIRED) | ||
| find_package(ct_core REQUIRED) | ||
| find_package(casadi REQUIRED) | ||
|
|
||
| include_directories( | ||
| include | ||
| ) | ||
|
|
||
|
|
||
| set(LIB_NAME velocity_controller_component) | ||
| add_library(${LIB_NAME} SHARED | ||
| src/velocity_controller_ros.cpp | ||
| src/PID_controller.cpp | ||
| src/LQR_setup.cpp | ||
| src/utilities.cpp | ||
| src/ct_instantiations.cpp | ||
| src/control_manager.cpp | ||
| src/3DOF_PID.cpp | ||
| ) | ||
| rclcpp_components_register_nodes(${LIB_NAME} "Velocity_node") | ||
| ament_target_dependencies(${LIB_NAME} | ||
| rclcpp | ||
| rclcpp_components | ||
| rclcpp_lifecycle | ||
| lifecycle_msgs | ||
| std_msgs | ||
| vortex_msgs | ||
| geometry_msgs | ||
| nav_msgs | ||
| vortex_utils | ||
| ) | ||
| target_link_libraries(${LIB_NAME} Eigen3::Eigen casadi::casadi ct_optcon ct_core) | ||
| install(TARGETS | ||
| ${LIB_NAME} | ||
| ARCHIVE DESTINATION lib | ||
| LIBRARY DESTINATION lib | ||
| RUNTIME DESTINATION bin | ||
| ) | ||
|
|
||
| install( | ||
| DIRECTORY include/ | ||
| DESTINATION include | ||
| ) | ||
|
|
||
| install(DIRECTORY | ||
| launch | ||
| config | ||
| DESTINATION share/${PROJECT_NAME}/ | ||
| ) | ||
|
|
||
| if(BUILD_TESTING) | ||
| add_subdirectory(tests) | ||
| endif() | ||
|
|
||
| ament_package() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| # velocity_controller | ||
|
|
||
| ROS2 lifecycle node for velocity control of an AUV (autonomous underwater vehicle). Supports two control strategies — a PID controller and an LQR controller. | ||
|
|
||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| The package implements a `Velocity_node` that subscribes to odometry and guidance inputs, computes thrust commands, and publishes them as `WrenchStamped` messages. The node is managed as a ROS2 lifecycle node, meaning it can be managed by a lifecycle manager, however if you do not want to use a lifecycle manager you can change the parameter autostart in the parameter file so that it automatically goes into active state. | ||
|
|
||
| The LQR controller linearizes the vehicle dynamics around the current state at each timestep (gain-scheduled LQR), using a body-frame model that includes linear hydrodynamic damping, Coriolis effects, and integral action for steady-state error rejection. The PID controller serves as a simpler backup. | ||
|
|
||
| --- | ||
|
|
||
| ## Dependencies | ||
| //TODO(henrimha): fix the dependencies | ||
| | Dependency | Purpose | | ||
| |---|---| | ||
| | `rclcpp` / `rclcpp_lifecycle` | ROS2 node and lifecycle management | | ||
| | `Eigen3` | Matrix math for LQR | | ||
| | `control_toolbox` (`ct::optcon`) | Riccati equation solver for LQR gain | | ||
| | `CasADi` | Used in utilities (NMPC-related) | | ||
| | `vortex_msgs` | Custom guidance message (`LOSGuidance`) | | ||
| | `nav_msgs` | Odometry input | | ||
| | `geometry_msgs` | Thrust output (`WrenchStamped`) | | ||
|
Comment on lines
+19
to
+25
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i see more dependencies here, something isnt right: rclcpp |
||
|
|
||
| --- | ||
|
|
||
| ## Topics | ||
|
|
||
| | Topic | Type | Direction | Description | | ||
| |---|---|---|---| | ||
| | `topic_thrust` | `geometry_msgs/WrenchStamped` | Published | Force and torque commands to thruster allocator | | ||
| | `topic_guidance` | `vortex_msgs/LOSGuidance` | Subscribed | Desired surge, pitch, yaw from guidance system | | ||
| | `topic_odometry` | `nav_msgs/Odometry` | Subscribed | Current vehicle state from state estimator | | ||
|
|
||
| Topic names are configurable via ROS2 global parameter file. | ||
|
|
||
| --- | ||
|
|
||
| ## Parameters | ||
|
|
||
| All parameters are loaded in the constructor via `get_new_parameters()`. | ||
|
|
||
| ### Controller selection | ||
|
|
||
| | Parameter | Type | Description | | ||
| |---|---|---| | ||
| | `controller_type` | `int` | `1` = PID, `2` = LQR | | ||
| | `publish_rate` | `int` | Control loop frequency in Hz | | ||
| | `max_force` | `double` | Saturation limit applied to all outputs (N / Nm) | | ||
|
|
||
| ### LQR parameters | ||
|
|
||
| | Parameter | Type | Dimension | Description | | ||
| |---|---|---|---| | ||
| | `Q` | `double[]` | 8 | Diagonal of state weight matrix. States: `[surge_err, pitch_err, yaw_err, pitch_rate_err, yaw_rate_err, ∫surge, ∫pitch, ∫yaw]` | | ||
| | `R` | `double[]` | 3 | Diagonal of input weight matrix. Inputs: `[Fx, Ty, Tz]` | | ||
| | `inertia_matrix` | `double[]` | 36 | Row-major 6x6 rigid body inertia matrix | | ||
| | `dampening_matrix_low` | `double[]` | 36 | Row-major 6x6 hydrodynamic damping matrix at low speed | | ||
|
Comment on lines
+59
to
+60
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. give dimention, size is eh |
||
|
|
||
| ### PID parameters | ||
|
|
||
| Each axis (surge, pitch, yaw) takes a parameter vector of the form `[Kp, Ki, Kd]`. | ||
|
|
||
| | Parameter | Description | | ||
| |---|---| | ||
| | `surge_params` | PID gains for surge | | ||
| | `pitch_params` | PID gains for pitch | | ||
| | `yaw_params` | PID gains for yaw | | ||
|
|
||
| ### Behaviour flags | ||
|
|
||
| | Parameter | Type | Description | | ||
| |---|---|---| | ||
| | `reset_on_new_ref` | `bool` | Reset integrators when a new guidance reference arrives | | ||
| | `anti_overshoot` | `bool` | Enable anti-overshoot logic | | ||
| | `odometry_dropout_guard` | `bool` | Stop publishing if odometry stops arriving | | ||
| | `auto_start` | `bool` | If true, node self-transitions to active on startup | | ||
|
|
||
|
|
||
| --- | ||
|
|
||
| ## Lifecycle states | ||
|
|
||
| The node uses the standard ROS2 managed lifecycle: | ||
|
|
||
| ``` | ||
| Unconfigured → [configure] → Inactive → [activate] → Active | ||
| ← [deactivate] ← | ||
| ``` | ||
|
|
||
| If `auto_start` is set to `true` in the parameters, the node will automatically call configure and activate itself after startup without needing an external lifecycle manager. | ||
|
|
||
| To manually manage the node: | ||
|
|
||
| ```bash | ||
| # Configure | ||
| ros2 lifecycle set /velocity_controller configure | ||
|
|
||
| # Activate | ||
| ros2 lifecycle set /velocity_controller activate | ||
|
|
||
| # Deactivate | ||
| ros2 lifecycle set /velocity_controller deactivate | ||
|
|
||
| # Cleanup | ||
| ros2 lifecycle set /velocity_controller cleanup | ||
|
|
||
| # Shutdown | ||
| ros2 lifecycle set /velocity_controller shutdown | ||
|
|
||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Controller details | ||
|
|
||
| ### LQR | ||
|
|
||
| The LQR controller uses an 8-state augmented model in the body frame: | ||
|
|
||
| ``` | ||
| x = [surge_err, pitch_err, yaw_err, pitch_rate_err, yaw_rate_err, ∫surge, ∫pitch, ∫yaw] | ||
| u = [Fx, Ty, Tz] | ||
| ``` | ||
|
|
||
| The system matrix `A` is re-linearized around the current state every control timestep. Guidance references in NED are converted to body-frame errors using the rotation matrix method before being passed to the controller — not by angle subtraction. | ||
|
|
||
| The gain `K` is computed by solving the continuous-time algebraic Riccati equation via `ct::optcon::LQR`. The control law is: | ||
|
Comment on lines
+128
to
+130
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perhaps give me the DLQR equation here |
||
|
|
||
| ``` | ||
| u = K * x_error | ||
| ``` | ||
| //TODO(henrimha): give the riccatti equation | ||
| where `ct::optcon` produces `K` such that this is equivalent to `u = -K * (x - x_ref)`. | ||
|
|
||
| If the Riccati solver fails (e.g. due to an unstabilizable operating point), the node automatically falls back to PID and logs an error. | ||
|
|
||
| ### PID | ||
|
|
||
| Three independent PID controllers run on surge, pitch, and yaw. Each supports anti-windup via integrator clamping. The derivative term can be computed either from the error signal or from a separately provided error derivative, depending on which `calculate_thrust` overload is called. | ||
|
|
||
| --- | ||
|
|
||
| ## Building | ||
|
|
||
| ```bash | ||
| colcon build --packages-select velocity_controller --symlink-install | ||
| source install/setup.bash | ||
| ``` | ||
| or with | ||
|
|
||
| ```bash | ||
| colcon build --packages-up-to velocity_controller --symlink-install | ||
| source install/setup.bash | ||
| ``` | ||
| Done in root of workspace | ||
| --- | ||
|
|
||
| ## Running | ||
|
|
||
| Via a launch file with a parameter file: | ||
|
|
||
| ```bash | ||
| ros2 launch velocity_controller velocity_controller.launch.py | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Tests | ||
| There are system tests and a helper node that generates a reference for the controller to follow. | ||
| Tests are build like this: | ||
| ```bash | ||
| colcon build --packages-select velocity_controller --symlink-install --cmake-args -DBUILD_TESTING=ON | ||
| source install/setup.bash | ||
| ``` | ||
| System tests are run with the command | ||
|
|
||
| ```bash | ||
| colcon test | ||
| ``` | ||
|
|
||
| Helper node is run with | ||
|
|
||
| ```bash | ||
| ros2 launch velocity_controller VCnTest.launch.py | ||
| ``` | ||
|
|
||
| ## Notes for new team members | ||
|
|
||
| - The guidance input is expected in NED frame (north-east-down). The controller handles the NED-to-body conversion internally. | ||
| - All angle errors are wrapped to `[-π, π]` using `ssa()` (smallest signed angle) before being fed to the controller. | ||
| - The LQR Q matrix ordering matters — the 8 diagonal values correspond exactly to `[surge_err, pitch_err, yaw_err, pitch_rate_err, yaw_rate_err, ∫surge, ∫pitch, ∫yaw]` in that order. | ||
| - If the vehicle behaves oddly, check that `interval_` (the control timestep) is being set correctly — a value of `0` disables integral action silently. | ||
|
|
||
| ## Adding new controllers | ||
| After adding the hpp file, add the calculation to calc_thrust function in a new switch case, add to the reset_controller function, with options to reset only one integral, lastly update documentation. Remember to initialize correctly, either in 'on_configure' or in constructor, add the appropriate parameters, and update all the {drone}_params.yaml files. | ||
|
|
||
| ## Adding new drones | ||
| Copy a {drone}_params.yaml file and change the name to the new name of the drone. Add the appropriate matrices, and tune to satisfying behaviour. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clear chat text, remove — and AUV explanation