Skip to content

Commit 4fba8ee

Browse files
authored
Merge pull request #661 from vortexntnu/580-task-Thrust-Allocator-AUV
refactored old thrust allocator and implemented QP solver. Also changed stuff to work with the new drone
2 parents da8722f + 7f10bc5 commit 4fba8ee

30 files changed

Lines changed: 1698 additions & 151 deletions

.github/workflows/simulator-test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jobs:
1414
with:
1515
vcs_repos_file: "tests/dependencies.repos"
1616
setup_script: "tests/setup.sh"
17+
pre_test_script: "scripts/ci_install_dependencies.sh"
1718
test_scripts: '[
1819
"tests/simulator_tests/waypoint_navigation/simulator_test.sh",
1920
"tests/simulator_tests/los_test/simulator_test.sh",

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ msg/*Result.msg
2121
msg/_*.py
2222
build_isolated/
2323
devel_isolated/
24+
*.cache/
2425

2526
# Generated by dynamic reconfigure
2627
*.cfgc

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ repos:
109109
rev: v2.4.1
110110
hooks:
111111
- id: codespell
112-
args: ['--write-changes', '--ignore-words-list=theses,fom,NED,ENU']
112+
args: ['--write-changes', '--ignore-words-list=theses,fom,NED,ENU,Bu']
113113

114114
ci:
115115
autoupdate_schedule: quarterly

auv_setup/config/robots/moby.yaml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
num: 3
2727
thrusters:
2828
num: 8
29-
min: -100
30-
max: 100
3129
thruster_force_direction: [ # Direction of forces X,Y,Z, same logic as thruster_position thruster0 produces thrust in (X0,Y0,Z0) and ||(X0,Y0,Z0)|| = 1
3230
0.70711,
3331
0.00000,
@@ -63,14 +61,14 @@
6361
-0.163904,
6462
0.140095,
6563
0.413892, # x-positions of the thrusters
66-
-0.313022,
67-
-0.313022,
68-
-0.313022,
69-
-0.313022,
7064
0.313022,
7165
0.313022,
7266
0.313022,
73-
0.313022, # y-positions of the thrusters
67+
0.313022,
68+
-0.313022,
69+
-0.313022,
70+
-0.313022,
71+
-0.313022, # y-positions of the thrusters
7472
0.021736,
7573
0.021736,
7674
0.021736,
@@ -80,6 +78,13 @@
8078
0.021736,
8179
0.021736, # z-positions of the thrusters
8280
]
81+
82+
constraints:
83+
max_force: 40.0
84+
min_force: -40.0
85+
input_matrix_weights: [1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]
86+
slack_matrix_weights: [2000.0,2000.0,2000.0,2000.0,2000.0,2000.0]
87+
8388
rate_of_change:
8489
max: 1 # Maximum rate of change in newton per second for a thruster
8590

auv_setup/config/robots/orca.yaml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
/**:
1818
ros__parameters:
1919
physical:
20-
center_of_mass: [0.0, 0.0, 0.035] # m (x,y,z)
20+
center_of_mass: [0.0, 0.0, 0.035] # Position (x,y,z) in meters (M)
2121
mass_matrix : [ 30.0, 0.0, 0.0, 0.0, 0.0, 0.6, 0.0, 30.0, 0.0, 0.0, -0.6, 0.3, 0.0, 0.0, 30.0, 0.6, 0.3, 0.0, 0.0, 0.0, 0.6, 0.68, 0.0, 0.0, 0.0, -0.6, 0.3, 0.0, 3.32, 0.0, 0.6, 0.3, 0.0, 0.0, 0.0, 3.34]
22+
# 6x6 mass_inertia_matrix
2223

2324
propulsion:
2425
dofs:
@@ -27,9 +28,7 @@
2728
num: 3
2829
thrusters:
2930
num: 8
30-
min: -100
31-
max: 100
32-
thruster_force_direction: [
31+
thruster_force_direction: [ # Direction of forces X,Y,Z, same logic as thruster_position thruster0 produces thrust in (X0,Y0,Z0) and ||(X0,Y0,Z0)|| = 1
3332
0.70711,
3433
0.00000,
3534
0.00000,
@@ -53,9 +52,9 @@
5352
0.00000,
5453
1.00000,
5554
1.00000,
56-
0.00000,
57-
] # Heave
58-
thruster_position: [
55+
0.00000, # Heave
56+
]
57+
thruster_position: [ # Position (x0,x1 ... x7,y1,y2, ...,y7,z1,z2, ... ,z7) in meters (M). i.e thruster0 has position (x0,y0,z0)
5958
0.41500,
6059
0.28400,
6160
-0.31800,
@@ -79,8 +78,14 @@
7978
0.07600,
8079
0.08200,
8180
0.08200,
82-
0.07600,
83-
] # z-position of thrusters
81+
0.07600, # z-position of thrusters
82+
]
83+
84+
constraints:
85+
max_force: 100.0
86+
min_force: -100.0
87+
input_matrix_weights: [1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]
88+
slack_matrix_weights: [2000.0,2000.0,2000.0,2000.0,2000.0,2000.0]
8489

8590
rate_of_change:
8691
max: 1 # Maximum rate of change in newton per second for a thruster

motion/thrust_allocator_auv/CMakeLists.txt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
cmake_minimum_required(VERSION 3.8)
22
project(thrust_allocator_auv)
33

4+
if(NOT CMAKE_BUILD_TYPE)
5+
set(CMAKE_BUILD_TYPE Release)
6+
endif()
7+
48
if(NOT CMAKE_CXX_STANDARD)
59
set(CMAKE_CXX_STANDARD 20)
610
endif()
@@ -18,13 +22,16 @@ find_package(geometry_msgs REQUIRED)
1822
find_package(Eigen3 REQUIRED)
1923
find_package(spdlog REQUIRED)
2024
find_package(fmt REQUIRED)
25+
find_package(casadi REQUIRED)
2126

2227
include_directories(include)
2328

2429
set(LIB_NAME "${PROJECT_NAME}_component")
2530

2631
add_library(${LIB_NAME} SHARED
27-
src/pseudoinverse_allocator.cpp
32+
src/solvers/qp_allocator.cpp
33+
src/solvers/allocator_factory.cpp
34+
src/solvers/pseudoinverse_allocator.cpp
2835
src/thrust_allocator_ros.cpp)
2936

3037
ament_target_dependencies(${LIB_NAME} PUBLIC
@@ -38,6 +45,8 @@ add_library(${LIB_NAME} SHARED
3845
spdlog
3946
)
4047

48+
target_link_libraries(${LIB_NAME} PRIVATE casadi)
49+
4150
rclcpp_components_register_node(
4251
${LIB_NAME}
4352
PLUGIN "ThrustAllocator"
@@ -63,4 +72,8 @@ install(DIRECTORY
6372
DESTINATION share/${PROJECT_NAME}/
6473
)
6574

75+
if(BUILD_TESTING)
76+
add_subdirectory(tests)
77+
endif()
78+
6679
ament_package()

motion/thrust_allocator_auv/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2024 Vortex NTNU
3+
Copyright (c) 2025 Vortex NTNU
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Thrust allocator
2+
3+
The **Thrust Allocator** is responsible for distributing the generalized control forces $\tau \in \mathbb{R}^n$ to the actuators in terms of control inputs $u \in \mathbb{R}^r$. For linear systems this boils down to $\tau = Bu$, where B is the input matrix. The individual control inputs $u_i$ are later passed into thruster_interface_auv.
4+
5+
# Notation
6+
7+
The thrust allocation problem follows the notation of Fossen (2021), Ch. 11.
8+
The variables used in all allocation formulations (unconstrained, pseudoinverse, and QP) are:
9+
10+
### Generalized forces and configuration matrix
11+
12+
- $\tau \in \mathbb{R}^n$, Desired generalized force
13+
14+
- $T_e$, Extended thruster configuration matrix
15+
16+
---
17+
18+
### Actuator forces and extended vectors
19+
20+
- $f_e$, Extended force vector
21+
22+
- $\bar{f}$ defined as, $\; -\bar{f} \le f_{e,i} \le \bar{f}$ is the scalar bound used for load balancing
23+
24+
---
25+
26+
### Weighting matrices and penalties
27+
28+
- $W_f \succeq 0$, Weighting matrix on the extended force vector
29+
30+
- $Q \succeq 0$, Weighting matrix on the slack vector $s$.
31+
32+
- $\beta > 0$, Penalty weight on $\bar{f}$ used for load balancing (QP formulation).
33+
34+
---
35+
36+
### Constraints
37+
38+
- $f_{\min}, f_{\max}$ Lower and upper bounds on the extended force vector $f_e$.
39+
40+
# Interfaces
41+
42+
- **[ThrusterInterface](https://github.com/vortexntnu/vortex-auv/tree/main/motion/thruster_interface_auv)**
43+
44+
# Solvers
45+
46+
### **Pseudoinverse Allocator**
47+
48+
The pseudoinverse allocator follows the unconstrained weighted least–squares formulation
49+
given in Fossen (2021, Eq. 11.27):
50+
51+
$$
52+
J = \min_{f_e} \; ( f_e^\top W_f f_e )
53+
\qquad \text{s.t.} \qquad
54+
\tau - T f = 0,
55+
$$
56+
57+
---
58+
59+
#### **Generalized pseudoinverse (Fossen Eq. 11.35)**
60+
61+
Solving the weighted least–squares problem leads to the **generalized pseudoinverse**
62+
63+
$$
64+
T_w^+
65+
= W_f^{-1} T_e^\top \left( T_e W_f^{-1} T_e^\top \right)^{-1},
66+
$$
67+
68+
where $T_e$ is the extended configuration matrix used in the allocation.
69+
70+
---
71+
72+
#### **Right Moore–Penrose pseudoinverse (Fossen Eq. 11.36)**
73+
74+
If the allocator uses **identity actuator weights**,
75+
i.e. $W_f = I$, then the generalized pseudoinverse simplifies to the **right Moore–Penrose pseudoinverse**
76+
77+
$$
78+
T^+ = T_e^\top (T_e T_e^\top)^{-1}.
79+
$$
80+
81+
For orca there was no big reason to weigh the different actuators since the drone will be using 8 of the same thruster. Therefore the pseudoinverse_allocator solution degenerates to the simpler Right Moore-Penrose pseudoinverse.
82+
83+
---
84+
85+
### **Constrained QP Allocator**
86+
87+
The constrained thrust allocation problem is formulated as a quadratic program (QP) following
88+
Fossen (2021, Eq. 11.38). The optimization variables include the **extended force vector** $f_e$,
89+
a slack vector $s$, and the scalar load-balancing parameter $\bar{f}$. For our intents and purposes it
90+
the load balancing parameter will do more harm than good as different maneuvers require some thrusters
91+
to work hard whilst other thrusters to be at rest.
92+
93+
### **Original Fossen Formulation (QP standard form)**
94+
95+
$$
96+
J = \min_{f_e,\, s,\, \bar{f}}
97+
\; ( f_e^\top W_f f_e + s^\top Q s + \beta \bar{f} )
98+
$$
99+
100+
$$
101+
\text{s.t.} \quad
102+
T_e f_e = \tau + s
103+
$$
104+
105+
$$
106+
f_{\min} \le f_e \le f_{\max}
107+
$$
108+
109+
$$
110+
-\bar{f} \le f_{e,i} \le \bar{f}.
111+
$$
112+
113+
### **Implemented QP Formulation (QP standard form)**
114+
115+
$$
116+
J = \min_{f_e,\, s}
117+
\; ( f_e^\top W_f f_e + s^\top Q s)
118+
$$
119+
120+
$$
121+
\text{s.t.} \quad
122+
T_e f_e = \tau + s
123+
$$
124+
125+
$$
126+
f_{\min} \le f_e \le f_{\max}
127+
$$
128+
129+
This QP formulation allows thrust limits, load balancing, soft constraint handling.
130+
131+
# Testing
132+
133+
If you wish to run the tests inside of the tests folder, run the following commands:
134+
135+
#### 1. Build the package together with the tests.
136+
137+
```bash
138+
colcon build --packages-select thrust_allocator_auv --cmake-args -DBUILD_TESTING=ON
139+
```
140+
141+
#### 2. Run colcon test.
142+
143+
```bash
144+
colcon test --packages-select thrust_allocator_auv --event-handlers console_direct+
145+
```
146+
147+
#### 3. print out the results with the --verbose flag.
148+
149+
```bash
150+
colcon test-result --verbose
151+
```
152+
153+
# Debugging (CasADi)
154+
155+
If the solver behaves unexpectedly it is possible to turn on CasADi's inbuilt spdlogs which show iterations, objective function value and report if the convergence was successful or not.
156+
157+
```bash
158+
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Debug
159+
```
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @file allocator.hpp
3+
* @brief Contains the Allocator base class, which the final
4+
* allocators will be derived from
5+
*/
6+
7+
#ifndef THRUST_ALLOCATOR_AUV__ALLOCATOR_HPP_
8+
#define THRUST_ALLOCATOR_AUV__ALLOCATOR_HPP_
9+
10+
#include <eigen3/Eigen/Eigen>
11+
#include <optional>
12+
13+
/**
14+
* @brief The Allocator class structure that the solvers will inherit and
15+
* override.
16+
*/
17+
class Allocator {
18+
public:
19+
/**
20+
* @brief Destructor for the Allocator class.
21+
*/
22+
23+
virtual ~Allocator() = default;
24+
25+
/**
26+
* @brief Calculates the allocated thrust given the input torques using the
27+
* pre-calculated pseudoinverse matrix.
28+
*
29+
* @param tau The generalized forces as a vector.
30+
* @return The allocated thrust as a vector.
31+
*/
32+
virtual std::optional<Eigen::VectorXd> calculate_allocated_thrust(
33+
const Eigen::VectorXd& tau) = 0;
34+
};
35+
36+
#endif // THRUST_ALLOCATOR_AUV__ALLOCATOR_HPP_

0 commit comments

Comments
 (0)