diff --git a/conf/airframes/tudelft/rotwing5.xml b/conf/airframes/tudelft/rotwing5.xml
index 3799450579..1fec38d2d1 100644
--- a/conf/airframes/tudelft/rotwing5.xml
+++ b/conf/airframes/tudelft/rotwing5.xml
@@ -1,13 +1,13 @@
-
- RotatingWing25Kg
+
+ RotatingWing 5
@@ -37,14 +37,14 @@
-
+
-
-
-
+
+
+
@@ -64,6 +64,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -79,7 +91,7 @@
-
+
@@ -102,7 +114,7 @@
-
+
@@ -163,7 +175,7 @@
-
+
@@ -183,7 +195,7 @@
-
+
@@ -198,7 +210,7 @@
-
+
@@ -214,7 +226,7 @@
-
+
@@ -226,9 +238,9 @@
-
+
-
+
@@ -240,13 +252,13 @@
-
+
-
+
-
+
@@ -266,71 +278,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -339,13 +288,13 @@
-
-
+
+
-
+
@@ -360,7 +309,7 @@
-
+
@@ -379,201 +328,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -590,8 +347,20 @@
- Put UAV on take-off location
- Check flight plan
- Switch to correct flight block
+ - Switch on drone tag
- Switch on camera
- Arm parachute
- Announce flight to other airspace users
+
+
+
+
diff --git a/conf/airframes/tudelft/rotwing6.xml b/conf/airframes/tudelft/rotwing6.xml
index 3c22a3e626..63d4dda8cf 100644
--- a/conf/airframes/tudelft/rotwing6.xml
+++ b/conf/airframes/tudelft/rotwing6.xml
@@ -1,13 +1,13 @@
-
- RotatingWing25Kg
+
+ RotatingWing 6
@@ -40,6 +40,13 @@
+
+
+
+
+
+
+
@@ -57,6 +64,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -72,7 +91,7 @@
-
+
@@ -95,7 +114,7 @@
-
+
@@ -155,7 +174,7 @@
-
+
@@ -175,7 +194,7 @@
-
+
@@ -190,7 +209,7 @@
-
+
@@ -206,7 +225,7 @@
-
+
@@ -218,9 +237,9 @@
-
+
-
+
@@ -232,13 +251,13 @@
-
+
-
+
-
+
@@ -258,71 +277,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -331,13 +287,13 @@
-
-
+
+
-
+
@@ -352,7 +308,7 @@
-
+
@@ -371,201 +327,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -582,8 +346,20 @@
- Put UAV on take-off location
- Check flight plan
- Switch to correct flight block
+ - Switch on drone tag
- Switch on camera
- Arm parachute
- Announce flight to other airspace users
+
+
+
+
diff --git a/conf/airframes/tudelft/rotwing_25kg_common.xml b/conf/airframes/tudelft/rotwing_25kg_common.xml
new file mode 100644
index 0000000000..37d3fe5877
--- /dev/null
+++ b/conf/airframes/tudelft/rotwing_25kg_common.xml
@@ -0,0 +1,258 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/airframes/tudelft/rotwing_7kg_common.xml b/conf/airframes/tudelft/rotwing_7kg_common.xml
new file mode 100644
index 0000000000..598d9c533e
--- /dev/null
+++ b/conf/airframes/tudelft/rotwing_7kg_common.xml
@@ -0,0 +1,316 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/airframes/tudelft/rotwing_v3b.xml b/conf/airframes/tudelft/rotwing_v3b.xml
index f1a8fce855..e67f2fc5be 100644
--- a/conf/airframes/tudelft/rotwing_v3b.xml
+++ b/conf/airframes/tudelft/rotwing_v3b.xml
@@ -30,16 +30,12 @@
+
-
-
-
-
-
@@ -69,6 +65,7 @@
+
@@ -99,12 +96,17 @@
+
+
+
+
+
@@ -141,64 +143,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -257,9 +201,9 @@
-
-
-
+
+
+
@@ -270,7 +214,7 @@
-
+
@@ -295,36 +239,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -333,7 +248,7 @@
-
+
@@ -342,7 +257,7 @@
-
+
@@ -441,33 +356,10 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ - Enter the PIC
+ - Enter the PAC
+ - Enter the GCS op
+ - Goal of the flight
+ - Location, airspace and weather
+ - Check the RC battery
+ - Check tail connection
+ - Check wings taped and secured
+ - Inspect airframe condition
+ - Check attitude and heading
+ - Airspeed sensor calibration
+ - Put UAV on take-off location
+ - Automated actuator check
+ - Check flight plan
+ - Switch to correct flight block
+ - Switch on drone tag
+ - Switch on camera
+ - Announce flight to other airspace users
+
-
-
-
- - Enter the PIC
- - Enter the PAC
- - Enter the GCS op
- - Goal of the flight
- - Location, airspace and weather
- - Check the RC battery
- - Check tail connection
- - Check wings taped and secured
- - Check attitude and heading
- - Put UAV on take-off location
- - Check flight plan
- - Switch to correct flight block
- - Switch on camera
- - Announce flight to other airspace users
-
+
diff --git a/conf/airframes/tudelft/rotwing_v3d.xml b/conf/airframes/tudelft/rotwing_v3d.xml
index d14796ae4e..18d7d82e05 100644
--- a/conf/airframes/tudelft/rotwing_v3d.xml
+++ b/conf/airframes/tudelft/rotwing_v3d.xml
@@ -30,6 +30,7 @@
+
@@ -56,6 +57,7 @@
+
@@ -70,7 +72,7 @@
-
+
@@ -82,8 +84,12 @@
+
+
+
+
@@ -92,6 +98,7 @@
+
@@ -128,73 +135,15 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -206,10 +155,10 @@
-
-
-
-
+
+
+
+
@@ -244,9 +193,9 @@
-
-
-
+
+
+
@@ -257,7 +206,7 @@
-
+
@@ -268,7 +217,7 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -429,37 +349,10 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Enter the PIC
- Enter the PAC
@@ -676,7 +382,19 @@
- Automated actuator check
- Check flight plan
- Switch to correct flight block
+ - Switch on drone tag
- Switch on camera
- Announce flight to other airspace users
+
+
+
+
diff --git a/conf/airframes/tudelft/rotwing_v3e.xml b/conf/airframes/tudelft/rotwing_v3e.xml
index 9c31d6a42d..e87c0e75a1 100644
--- a/conf/airframes/tudelft/rotwing_v3e.xml
+++ b/conf/airframes/tudelft/rotwing_v3e.xml
@@ -30,6 +30,7 @@
+
@@ -56,6 +57,7 @@
+
@@ -82,8 +84,12 @@
+
+
+
+
@@ -92,6 +98,7 @@
+
@@ -128,64 +135,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -194,7 +143,7 @@
-
+
@@ -244,9 +193,9 @@
-
-
-
+
+
+
@@ -257,7 +206,7 @@
-
+
@@ -268,7 +217,7 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -429,37 +349,10 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Enter the PIC
- Enter the PAC
@@ -676,7 +382,19 @@
- Automated actuator check
- Check flight plan
- Switch to correct flight block
+ - Switch on drone tag
- Switch on camera
- Announce flight to other airspace users
+
+
+
+
diff --git a/conf/airframes/tudelft/rotwing_v3f.xml b/conf/airframes/tudelft/rotwing_v3f.xml
index 31b8bfd117..dd3c8255bb 100644
--- a/conf/airframes/tudelft/rotwing_v3f.xml
+++ b/conf/airframes/tudelft/rotwing_v3f.xml
@@ -30,6 +30,7 @@
+
@@ -56,6 +57,7 @@
+
@@ -70,7 +72,7 @@
-
+
@@ -82,8 +84,12 @@
+
+
+
+
@@ -92,6 +98,7 @@
+
@@ -128,64 +135,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -194,14 +143,14 @@
-
+
-
+
@@ -244,9 +193,9 @@
-
-
-
+
+
+
@@ -257,18 +206,18 @@
-
+
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -382,7 +302,7 @@
-
+
@@ -429,37 +349,10 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Enter the PIC
- Enter the PAC
@@ -676,7 +382,19 @@
- Automated actuator check
- Check flight plan
- Switch to correct flight block
+ - Switch on drone tag
- Switch on camera
- Announce flight to other airspace users
+
+
+
+
diff --git a/conf/airframes/tudelft/rotwing_v3g.xml b/conf/airframes/tudelft/rotwing_v3g.xml
index ac76f9f699..0b124d6b49 100644
--- a/conf/airframes/tudelft/rotwing_v3g.xml
+++ b/conf/airframes/tudelft/rotwing_v3g.xml
@@ -57,6 +57,7 @@
+
@@ -71,7 +72,7 @@
-
+
@@ -97,6 +98,7 @@
+
@@ -133,64 +135,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -199,14 +143,14 @@
-
-
+
+
-
+
@@ -249,9 +193,9 @@
-
-
-
+
+
+
@@ -262,7 +206,7 @@
-
+
@@ -273,7 +217,7 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -387,7 +302,7 @@
-
+
@@ -434,41 +349,28 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -477,193 +379,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Enter the PIC
- Enter the PAC
@@ -680,7 +395,19 @@
- Automated actuator check
- Check flight plan
- Switch to correct flight block
+ - Switch on drone tag
- Switch on camera
- Announce flight to other airspace users
+
+
+
+
diff --git a/conf/airframes/tudelft/rotwing_v3h.xml b/conf/airframes/tudelft/rotwing_v3h.xml
index 47e9eb564d..0816565335 100644
--- a/conf/airframes/tudelft/rotwing_v3h.xml
+++ b/conf/airframes/tudelft/rotwing_v3h.xml
@@ -57,6 +57,7 @@
+
@@ -71,7 +72,7 @@
-
+
@@ -97,6 +98,7 @@
+
@@ -133,64 +135,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -199,14 +143,14 @@
-
-
+
+
-
+
@@ -249,9 +193,9 @@
-
-
-
+
+
+
@@ -262,7 +206,7 @@
-
+
@@ -273,7 +217,7 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -434,36 +349,10 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Enter the PIC
- Enter the PAC
@@ -678,7 +382,19 @@
- Automated actuator check
- Check flight plan
- Switch to correct flight block
+ - Switch on drone tag
- Switch on camera
- Announce flight to other airspace users
+
+
+
+
diff --git a/conf/flight_plans/tudelft/rotating_wing_EHR8.xml b/conf/flight_plans/tudelft/rotating_wing_EHR8.xml
index ff81f7d2ef..25cfe36055 100644
--- a/conf/flight_plans/tudelft/rotating_wing_EHR8.xml
+++ b/conf/flight_plans/tudelft/rotating_wing_EHR8.xml
@@ -53,34 +53,35 @@
-
+
-
+
-
+
-
+
+
-
+
@@ -92,31 +93,31 @@
-
+
-
+
-
+
-
+
-
+
@@ -124,7 +125,7 @@
-
+
@@ -132,47 +133,47 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -180,7 +181,7 @@
-
+
diff --git a/conf/flight_plans/tudelft/rotating_wing_EHVB.xml b/conf/flight_plans/tudelft/rotating_wing_EHVB.xml
index d8bf210d59..c1c2551c4a 100644
--- a/conf/flight_plans/tudelft/rotating_wing_EHVB.xml
+++ b/conf/flight_plans/tudelft/rotating_wing_EHVB.xml
@@ -1,5 +1,5 @@
-
+
@@ -53,34 +53,35 @@
-
+
-
+
-
+
-
+
+
-
+
-
+
@@ -94,52 +95,44 @@
-
+
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
-
+
-
+
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -215,7 +198,7 @@
-
+
diff --git a/conf/flight_plans/tudelft/rotating_wing_terschelling.xml b/conf/flight_plans/tudelft/rotating_wing_terschelling.xml
deleted file mode 100644
index 3ec0767f32..0000000000
--- a/conf/flight_plans/tudelft/rotating_wing_terschelling.xml
+++ /dev/null
@@ -1,166 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/conf/flight_plans/tudelft/rotating_wing_tharde.xml b/conf/flight_plans/tudelft/rotating_wing_tharde.xml
index 69b620d915..e71fe39720 100644
--- a/conf/flight_plans/tudelft/rotating_wing_tharde.xml
+++ b/conf/flight_plans/tudelft/rotating_wing_tharde.xml
@@ -40,28 +40,28 @@
-
+
-
+
-
+
-
+
-
+
@@ -70,24 +70,24 @@
-
+
-
+
-
+
-
+
@@ -95,7 +95,7 @@
-
+
@@ -103,47 +103,47 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -151,7 +151,7 @@
-
+
diff --git a/conf/flight_plans/tudelft/rotating_wing_troia.xml b/conf/flight_plans/tudelft/rotating_wing_troia.xml
new file mode 100644
index 0000000000..9adef32f28
--- /dev/null
+++ b/conf/flight_plans/tudelft/rotating_wing_troia.xml
@@ -0,0 +1,309 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/modules/eff_scheduling_rotwing.xml b/conf/modules/eff_scheduling_rotwing.xml
index fc002d8105..0d206200d0 100644
--- a/conf/modules/eff_scheduling_rotwing.xml
+++ b/conf/modules/eff_scheduling_rotwing.xml
@@ -22,7 +22,12 @@
-
+
+
+
+
+
+
@@ -67,4 +72,4 @@
-
+
\ No newline at end of file
diff --git a/conf/modules/guidance_indi_hybrid.xml b/conf/modules/guidance_indi_hybrid.xml
index ffc50824b8..47394e3a14 100644
--- a/conf/modules/guidance_indi_hybrid.xml
+++ b/conf/modules/guidance_indi_hybrid.xml
@@ -7,10 +7,14 @@
- guidance_indi_hybid_tailsitter
- guidance_indi_hybid_quadplane
-
+
@@ -24,11 +28,17 @@
-
+
+
+
+
+
+
+
diff --git a/conf/modules/rotwing_state.xml b/conf/modules/rotwing_state.xml
index 2eb1fcc33c..9af4f76bb8 100644
--- a/conf/modules/rotwing_state.xml
+++ b/conf/modules/rotwing_state.xml
@@ -3,26 +3,28 @@
This module keeps track of the current state of a rotating wing drone and desired state set by the RC or flightplan. Paramters are being scheduled in each change of a current state and desired state. Functions are defined in this module to call the actual state and desired state and set a desired state.
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
+
+
diff --git a/conf/telemetry/highspeed_rotorcraft.xml b/conf/telemetry/highspeed_rotorcraft.xml
index 3437509e1e..e6e0209038 100644
--- a/conf/telemetry/highspeed_rotorcraft.xml
+++ b/conf/telemetry/highspeed_rotorcraft.xml
@@ -24,7 +24,7 @@
-
+
@@ -42,7 +42,7 @@
-
+
@@ -64,6 +64,8 @@
+
+
@@ -276,10 +278,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -327,7 +384,7 @@
-
+
@@ -347,6 +404,7 @@
+
diff --git a/conf/userconf/tudelft/RW_control_panel.xml b/conf/userconf/tudelft/RW_control_panel.xml
index 23e8fab250..5d8c7db428 100644
--- a/conf/userconf/tudelft/RW_control_panel.xml
+++ b/conf/userconf/tudelft/RW_control_panel.xml
@@ -1506,5 +1506,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/userconf/tudelft/conf.xml b/conf/userconf/tudelft/conf.xml
index 45c7d655f3..afb58b072a 100644
--- a/conf/userconf/tudelft/conf.xml
+++ b/conf/userconf/tudelft/conf.xml
@@ -610,7 +610,7 @@
airframe="airframes/tudelft/rotwing_v3f.xml"
radio="radios/crossfire_sbus.xml"
telemetry="telemetry/highspeed_rotorcraft.xml"
- flight_plan="flight_plans/tudelft/rotating_wing_EHVB.xml"
+ flight_plan="flight_plans/tudelft/rotating_wing_troia.xml"
settings="settings/rotorcraft_basic.xml"
settings_modules="modules/air_data.xml modules/airspeed_ms45xx_i2c.xml modules/airspeed_uavcan.xml modules/approach_moving_target.xml modules/eff_scheduling_rotwing.xml modules/ekf_aw.xml modules/electrical.xml modules/follow_me.xml modules/gps.xml modules/gps_ublox.xml modules/guidance_indi_hybrid.xml modules/guidance_rotorcraft.xml modules/imu_common.xml modules/imu_heater.xml modules/ins_ekf2.xml modules/logger_sd_chibios.xml modules/nav_hybrid.xml modules/nav_rotorcraft.xml modules/parachute.xml modules/pfc_actuators.xml modules/preflight_checks.xml modules/rotwing_state.xml modules/stabilization_indi.xml modules/sys_id_auto_doublets.xml modules/sys_id_doublet.xml modules/target_pos.xml"
gui_color="red"
@@ -665,9 +665,9 @@
airframe="airframes/tudelft/rotwing5.xml"
radio="radios/crossfire_sbus.xml"
telemetry="telemetry/highspeed_rotorcraft.xml"
- flight_plan="flight_plans/tudelft/rotating_wing_EHVB.xml"
+ flight_plan="flight_plans/tudelft/rotating_wing_troia.xml"
settings="settings/rotorcraft_basic.xml"
- settings_modules="modules/actuators_faulhaber.xml modules/air_data.xml modules/airspeed_ms45xx_i2c.xml modules/airspeed_uavcan.xml modules/approach_moving_target.xml modules/eff_scheduling_rotwing.xml modules/electrical.xml modules/follow_me.xml modules/gps.xml modules/gps_ublox.xml modules/guidance_indi_hybrid.xml modules/guidance_rotorcraft.xml modules/imu_common.xml modules/imu_heater.xml modules/ins_ekf2.xml modules/logger_sd_chibios.xml modules/nav_hybrid.xml modules/nav_rotorcraft.xml modules/preflight_checks.xml modules/rotwing_state.xml modules/stabilization_indi.xml modules/sys_id_auto_doublets.xml modules/sys_id_doublet.xml modules/target_pos.xml"
+ settings_modules="modules/actuators_faulhaber.xml modules/air_data.xml modules/airspeed_ms45xx_i2c.xml modules/airspeed_uavcan.xml modules/approach_moving_target.xml modules/eff_scheduling_rotwing.xml modules/electrical.xml modules/gps.xml modules/gps_ublox.xml modules/guidance_indi_hybrid.xml modules/guidance_rotorcraft.xml modules/imu_common.xml modules/imu_heater.xml modules/ins_ekf2.xml modules/logger_sd_chibios.xml modules/nav_hybrid.xml modules/nav_rotorcraft.xml modules/preflight_checks.xml modules/rotwing_state.xml modules/stabilization_indi.xml modules/sys_id_auto_doublets.xml modules/sys_id_doublet.xml modules/target_pos.xml"
gui_color="red"
/>
-
-
+
+
@@ -229,8 +229,8 @@
-
-
+
+
@@ -294,6 +294,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sw/airborne/firmwares/rotorcraft/guidance/guidance_indi_hybrid.c b/sw/airborne/firmwares/rotorcraft/guidance/guidance_indi_hybrid.c
index adcdc277d4..bf4d9d354e 100644
--- a/sw/airborne/firmwares/rotorcraft/guidance/guidance_indi_hybrid.c
+++ b/sw/airborne/firmwares/rotorcraft/guidance/guidance_indi_hybrid.c
@@ -71,6 +71,42 @@
#define GUIDANCE_INDI_LIFTD_P50 (GUIDANCE_INDI_LIFTD_P80/2)
#endif
+#ifndef GUIDANCE_INDI_MAX_AIRSPEED
+#error "You must have an airspeed sensor to use this guidance"
+#endif
+
+#ifndef GUIDANCE_INDI_MIN_AIRSPEED
+#define GUIDANCE_INDI_MIN_AIRSPEED -10.f
+#endif
+
+/**
+ * Climb speed when navigation is making turns instead of direct lines
+ */
+#ifndef GUIDANCE_INDI_FWD_CLIMB_SPEED
+#define GUIDANCE_INDI_FWD_CLIMB_SPEED 4.0
+#endif
+
+/**
+ * Descend speed when navigation is making turns instead of direct lines
+ */
+#ifndef GUIDANCE_INDI_FWD_DESCEND_SPEED
+#define GUIDANCE_INDI_FWD_DESCEND_SPEED -4.0
+#endif
+
+/**
+ * Climb speed when navigation is doing direct lines
+ */
+#ifndef GUIDANCE_INDI_QUAD_CLIMB_SPEED
+#define GUIDANCE_INDI_QUAD_CLIMB_SPEED 2.0
+#endif
+
+/**
+ * Descend speed when navigation is doing direct lines
+ */
+#ifndef GUIDANCE_INDI_QUAD_DESCEND_SPEED
+#define GUIDANCE_INDI_QUAD_DESCEND_SPEED -2.0
+#endif
+
struct guidance_indi_hybrid_params gih_params = {
.pos_gain = GUIDANCE_INDI_POS_GAIN,
.pos_gainz = GUIDANCE_INDI_POS_GAINZ,
@@ -82,13 +118,15 @@ struct guidance_indi_hybrid_params gih_params = {
.liftd_asq = GUIDANCE_INDI_LIFTD_ASQ, // coefficient of airspeed squared
.liftd_p80 = GUIDANCE_INDI_LIFTD_P80,
.liftd_p50 = GUIDANCE_INDI_LIFTD_P50,
+ .min_airspeed = GUIDANCE_INDI_MIN_AIRSPEED,
+ .max_airspeed = GUIDANCE_INDI_MAX_AIRSPEED,
+ .stall_protect_gain = 1.5, // m/s^2 downward acceleration per m/s airspeed loss
+ .climb_vspeed_fwd = GUIDANCE_INDI_FWD_CLIMB_SPEED,
+ .descend_vspeed_fwd = GUIDANCE_INDI_FWD_DESCEND_SPEED,
+ .climb_vspeed_quad = GUIDANCE_INDI_QUAD_CLIMB_SPEED,
+ .descend_vspeed_quad = GUIDANCE_INDI_QUAD_DESCEND_SPEED,
};
-#ifndef GUIDANCE_INDI_MAX_AIRSPEED
-#error "You must have an airspeed sensor to use this guidance"
-#endif
-float guidance_indi_max_airspeed = GUIDANCE_INDI_MAX_AIRSPEED;
-
// Quadplanes can hover at various pref pitch
float guidance_indi_pitch_pref_deg = 0;
@@ -113,7 +151,7 @@ float guidance_indi_pitch_pref_deg = 0;
/*Airspeed threshold where making a turn is "worth it"*/
#ifndef TURN_AIRSPEED_TH
-#define TURN_AIRSPEED_TH 10.0
+#define TURN_AIRSPEED_TH 13 .0
#endif
/*Boolean to force the heading to a static value (only use for specific experiments)*/
@@ -158,20 +196,21 @@ static void guidance_indi_filter_thrust(void);
#define GUIDANCE_INDI_AIRSPEED_FILT_CUTOFF 0.5
#endif
-#ifndef GUIDANCE_INDI_CLIMB_SPEED_FWD
-#define GUIDANCE_INDI_CLIMB_SPEED_FWD 4.0
-#endif
-
-#ifndef GUIDANCE_INDI_DESCEND_SPEED_FWD
-#define GUIDANCE_INDI_DESCEND_SPEED_FWD -4.0
-#endif
-
#ifndef GUIDANCE_INDI_MAX_LAT_ACCEL
#define GUIDANCE_INDI_MAX_LAT_ACCEL 9.81
#endif
-float climb_vspeed_fwd = GUIDANCE_INDI_CLIMB_SPEED_FWD;
-float descend_vspeed_fwd = GUIDANCE_INDI_DESCEND_SPEED_FWD;
+#ifndef GUIDANCE_INDI_COORDINATED_TURN_MIN_AIRSPEED
+#define GUIDANCE_INDI_COORDINATED_TURN_MIN_AIRSPEED 10.0
+#endif
+
+#ifndef GUIDANCE_INDI_COORDINATED_TURN_MAX_AIRSPEED
+#define GUIDANCE_INDI_COORDINATED_TURN_MAX_AIRSPEED 30.0
+#endif
+
+#ifndef GUIDANCE_INDI_COORDINATED_TURN_AIRSPEED_MARGIN
+#define GUIDANCE_INDI_COORDINATED_TURN_AIRSPEED_MARGIN 0.0
+#endif
float inv_eff[4];
@@ -179,6 +218,16 @@ float inv_eff[4];
float guidance_indi_max_bank = GUIDANCE_H_MAX_BANK;
float guidance_indi_min_pitch = GUIDANCE_INDI_MIN_PITCH;
+#if defined(ROTWING_STATE_FW_MAX_AIRSPEED) && defined(ROTWING_STATE_QUAD_MAX_AIRSPEED)
+ float gih_coordinated_turn_min_airspeed = ROTWING_STATE_QUAD_MAX_AIRSPEED;
+ float gih_coordinated_turn_max_airspeed = ROTWING_STATE_FW_MAX_AIRSPEED + GUIDANCE_INDI_COORDINATED_TURN_AIRSPEED_MARGIN;
+#else
+ float gih_coordinated_turn_min_airspeed = GUIDANCE_INDI_COORDINATED_TURN_MIN_AIRSPEED;
+ float gih_coordinated_turn_max_airspeed = GUIDANCE_INDI_COORDINATED_TURN_MAX_AIRSPEED + GUIDANCE_INDI_COORDINATED_TURN_AIRSPEED_MARGIN;
+#endif
+
+bool coordinated_turn_use_accel = false;
+
/** state eulers in zxy order */
struct FloatEulers eulers_zxy;
@@ -192,6 +241,7 @@ Butterworth2LowPass accely_filt;
Butterworth2LowPass guidance_indi_airspeed_filt;
struct FloatVect2 desired_airspeed;
+float gi_unbounded_airspeed_sp = 0.f;
float Ga[GUIDANCE_INDI_HYBRID_V][GUIDANCE_INDI_HYBRID_U];
struct FloatVect3 euler_cmd;
@@ -247,6 +297,7 @@ struct FloatVect3 indi_vel_sp = {0.0, 0.0, 0.0};
float time_of_vel_sp = 0.0;
void guidance_indi_propagate_filters(void);
+void guidance_indi_set_min_max_airspeed(float min_airspeed, float max_airspeed);
#if PERIODIC_TELEMETRY
#include "modules/datalink/telemetry.h"
@@ -344,7 +395,7 @@ void guidance_indi_enter(void)
thrust_in = stabilization.cmd[COMMAND_THRUST];
thrust_act = thrust_in;
- guidance_indi_hybrid_heading_sp = stateGetNedToBodyEulers_f()->psi;
+ guidance_indi_hybrid_heading_sp = eulers_zxy.psi;
float tau = 1.0 / (2.0 * M_PI * filter_cutoff);
float sample_time = 1.0 / PERIODIC_FREQUENCY;
@@ -352,9 +403,6 @@ void guidance_indi_enter(void)
init_butterworth_2_low_pass(&filt_accel_ned[i], tau, sample_time, 0.0);
}
- /*Obtain eulers with zxy rotation order*/
- float_eulers_of_quat_zxy(&eulers_zxy, stateGetNedToBodyQuat_f());
-
init_butterworth_2_low_pass(&roll_filt, tau, sample_time, eulers_zxy.phi);
init_butterworth_2_low_pass(&pitch_filt, tau, sample_time, eulers_zxy.theta);
init_butterworth_2_low_pass(&thrust_filt, tau, sample_time, thrust_in);
@@ -364,6 +412,11 @@ void guidance_indi_enter(void)
init_butterworth_2_low_pass(&guidance_indi_airspeed_filt, tau_guidance_indi_airspeed, sample_time, 0.0);
}
+void guidance_indi_set_min_max_airspeed(float min_airspeed, float max_airspeed) {
+ gih_params.min_airspeed = min_airspeed;
+ gih_params.max_airspeed = max_airspeed;
+}
+
/**
* @param accel_sp accel setpoint in NED frame [m/s^2]
* @param heading_sp the desired heading [rad]
@@ -459,7 +512,7 @@ struct StabilizationSetpoint guidance_indi_run(struct FloatVect3 *accel_sp, floa
float airspeed_turn = stateGetAirspeed_f();
#endif
// We are dividing by the airspeed, so a lower bound is important
- Bound(airspeed_turn, 10.0f, 30.0f);
+ Bound(airspeed_turn, gih_coordinated_turn_min_airspeed, gih_coordinated_turn_max_airspeed);
guidance_euler_cmd.phi = roll_filt.o[0] + euler_cmd.x;
guidance_euler_cmd.theta = pitch_filt.o[0] + euler_cmd.y;
@@ -586,6 +639,7 @@ static struct FloatVect3 compute_accel_from_speed_sp(void)
float airspeed = 0.f;
#else
float airspeed = stateGetAirspeed_f();
+ Bound(airspeed, 0.0f, 100.0f);
if (guidance_indi_airspeed_filtering) {
airspeed = guidance_indi_airspeed_filt.o[0];
}
@@ -598,18 +652,27 @@ static struct FloatVect3 compute_accel_from_speed_sp(void)
VECT2_DIFF(desired_airspeed, gi_speed_sp, windspeed); // Use 2d part of gi_speed_sp
float norm_des_as = FLOAT_VECT2_NORM(desired_airspeed);
- // Make turn instead of straight line
+ gi_unbounded_airspeed_sp = norm_des_as;
+
+ // Check if some minimum airspeed is desired (e.g. to prevent stall)
+ if (norm_des_as < gih_params.min_airspeed) {
+ norm_des_as = gih_params.min_airspeed;
+ }
+
+ float gi_airspeed_sp = norm_des_as;
+
+ // Make turn instead of straight line, control airspeed
if ((airspeed > TURN_AIRSPEED_TH) && (norm_des_as > (TURN_AIRSPEED_TH+2.0f))) {
// Give the wind cancellation priority.
- if (norm_des_as > guidance_indi_max_airspeed) {
+ if (norm_des_as > gih_params.max_airspeed) {
float groundspeed_factor = 0.0f;
// if the wind is faster than we can fly, just fly in the wind direction
- if (FLOAT_VECT2_NORM(windspeed) < guidance_indi_max_airspeed) {
+ if (FLOAT_VECT2_NORM(windspeed) < gih_params.max_airspeed) {
float av = gi_speed_sp.x * gi_speed_sp.x + gi_speed_sp.y * gi_speed_sp.y;
float bv = -2.f * (windspeed.x * gi_speed_sp.x + windspeed.y * gi_speed_sp.y);
- float cv = windspeed.x * windspeed.x + windspeed.y * windspeed.y - guidance_indi_max_airspeed * guidance_indi_max_airspeed;
+ float cv = windspeed.x * windspeed.x + windspeed.y * windspeed.y - gih_params.max_airspeed * gih_params.max_airspeed;
float dv = bv * bv - 4.0f * av * cv;
@@ -625,14 +688,11 @@ static struct FloatVect3 compute_accel_from_speed_sp(void)
desired_airspeed.x = groundspeed_factor * gi_speed_sp.x - windspeed.x;
desired_airspeed.y = groundspeed_factor * gi_speed_sp.y - windspeed.y;
- speed_sp_b_x = guidance_indi_max_airspeed;
+ gi_airspeed_sp = gih_params.max_airspeed;
}
- // desired airspeed can not be larger than max airspeed
- speed_sp_b_x = Min(norm_des_as, guidance_indi_max_airspeed);
-
if (force_forward) {
- speed_sp_b_x = guidance_indi_max_airspeed;
+ gi_airspeed_sp = gih_params.max_airspeed;
}
// Calculate accel sp in body axes, because we need to regulate airspeed
@@ -645,7 +705,7 @@ static struct FloatVect3 compute_accel_from_speed_sp(void)
BoundAbs(sp_accel_b.y, GUIDANCE_INDI_MAX_LAT_ACCEL);
// Control the airspeed
- sp_accel_b.x = (speed_sp_b_x - airspeed) * gih_params.speed_gain;
+ sp_accel_b.x = (gi_airspeed_sp - airspeed) * gih_params.speed_gain;
accel_sp.x = cpsi * sp_accel_b.x - spsi * sp_accel_b.y;
accel_sp.y = spsi * sp_accel_b.x + cpsi * sp_accel_b.y;
@@ -659,8 +719,8 @@ static struct FloatVect3 compute_accel_from_speed_sp(void)
float speed_increment = speed_sp_b_x - groundspeed_x;
// limit groundspeed setpoint to max_airspeed + (diff gs and airspeed)
- if ((speed_increment + airspeed) > guidance_indi_max_airspeed) {
- speed_sp_b_x = guidance_indi_max_airspeed + groundspeed_x - airspeed;
+ if ((speed_increment + airspeed) > gih_params.max_airspeed) {
+ speed_sp_b_x = gih_params.max_airspeed + groundspeed_x - airspeed;
}
}
@@ -673,22 +733,25 @@ static struct FloatVect3 compute_accel_from_speed_sp(void)
}
// Bound the acceleration setpoint
- float accelbound = 3.0f + airspeed / guidance_indi_max_airspeed * 5.0f; // FIXME remove hard coded values
+ float accelbound = 3.0f + airspeed / gih_params.max_airspeed * 5.0f; // FIXME remove hard coded values
float_vect3_bound_in_2d(&accel_sp, accelbound);
- /*BoundAbs(sp_accel.x, 3.0 + airspeed/guidance_indi_max_airspeed*6.0);*/
- /*BoundAbs(sp_accel.y, 3.0 + airspeed/guidance_indi_max_airspeed*6.0);*/
BoundAbs(accel_sp.z, 3.0);
+ if (!rotwing_state_pusher_motor_running() && !rotwing_state_hover_motors_running()) {
+ accel_sp.z = gih_params.stall_protect_gain * (gi_airspeed_sp - airspeed);
+ BoundAbs(accel_sp.z, 5.0);
+ }
+
return accel_sp;
}
static float bound_vz_sp(float vz_sp)
{
// Bound vertical speed setpoint
- if (stateGetAirspeed_f() > 13.f) {
- Bound(vz_sp, -climb_vspeed_fwd, -descend_vspeed_fwd);
+ if (stateGetAirspeed_f() > TURN_AIRSPEED_TH) {
+ Bound(vz_sp, -gih_params.climb_vspeed_fwd, -gih_params.descend_vspeed_fwd);
} else {
- Bound(vz_sp, -nav.climb_vspeed, -nav.descend_vspeed); // FIXME don't use nav settings
+ Bound(vz_sp, -gih_params.climb_vspeed_quad, -gih_params.descend_vspeed_quad);
}
return vz_sp;
}
@@ -804,6 +867,7 @@ void guidance_indi_propagate_filters(void)
update_butterworth_2_low_pass(&accely_filt, accely);
float airspeed = stateGetAirspeed_f();
+ Bound(airspeed, 0.0f, 100.0f);
update_butterworth_2_low_pass(&guidance_indi_airspeed_filt, airspeed);
}
diff --git a/sw/airborne/firmwares/rotorcraft/guidance/guidance_indi_hybrid.h b/sw/airborne/firmwares/rotorcraft/guidance/guidance_indi_hybrid.h
index 7385d1fff3..0540aa8ce6 100644
--- a/sw/airborne/firmwares/rotorcraft/guidance/guidance_indi_hybrid.h
+++ b/sw/airborne/firmwares/rotorcraft/guidance/guidance_indi_hybrid.h
@@ -70,6 +70,7 @@ enum GuidanceIndiHybrid_VMode {
extern struct StabilizationSetpoint guidance_indi_run(struct FloatVect3 *accep_sp, float heading_sp);
extern struct StabilizationSetpoint guidance_indi_run_mode(bool in_flight, struct HorizontalGuidance *gh, struct VerticalGuidance *gv, enum GuidanceIndiHybrid_HMode h_mode, enum GuidanceIndiHybrid_VMode v_mode);
+extern void guidance_indi_set_min_max_airspeed(float min_airspeed, float max_airspeed);
struct guidance_indi_hybrid_params {
float pos_gain;
@@ -80,30 +81,32 @@ struct guidance_indi_hybrid_params {
float liftd_asq;
float liftd_p80;
float liftd_p50;
+ float min_airspeed;
+ float max_airspeed;
+ float stall_protect_gain;
+ float climb_vspeed_fwd;
+ float descend_vspeed_fwd;
+ float climb_vspeed_quad;
+ float descend_vspeed_quad;
};
extern struct FloatVect3 sp_accel;
extern struct FloatVect3 gi_speed_sp;
+extern struct guidance_indi_hybrid_params gih_params;
extern float guidance_indi_pitch_pref_deg;
-#if GUIDANCE_INDI_HYBRID_USE_WLS
-extern float Wu_gih[GUIDANCE_INDI_HYBRID_U];
-extern float Wv_gih[GUIDANCE_INDI_HYBRID_V];
-extern float du_min_gih[GUIDANCE_INDI_HYBRID_U];
-extern float du_max_gih[GUIDANCE_INDI_HYBRID_U];
-extern float du_pref_gih[GUIDANCE_INDI_HYBRID_U];
-#endif
+extern float gi_unbounded_airspeed_sp;
extern float guidance_indi_thrust_z_eff;
extern struct guidance_indi_hybrid_params gih_params;
extern float guidance_indi_specific_force_gain;
-extern float guidance_indi_max_airspeed;
extern bool take_heading_control;
extern float guidance_indi_max_bank;
extern float guidance_indi_min_pitch;
extern bool force_forward; ///< forward flight for hybrid nav
extern bool guidance_indi_airspeed_filtering;
+extern bool coordinated_turn_use_accel;
#endif /* GUIDANCE_INDI_HYBRID_H */
diff --git a/sw/airborne/firmwares/rotorcraft/navigation.c b/sw/airborne/firmwares/rotorcraft/navigation.c
index b15380fc92..a3bb4e6e8b 100644
--- a/sw/airborne/firmwares/rotorcraft/navigation.c
+++ b/sw/airborne/firmwares/rotorcraft/navigation.c
@@ -267,9 +267,12 @@ void nav_periodic_task(void)
bool nav_detect_ground(void)
{
- if (!autopilot.ground_detected) { return false; }
- autopilot.ground_detected = false;
- return true;
+ if (autopilot.ground_detected) {
+ autopilot.ground_detected = false;
+ return true;
+ } else {
+ return false;
+ }
}
bool nav_is_in_flight(void)
diff --git a/sw/airborne/modules/ctrl/eff_scheduling_rotwing.c b/sw/airborne/modules/ctrl/eff_scheduling_rotwing.c
index 7717dd3142..0aa5d75243 100644
--- a/sw/airborne/modules/ctrl/eff_scheduling_rotwing.c
+++ b/sw/airborne/modules/ctrl/eff_scheduling_rotwing.c
@@ -130,6 +130,7 @@ struct rotwing_eff_sched_param_t eff_sched_p = {
.Ixx_wing = ROTWING_EFF_SCHED_IXX_WING,
.Iyy_wing = ROTWING_EFF_SCHED_IYY_WING,
.m = ROTWING_EFF_SCHED_M,
+ .DMdpprz_hover_pitch = ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_PITCH,
.DMdpprz_hover_roll = ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_ROLL,
.hover_roll_pitch_coef = ROTWING_EFF_SCHED_HOVER_ROLL_PITCH_COEF,
.hover_roll_roll_coef = ROTWING_EFF_SCHED_HOVER_ROLL_ROLL_COEF,
@@ -146,9 +147,28 @@ struct rotwing_eff_sched_param_t eff_sched_p = {
.k_lift_tail = ROTWING_EFF_SCHED_K_LIFT_TAIL
};
-float eff_sched_pusher_time = 0.002;
+int32_t rw_flap_offset = 0;
-float roll_eff_scaling = 1.f;
+// for negative values, still should be low_lim < up_lim
+inline float bound_or_zero(float value, float low_lim, float up_lim) {
+ float output = value;
+ if (low_lim > 0.f) {
+ if (value < low_lim) {
+ output = 0.f;
+ } else if (value > up_lim) {
+ output = up_lim;
+ }
+ } else {
+ if (value > up_lim) {
+ output = 0.f;
+ } else if (value < low_lim) {
+ output = low_lim;
+ }
+ }
+ return output;
+}
+
+float eff_sched_pusher_time = 0.002;
struct rotwing_eff_sched_var_t eff_sched_var;
@@ -204,8 +224,9 @@ void eff_scheduling_rotwing_init(void)
eff_sched_var.sinr3 = 0;
// Set moment derivative variables
- eff_sched_var.pitch_motor_dMdpprz = ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_PITCH;
- eff_sched_var.roll_motor_dMdpprz = (eff_sched_p.DMdpprz_hover_roll[0] + (MAX_PPRZ/2.) * eff_sched_p.DMdpprz_hover_roll[1]) / 10000.; // Dmdpprz hover roll for hover thrust
+ float hover_thrust = 6000;
+ eff_sched_var.pitch_motor_dMdpprz = (eff_sched_p.DMdpprz_hover_pitch[0] + 2*hover_thrust * eff_sched_p.DMdpprz_hover_pitch[1]) / 10000.; // Dmdpprz hover pitch for hover thrust
+ eff_sched_var.roll_motor_dMdpprz = (eff_sched_p.DMdpprz_hover_roll[0] + 2*hover_thrust * eff_sched_p.DMdpprz_hover_roll[1]) / 10000.; // Dmdpprz hover roll for hover thrust
eff_sched_var.cmd_elevator = 0;
eff_sched_var.cmd_pusher = 0;
@@ -282,44 +303,45 @@ void eff_scheduling_rotwing_update_airspeed(void)
void eff_scheduling_rotwing_update_hover_motor_effectiveness(void)
{
- // Pitch motor effectiveness
+ float cmd_quat[4];
+ float dM_dpprz[4];
+ // Quadratic thrust (and therefore moment) model of the hover propellers
+ for (uint8_t i = 0; i < 4; i++) {
+ cmd_quat[i] = actuator_state_filt_vect[i];
+ Bound(cmd_quat[i], 2500, MAX_PPRZ);
- float pitch_motor_q_eff = eff_sched_var.pitch_motor_dMdpprz / eff_sched_var.Iyy;
-
- float cmd_right = actuator_state_filt_vect[1];
- float cmd_left = actuator_state_filt_vect[3];
- Bound(cmd_right, 3500, MAX_PPRZ);
- Bound(cmd_left, 3500, MAX_PPRZ);
+ if(i==0 || i==2) { // pitch motors
+ dM_dpprz[i] = (eff_sched_p.DMdpprz_hover_pitch[0] + 2*cmd_quat[i] * eff_sched_p.DMdpprz_hover_pitch[1]) / 10000.;
+ // Bound dM_dpprz to half and 2 times the hover effectiveness
+ Bound(dM_dpprz[i], eff_sched_var.pitch_motor_dMdpprz * 0.5, eff_sched_var.pitch_motor_dMdpprz * 2.0);
+ } else { // roll motors
+ dM_dpprz[i] = (eff_sched_p.DMdpprz_hover_roll[0] + 2*cmd_quat[i] * eff_sched_p.DMdpprz_hover_roll[1]) / 10000.;
+ Bound(dM_dpprz[i], eff_sched_var.roll_motor_dMdpprz * 0.5, eff_sched_var.roll_motor_dMdpprz * 2.0);
+ }
+ }
// Roll motor effectiveness
- float dM_dpprz_right = (eff_sched_p.DMdpprz_hover_roll[0] + cmd_right * eff_sched_p.DMdpprz_hover_roll[1]) / 10000.;
- float dM_dpprz_left = (eff_sched_p.DMdpprz_hover_roll[0] + cmd_left * eff_sched_p.DMdpprz_hover_roll[1]) / 10000.;
-
- dM_dpprz_right = dM_dpprz_right * roll_eff_scaling;
- dM_dpprz_left = dM_dpprz_left * roll_eff_scaling;
-
- // Bound dM_dpprz to half and 2 times the hover effectiveness
- Bound(dM_dpprz_right, eff_sched_var.roll_motor_dMdpprz * 0.5, eff_sched_var.roll_motor_dMdpprz * 2.0);
- Bound(dM_dpprz_left, eff_sched_var.roll_motor_dMdpprz * 0.5, eff_sched_var.roll_motor_dMdpprz * 2.0);
+ float dM_dpprz_right = dM_dpprz[1];
+ float dM_dpprz_left = dM_dpprz[3];;
float roll_motor_p_eff_right = -(dM_dpprz_right * eff_sched_var.cosr + eff_sched_p.hover_roll_roll_coef[0] * eff_sched_var.wing_rotation_rad * eff_sched_var.wing_rotation_rad * eff_sched_var.airspeed * eff_sched_var.cosr) / eff_sched_var.Ixx;
- Bound(roll_motor_p_eff_right, -1, -0.00001);
+ roll_motor_p_eff_right = bound_or_zero(roll_motor_p_eff_right, -1.f, -0.00001f);
float roll_motor_p_eff_left = (dM_dpprz_left * eff_sched_var.cosr + eff_sched_p.hover_roll_roll_coef[0] * eff_sched_var.wing_rotation_rad * eff_sched_var.wing_rotation_rad * eff_sched_var.airspeed * eff_sched_var.cosr) / eff_sched_var.Ixx;
if(autopilot.in_flight) {
float roll_motor_airspeed_compensation = eff_sched_p.hover_roll_roll_coef[1] * eff_sched_var.airspeed * eff_sched_var.cosr / eff_sched_var.Ixx;
roll_motor_p_eff_left += roll_motor_airspeed_compensation;
}
- Bound(roll_motor_p_eff_left, 0.00001, 1);
+ roll_motor_p_eff_left = bound_or_zero(roll_motor_p_eff_left, 0.00001f, 1.f);
float roll_motor_q_eff = (eff_sched_p.hover_roll_pitch_coef[0] * eff_sched_var.wing_rotation_rad + eff_sched_p.hover_roll_pitch_coef[1] * eff_sched_var.wing_rotation_rad * eff_sched_var.wing_rotation_rad * eff_sched_var.sinr) / eff_sched_var.Iyy;
Bound(roll_motor_q_eff, 0, 1);
// Update front pitch motor q effectiveness
- g1g2[1][0] = pitch_motor_q_eff; // pitch effectiveness front motor
+ g1g2[1][0] = dM_dpprz[0] / eff_sched_var.Iyy; // pitch effectiveness front motor
// Update back motor q effectiveness
- g1g2[1][2] = -pitch_motor_q_eff; // pitch effectiveness back motor
+ g1g2[1][2] = - dM_dpprz[2] / eff_sched_var.Iyy; // pitch effectiveness back motor
// Update right motor p and q effectiveness
g1g2[0][1] = roll_motor_p_eff_right; // roll effectiveness right motor (no airspeed compensation)
@@ -376,6 +398,11 @@ void eff_scheduling_rotwing_update_aileron_effectiveness(void)
float eff_x_aileron = dMxdpprz / eff_sched_var.Ixx;
Bound(eff_x_aileron, 0, 0.005)
g1g2[0][6] = eff_x_aileron;
+
+ float dMydpprz = 4.0*(eff_sched_p.k_aileron * eff_sched_var.airspeed2 * eff_sched_var.sinr2 * eff_sched_var.cosr) / 1000000.;
+ float eff_y_aileron = dMydpprz / eff_sched_var.Iyy;
+ eff_y_aileron = bound_or_zero(eff_y_aileron, 0.00003f, 0.005f);
+ g1g2[1][6] = eff_y_aileron;
}
void eff_scheduling_rotwing_update_flaperon_effectiveness(void)
@@ -427,11 +454,18 @@ void stabilization_indi_set_wls_settings(void)
wls_stab_p.u_min[i] = -MAX_PPRZ * act_is_servo[i];
wls_stab_p.u_max[i] = MAX_PPRZ;
wls_stab_p.u_pref[i] = act_pref[i];
- if (i == 5) {
- wls_stab_p.u_pref[i] = actuator_state_filt_vect[i]; // Set change in preferred state to 0 for elevator
+ if (i == 5) { // elevator
+ wls_stab_p.u_pref[i] = actuator_state_filt_vect[i]; // Set change in prefered state to 0 for elevator
wls_stab_p.u_min[i] = 0; // cmd 0 is lowest position for elevator
}
- if (i==8) {
+ if (i == 7) { // flaperons
+ // If an offset is used, limit the max differential command to prevent unilateral saturation.
+ int32_t flap_saturation_limit = MAX_PPRZ - abs(rw_flap_offset);
+ BoundAbs(flap_saturation_limit, MAX_PPRZ);
+ wls_stab_p.u_min[i] = -flap_saturation_limit;
+ wls_stab_p.u_max[i] = flap_saturation_limit;
+ }
+ if (i==8) { // pusher
// dt (min to max) MAX_PPRZ / (dt * f) dt_min == 0.002
Bound(eff_sched_pusher_time, 0.002, 5.);
float max_increment = MAX_PPRZ / (eff_sched_pusher_time * 500);
diff --git a/sw/airborne/modules/ctrl/eff_scheduling_rotwing.h b/sw/airborne/modules/ctrl/eff_scheduling_rotwing.h
index 5b08e15002..da59fcfcbf 100644
--- a/sw/airborne/modules/ctrl/eff_scheduling_rotwing.h
+++ b/sw/airborne/modules/ctrl/eff_scheduling_rotwing.h
@@ -36,6 +36,7 @@ struct rotwing_eff_sched_param_t {
float Iyy_wing; // wing MMOI around the spanwise direction of the wing [kgm²]
float m; // mass [kg]
float DMdpprz_hover_roll[2]; // Moment coeficients for roll motors (Scaled by 10000)
+ float DMdpprz_hover_pitch[2]; // Moment coeficients for pitch motors (Scaled by 10000)
float hover_roll_pitch_coef[2]; // Model coefficients to correct pitch effective for roll motors
float hover_roll_roll_coef[2]; // Model coefficients to correct roll effectiveness for roll motors
float k_elevator[3];
@@ -50,6 +51,7 @@ struct rotwing_eff_sched_param_t {
float k_lift_fuselage;
float k_lift_tail;
};
+extern struct rotwing_eff_sched_param_t eff_sched_p;
struct rotwing_eff_sched_var_t {
float Ixx; // Total MMOI around roll axis [kgm²]
@@ -77,12 +79,13 @@ struct rotwing_eff_sched_var_t {
float airspeed2;
};
-extern float roll_eff_scaling;
+extern int32_t rw_flap_offset;
extern float rotation_angle_setpoint_deg;
extern int16_t rotation_cmd;
extern float eff_sched_pusher_time;
+extern float roll_eff_slider;
extern void eff_scheduling_rotwing_init(void);
extern void eff_scheduling_rotwing_periodic(void);
diff --git a/sw/airborne/modules/nav/nav_rotorcraft_hybrid.c b/sw/airborne/modules/nav/nav_rotorcraft_hybrid.c
index b4a7e03ee9..a31c5c14de 100644
--- a/sw/airborne/modules/nav/nav_rotorcraft_hybrid.c
+++ b/sw/airborne/modules/nav/nav_rotorcraft_hybrid.c
@@ -87,12 +87,18 @@ float nav_hybrid_line_gain = 1.0f;
#define NAV_HYBRID_NAV_CIRCLE_DIST 40.f
#endif
-#ifdef NAV_HYBRID_POS_GAIN
+#ifdef GUIDANCE_INDI_POS_GAIN
+float nav_hybrid_pos_gain = GUIDANCE_INDI_POS_GAIN;
+#elif defined(NAV_HYBRID_POS_GAIN)
float nav_hybrid_pos_gain = NAV_HYBRID_POS_GAIN;
#else
float nav_hybrid_pos_gain = 1.0f;
#endif
+#if defined(NAV_HYBRID_POS_GAIN) && defined(GUIDANCE_INDI_POS_GAIN)
+#warning "NAV_HYBRID_POS_GAIN and GUIDANCE_INDI_POS_GAIN serve similar purpose and are both defined, using GUIDANCE_INDI_POS_GAIN"
+#endif
+
#ifndef GUIDANCE_INDI_HYBRID
bool force_forward = 0.0f;
#endif
diff --git a/sw/airborne/modules/rotwing_drone/rotwing_state.c b/sw/airborne/modules/rotwing_drone/rotwing_state.c
index ed3032d796..500956c40a 100644
--- a/sw/airborne/modules/rotwing_drone/rotwing_state.c
+++ b/sw/airborne/modules/rotwing_drone/rotwing_state.c
@@ -26,134 +26,91 @@
#include "modules/rotwing_drone/rotwing_state.h"
#include "firmwares/rotorcraft/stabilization/stabilization_indi.h"
#include "firmwares/rotorcraft/guidance/guidance_indi_hybrid.h"
-#include "modules/nav/nav_rotorcraft_hybrid.h"
#include "firmwares/rotorcraft/autopilot_firmware.h"
#include "modules/actuators/actuators.h"
#include "modules/core/abi.h"
-// Quad state identification
-#ifndef ROTWING_MIN_SKEW_ANGLE_DEG_QUAD
-#define ROTWING_MIN_SKEW_ANGLE_DEG_QUAD 10.0
-#endif
-#ifndef ROTWING_MIN_SKEW_ANGLE_COUNTER
-#define ROTWING_MIN_SKEW_ANGLE_COUNTER 10 // Minimum number of loops the skew angle is below ROTWING_MIN_SKEW_ANGLE_COUNTER
+/* Minimum measured RPM to consider the hover motors running (RPM) */
+#ifndef ROTWING_QUAD_MIN_RPM
+#define ROTWING_QUAD_MIN_RPM 400
#endif
-// Skewing state identification
-#ifndef ROTWING_SKEWING_COUNTER
-#define ROTWING_SKEWING_COUNTER 10 // Minimum number of loops the skew angle is in between QUAD and FW
+/* Minimum measured RPM to consider the pusher motor running (RPM) */
+#ifndef ROTWING_PUSH_MIN_RPM
+#define ROTWING_PUSH_MIN_RPM 300
#endif
-// maximum quad airspeed to force quad state
-#ifndef ROTWING_MAX_QUAD_AIRSPEED
-#define ROTWING_MAX_QUAD_AIRSPEED 20.0
+/* Timeout for the RPM feedback (seconds) */
+#ifndef ROTWING_RPM_TIMEOUT
+#define ROTWING_RPM_TIMEOUT 1.0
#endif
-// Half skew state identification
-#ifndef ROTWING_HALF_SKEW_ANGLE_DEG
-#define ROTWING_HALF_SKEW_ANGLE_DEG 55.0
-#endif
-#ifndef ROTWING_HALF_SKEW_ANGLE_RANG
-#define ROTWING_HALF_SKEW_ANGLE_HALF_RANGE 10.0
-#endif
-#ifndef ROTWING_HALF_SKEW_COUNTER
-#define ROTWING_HALF_SKEW_COUNTER 10 // Minimum number of loops the skew angle is at HALF_SKEW_ANGLE_DEG +/- ROTWING_HALF_SKEW_ANGLE_HALF_RANGE to trigger ROTWING_HALF_SKEW_ANGLE state
+/* Minimum thrust to consider the hover motors idling (PPRZ) */
+#ifndef ROTWING_QUAD_IDLE_MIN_THRUST
+#define ROTWING_QUAD_IDLE_MIN_THRUST 100
#endif
-// FW state identification
-#ifndef ROTWING_MIN_FW_SKEW_ANGLE_DEG
-#define ROTWING_MIN_FW_SKEW_ANGLE_DEG 80.0 // Minimum wing angle to fly in fixed wing state
-#endif
-#ifndef ROTWING_MIN_FW_COUNTER
-#define ROTWING_MIN_FW_COUNTER 10 // Minimum number of loops the skew angle is above the MIN_FW_SKEW_ANGLE
+/* Minimum time for the hover motors to be considered idling (seconds) */
+#ifndef ROTWING_QUAD_IDLE_TIMEOUT
+#define ROTWING_QUAD_IDLE_TIMEOUT 0.4
#endif
-// FW idle state identification
-#ifndef ROTWING_MIN_THRUST_IDLE
-#define ROTWING_MIN_THRUST_IDLE 100
-#endif
-#ifndef ROTWING_MIN_THRUST_IDLE_COUNTER
-#define ROTWING_MIN_THRUST_IDLE_COUNTER 10
+/* Minimum measured skew angle to consider the rotating wing in fixedwing (deg) */
+#ifndef ROTWING_FW_SKEW_ANGLE
+#define ROTWING_FW_SKEW_ANGLE 85.0
#endif
-// FW hov mot off state identification
-#ifndef ROTWING_HOV_MOT_RUN_RPM_TH
-#define ROTWING_HOV_MOT_RUN_RPM_TH 800
-#endif
-#ifndef ROTWING_HOV_MOT_OFF_RPM_TH
-#define ROTWING_HOV_MOT_OFF_RPM_TH 50
-#endif
-#ifndef ROTWING_HOV_MOT_OFF_COUNTER
-#define ROTWING_HOV_MOT_OFF_COUNTER 10
+/* Magnitude skew angle jump away from quad */
+#ifndef ROTWING_SKEW_ANGLE_STEP
+#define ROTWING_SKEW_ANGLE_STEP 55.0
#endif
-#ifndef ROTWING_STATE_USE_ROTATION_REF_MODEL
-#define ROTWING_STATE_USE_ROTATION_REF_MODEL FALSE
+/* TODO: Give a name.... */
+#ifndef ROTWING_SKEW_BACK_MARGIN
+#define ROTWING_SKEW_BACK_MARGIN 5.0
#endif
-
-// Hover preferred pitch (deg)
-#ifndef ROTWING_STATE_HOVER_PREF_PITCH
-#define ROTWING_STATE_HOVER_PREF_PITCH 0.0
+/* Maximum angle difference between the measured skew and modelled skew for skew failure detection */
+#ifndef ROTWING_SKEW_REF_MODEL_MAX_DIFF
+#define ROTWING_SKEW_REF_MODEL_MAX_DIFF 5.f
#endif
-// Transition preffered pitch (deg)
-#ifndef ROTWING_STATE_TRANSITION_PREF_PITCH
-#define ROTWING_STATE_TRANSITION_PREF_PITCH 3.0
+/* Skew angle at which the mininum airspeed starts its linear portion */
+#ifndef ROTWING_MIN_AIRSPEED_SLOPE_START_ANGLE
+#define ROTWING_MIN_AIRSPEED_SLOPE_START_ANGLE 30.0
#endif
-// Forward preffered pitch (deg)
-#ifndef ROTWING_STATE_FW_PREF_PITCH
-#define ROTWING_STATE_FW_PREF_PITCH 8.0
+/* Preferred pitch angle for the quad mode (deg) */
+#ifndef ROTWING_QUAD_PREF_PITCH
+#define ROTWING_QUAD_PREF_PITCH -5.0
#endif
-// stream ADC data if ADC rotation sensor
-#ifndef ADC_WING_ROTATION
-#define ADC_WING_ROTATION FALSE
+/* Amount of time the airspeed needs to be below the FW_MIN_AIRSPEED */
+#ifndef ROTWING_FW_STALL_TIMEOUT
+#define ROTWING_FW_STALL_TIMEOUT 0.5
#endif
-#if ADC_WING_ROTATION
-#include "wing_rotation_adc_sensor.h"
+
+/* Fix for not having double can busses */
+#ifndef SERVO_BMOTOR_PUSH_IDX
+#define SERVO_BMOTOR_PUSH_IDX SERVO_MOTOR_PUSH_IDX
#endif
-/** ABI binding feedback data.
- */
+
+/* Fix for not having double can busses */
+#ifndef SERVO_BROTATION_MECH_IDX
+#define SERVO_BROTATION_MECH_IDX SERVO_ROTATION_MECH_IDX
+#endif
+
+/** ABI binding feedback data */
#ifndef ROTWING_STATE_ACT_FEEDBACK_ID
#define ROTWING_STATE_ACT_FEEDBACK_ID ABI_BROADCAST
#endif
abi_event rotwing_state_feedback_ev;
static void rotwing_state_feedback_cb(uint8_t sender_id, struct act_feedback_t *feedback_msg, uint8_t num_act);
-#define ROTWING_STATE_NUM_HOVER_RPM 4
-int32_t rotwing_state_hover_rpm[ROTWING_STATE_NUM_HOVER_RPM] = {0, 0, 0, 0};
-struct RotwingState rotwing_state;
-struct RotWingStateSettings rotwing_state_settings;
-struct RotWingStateSkewing rotwing_state_skewing;
-
-uint8_t rotwing_state_hover_counter = 0;
-uint8_t rotwing_state_skewing_counter = 0;
-uint8_t rotwing_state_fw_counter = 0;
-uint8_t rotwing_state_fw_idle_counter = 0;
-uint8_t rotwing_state_fw_m_off_counter = 0;
-
-float rotwing_state_max_hover_speed = 7;
-
-bool hover_motors_active = true;
-bool bool_disable_hover_motors = false;
-
-float Wu_gih_original[GUIDANCE_INDI_HYBRID_U] = GUIDANCE_INDI_WLS_WU;
-
-inline void rotwing_check_set_current_state(void);
-inline void rotwing_switch_state(void);
-
-inline void rotwing_state_set_hover_settings(void);
-inline void rotwing_state_set_skewing_settings(void);
-inline void rotwing_state_set_fw_settings(void);
-inline void rotwing_state_set_fw_hov_mot_idle_settings(void);
-inline void rotwing_state_set_fw_hov_mot_off_settings(void);
-
-inline void rotwing_state_set_state_settings(void);
-inline void rotwing_state_skewer(void);
-inline void rotwing_state_free_processor(void);
+static bool rotwing_state_hover_motors_idling(void);
+static const float Wu_gih_original[GUIDANCE_INDI_HYBRID_U] = GUIDANCE_INDI_WLS_WU;
+struct rotwing_state_t rotwing_state;
inline void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_angle, float pitch_angle);
@@ -161,605 +118,355 @@ inline void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_an
#include "modules/datalink/telemetry.h"
static void send_rotating_wing_state(struct transport_tx *trans, struct link_device *dev)
{
- uint16_t adc_dummy = 0;
+ // Set the status
+ union rotwing_bitmask_t status;
+ status.value = 0;
+ status.skew_angle_valid = rotwing_state_skew_angle_valid();
+ status.hover_motors_enabled = rotwing_state.hover_motors_enabled;
+ status.hover_motors_idle = rotwing_state_hover_motors_idling();
+ status.hover_motors_running = rotwing_state_hover_motors_running();
+ status.pusher_motor_running = rotwing_state_pusher_motor_running();
+ status.skew_forced = rotwing_state.force_skew;
+
+ // Send the message
+ uint8_t state = rotwing_state.state;
+ uint8_t nav_state = rotwing_state.nav_state;
pprz_msg_send_ROTATING_WING_STATE(trans, dev, AC_ID,
- &rotwing_state.current_state,
- &rotwing_state.desired_state,
- &rotwing_state_skewing.wing_angle_deg,
- &rotwing_state_skewing.wing_angle_deg_sp,
- &adc_dummy,
- &rotwing_state_skewing.servo_pprz_cmd);
+ &state,
+ &nav_state,
+ &status.value,
+ &rotwing_state.meas_skew_angle_deg,
+ &rotwing_state.sp_skew_angle_deg,
+ &gi_unbounded_airspeed_sp,
+ &rotwing_state.min_airspeed,
+ &rotwing_state.max_airspeed);
}
#endif // PERIODIC_TELEMETRY
-void init_rotwing_state(void)
+void rotwing_state_init(void)
{
+ // Initialize rotwing state
+ rotwing_state.state = ROTWING_STATE_FORCE_HOVER; // For takeoff
+ rotwing_state.nav_state = ROTWING_STATE_FORCE_HOVER;
+ rotwing_state.hover_motors_enabled = true;
+ rotwing_state.fw_min_airspeed = ROTWING_FW_MIN_AIRSPEED;
+ rotwing_state.cruise_airspeed = ROTWING_FW_CRUISE_AIRSPEED;
+ rotwing_state.sp_skew_angle_deg = 0;
+ rotwing_state.meas_skew_angle_deg = 0;
+ rotwing_state.meas_skew_angle_time = 0;
+ rotwing_state.skew_cmd = 0;
+ rotwing_state.force_skew = false;
+ for (int i = 0; i < 5; i++) {
+ rotwing_state.meas_rpm[i] = 0;
+ rotwing_state.meas_rpm_time[i] = 0;
+ }
+ rotwing_state.fail_skew_angle = false;
+ rotwing_state.fail_hover_motor = false;
+ rotwing_state.fail_pusher_motor = false;
+ rotwing_state.ref_model_skew_angle_deg = 0;
+
// Bind ABI messages
AbiBindMsgACT_FEEDBACK(ROTWING_STATE_ACT_FEEDBACK_ID, &rotwing_state_feedback_ev, rotwing_state_feedback_cb);
- // Start the drone in a desired hover state
- rotwing_state.current_state = ROTWING_STATE_HOVER;
- rotwing_state.desired_state = ROTWING_STATE_HOVER;
- rotwing_state.requested_config = ROTWING_CONFIGURATION_HOVER;
-
- rotwing_state_skewing.wing_angle_deg_sp = 0;
- rotwing_state_skewing.wing_angle_deg = 0;
- rotwing_state_skewing.servo_pprz_cmd = -MAX_PPRZ;
- rotwing_state_skewing.airspeed_scheduling = false;
- rotwing_state_skewing.force_rotation_angle = false;
-
#if PERIODIC_TELEMETRY
register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_ROTATING_WING_STATE, send_rotating_wing_state);
#endif
}
-void periodic_rotwing_state(void)
-{
- // Check and set the current state
- rotwing_check_set_current_state();
+/**
+ * @brief Check if hover motors are idling (COMMAND_THRUST < ROTWING_QUAD_IDLE_MIN_THRUST) for ROTWING_QUAD_IDLE_TIMEOUT time
+ * @return true if hover motors are idling, false otherwise
+ */
+static bool rotwing_state_hover_motors_idling(void) {
+ static float last_idle_time = 0;
+ // Check if hover motors are idling and reset timer
+ if(stabilization.cmd[COMMAND_THRUST] > ROTWING_QUAD_IDLE_MIN_THRUST) {
+ last_idle_time = get_sys_time_float();
+ }
- // Check and update desired state
- if (guidance_h.mode == GUIDANCE_H_MODE_NAV) {
- // Run the free state requester if free configuration requestes
- if(rotwing_state.requested_config == ROTWING_CONFIGURATION_FREE) {
- rotwing_state_free_processor();
+ // Check if we exceeded the idle timeout
+ if(get_sys_time_float() - last_idle_time > ROTWING_QUAD_IDLE_TIMEOUT) {
+ return true;
+ }
+ return false;
+}
+
+void rotwing_state_periodic(void)
+{
+ /* Get some genericly used variables */
+ static float last_stall_time = 0;
+ float current_time = get_sys_time_float();
+ float meas_airspeed = stateGetAirspeed_f();
+ float meas_skew_angle = rotwing_state.meas_skew_angle_deg;
+ Bound(meas_skew_angle, 0, 90); // Bound to prevent errors
+
+ if(meas_airspeed > rotwing_state.fw_min_airspeed) {
+ last_stall_time = current_time;
+ }
+
+ /* Override modes if flying with RC */
+ rotwing_state.state = rotwing_state.nav_state;
+ if(guidance_h.mode == GUIDANCE_H_MODE_NONE) {
+ // Kill mode
+ if(stabilization.mode == STABILIZATION_MODE_NONE) {
+ rotwing_state.state = ROTWING_STATE_FORCE_HOVER;
}
- rotwing_switch_state();
- } else if (guidance_h.mode == GUIDANCE_H_MODE_NONE) {
- if (stabilization.mode == STABILIZATION_MODE_ATTITUDE) {
+ // ATT and ATT_FWD
+ else if(stabilization.mode == STABILIZATION_MODE_ATTITUDE) {
if (stabilization.att_submode == STABILIZATION_ATT_SUBMODE_FORWARD) {
- rotwing_state_set_fw_settings();
+ rotwing_state.state = ROTWING_STATE_FORCE_FW;
} else {
- rotwing_state_set_hover_settings();
+ rotwing_state.state = ROTWING_STATE_FORCE_HOVER;
}
}
}
- // Run the wing skewer
- rotwing_state_skewer();
-
- //TODO: incorparate motor active / disbaling depending on called flight state
- // Switch on motors if flight mode is attitude
- if (guidance_h.mode == GUIDANCE_H_MODE_NONE) {
- bool_disable_hover_motors = false;
+ /* Handle the quad motors on/off state */
+ if(rotwing_state.state == ROTWING_STATE_FORCE_HOVER || rotwing_state.state == ROTWING_STATE_REQUEST_HOVER) {
+ rotwing_state.hover_motors_enabled = true;
+ }
+ else if((current_time - last_stall_time) < ROTWING_FW_STALL_TIMEOUT && rotwing_state_hover_motors_idling() && rotwing_state_pusher_motor_running() && meas_skew_angle >= ROTWING_FW_SKEW_ANGLE
+ && (gi_unbounded_airspeed_sp >= rotwing_state.fw_min_airspeed || rotwing_state.state != ROTWING_STATE_FREE)) {
+ rotwing_state.hover_motors_enabled = false;
+ }
+ else {
+ rotwing_state.hover_motors_enabled = true;
}
-}
+ /* Calculate min/max airspeed bounds based on skew angle */
+ float skew_min_airspeed = ROTWING_FW_QUAD_MIN_AIRSPEED * (meas_skew_angle - ROTWING_MIN_AIRSPEED_SLOPE_START_ANGLE) / (90.f - ROTWING_MIN_AIRSPEED_SLOPE_START_ANGLE);
+ float skew_max_airspeed = ROTWING_QUAD_MAX_AIRSPEED + (ROTWING_FW_MAX_AIRSPEED - ROTWING_QUAD_MAX_AIRSPEED) * meas_skew_angle / ROTWING_FW_SKEW_ANGLE;
+ Bound(skew_min_airspeed, 0, rotwing_state.fw_min_airspeed);
+ Bound(skew_max_airspeed, ROTWING_QUAD_MAX_AIRSPEED, ROTWING_FW_MAX_AIRSPEED);
-// Function to request a state
-void request_rotwing_state(uint8_t state)
-{
- if (state <= ROTWING_STATE_FW_HOV_MOT_OFF) {
- rotwing_state.desired_state = state;
- }
-}
-
-// Function to prefer configuration
-void rotwing_request_configuration(uint8_t configuration)
-{
- switch (configuration) {
- case ROTWING_CONFIGURATION_HOVER:
- request_rotwing_state(ROTWING_STATE_HOVER);
- rotwing_state.requested_config = ROTWING_CONFIGURATION_HOVER;
- break;
- case ROTWING_CONFIGURATION_HYBRID:
- request_rotwing_state(ROTWING_STATE_SKEWING);
- rotwing_state.requested_config = ROTWING_CONFIGURATION_HYBRID;
- break;
- case ROTWING_CONFIGURATION_EFFICIENT:
- request_rotwing_state(ROTWING_STATE_FW_HOV_MOT_OFF);
- rotwing_state.requested_config = ROTWING_CONFIGURATION_EFFICIENT;
- break;
- case ROTWING_CONFIGURATION_FREE:
- rotwing_state.requested_config = ROTWING_CONFIGURATION_FREE;
- break;
- }
-}
-
-void rotwing_check_set_current_state(void)
-{
- // if !in_flight, set state to hover
- if (!autopilot.in_flight) {
- rotwing_state_hover_counter = 0;
- rotwing_state_skewing_counter = 0;
- rotwing_state_fw_counter = 0;
- rotwing_state_fw_idle_counter = 0;
- rotwing_state_fw_m_off_counter = 0;
- rotwing_state.current_state = ROTWING_STATE_HOVER;
- return;
+ if(!rotwing_state_hover_motors_running() || !rotwing_state.hover_motors_enabled) {
+ skew_min_airspeed = rotwing_state.fw_min_airspeed;
+ skew_max_airspeed = ROTWING_FW_MAX_AIRSPEED;
}
- // States can be checked according to wing angle sensor, setpoints .....
- uint8_t prev_state = rotwing_state.current_state;
- switch (prev_state) {
- case ROTWING_STATE_HOVER:
- // Check if state needs to be set to skewing
- if (rotwing_state_skewing.wing_angle_deg > ROTWING_MIN_SKEW_ANGLE_DEG_QUAD) {
- rotwing_state_skewing_counter++;
- } else {
- rotwing_state_skewing_counter = 0;
- }
- // Switch state if necessary
- if (rotwing_state_skewing_counter > ROTWING_MIN_SKEW_ANGLE_COUNTER) {
- rotwing_state.current_state = ROTWING_STATE_SKEWING;
- rotwing_state_skewing_counter = 0;
- }
- break;
-
- case ROTWING_STATE_SKEWING:
- // Check if state needs to be set to hover
- if (rotwing_state_skewing.wing_angle_deg < ROTWING_MIN_SKEW_ANGLE_DEG_QUAD) {
- rotwing_state_hover_counter++;
- } else {
- rotwing_state_hover_counter = 0;
- }
-
- // Check if state needs to be set to fixed wing
- if (rotwing_state_skewing.wing_angle_deg > ROTWING_MIN_FW_SKEW_ANGLE_DEG) {
- rotwing_state_fw_counter++;
- } else {
- rotwing_state_fw_counter = 0;
- }
-
- // Switch state if necessary
- if (rotwing_state_hover_counter > ROTWING_MIN_SKEW_ANGLE_COUNTER) {
- rotwing_state.current_state = ROTWING_STATE_HOVER;
- rotwing_state_hover_counter = 0;
- }
-
- if (rotwing_state_fw_counter > ROTWING_MIN_FW_COUNTER) {
- rotwing_state.current_state = ROTWING_STATE_FW;
- rotwing_state_fw_counter = 0;
- }
- break;
-
- case ROTWING_STATE_FW:
- // Check if state needs to be set to skewing
- if (rotwing_state_skewing.wing_angle_deg < ROTWING_MIN_FW_SKEW_ANGLE_DEG) {
- rotwing_state_skewing_counter++;
- } else {
- rotwing_state_skewing_counter = 0;
- }
-
- // Check if state needs to be set to fixed wing with hover motors idle (If hover thrust below threshold)
- if (stabilization.cmd[COMMAND_THRUST] < ROTWING_MIN_THRUST_IDLE && rotwing_state.desired_state > ROTWING_STATE_FW) {
- rotwing_state_fw_idle_counter++;
- } else {
- rotwing_state_fw_idle_counter = 0;
- }
-
- // Switch state if necessary
- if (rotwing_state_skewing_counter > ROTWING_MIN_FW_COUNTER) {
- rotwing_state.current_state = ROTWING_STATE_SKEWING;
- rotwing_state_skewing_counter = 0;
- rotwing_state_fw_idle_counter = 0;
- } else if (rotwing_state_fw_idle_counter > ROTWING_MIN_THRUST_IDLE_COUNTER
- && rotwing_state_skewing_counter == 0) {
- rotwing_state.current_state = ROTWING_STATE_FW_HOV_MOT_IDLE;
- rotwing_state_skewing_counter = 0;
- rotwing_state_fw_idle_counter = 0;
- }
- break;
-
- case ROTWING_STATE_FW_HOV_MOT_IDLE:
- // Check if state needs to be set to fixed wing with hover motors activated
- if (stabilization.cmd[COMMAND_THRUST] > ROTWING_MIN_THRUST_IDLE
- || rotwing_state.desired_state < ROTWING_STATE_FW_HOV_MOT_IDLE) {
- rotwing_state_fw_counter++;
- } else {
- rotwing_state_fw_counter = 0;
- }
-
- // Check if state needs to be set to fixed wing with hover motors off (if zero rpm on hover motors)
- if (rotwing_state_hover_rpm[0] == 0
- && rotwing_state_hover_rpm[1] == 0
- && rotwing_state_hover_rpm[2] == 0
- && rotwing_state_hover_rpm[3] == 0) {
-#if !USE_NPS
- rotwing_state_fw_m_off_counter++;
-#endif
- } else {
- rotwing_state_fw_m_off_counter = 0;
- }
-
- // Switch state if necessary
- if (rotwing_state_fw_counter > ROTWING_MIN_THRUST_IDLE_COUNTER) {
- rotwing_state.current_state = ROTWING_STATE_FW;
- rotwing_state_fw_counter = 0;
- rotwing_state_fw_m_off_counter = 0;
- } else if (rotwing_state_fw_m_off_counter > ROTWING_HOV_MOT_OFF_COUNTER
- && rotwing_state_fw_counter == 0) {
- rotwing_state.current_state = ROTWING_STATE_FW_HOV_MOT_OFF;
- rotwing_state_fw_counter = 0;
- rotwing_state_fw_m_off_counter = 0;
- }
- break;
-
- case ROTWING_STATE_FW_HOV_MOT_OFF:
- // Check if state needs to be set to fixed wing with hover motors idle (if rpm on hover motors)
- if (rotwing_state_hover_rpm[0] > ROTWING_HOV_MOT_OFF_RPM_TH
- && rotwing_state_hover_rpm[1] > ROTWING_HOV_MOT_OFF_RPM_TH
- && rotwing_state_hover_rpm[2] > ROTWING_HOV_MOT_OFF_RPM_TH
- && rotwing_state_hover_rpm[3] > ROTWING_HOV_MOT_OFF_RPM_TH) {
- rotwing_state_fw_idle_counter++;
- } else {
- rotwing_state_fw_idle_counter = 0;
- }
-
- // Switch state if necessary
- if (rotwing_state_fw_idle_counter > ROTWING_MIN_THRUST_IDLE_COUNTER) {
- rotwing_state.current_state = ROTWING_STATE_FW_HOV_MOT_IDLE;
- rotwing_state_fw_idle_counter = 0;
- }
- break;
-
- default:
- break;
+ /* Handle the skew angle setpoint */
+ if (rotwing_state.force_skew) {
+ // Do nothing
}
-}
-
-// Function that handles settings for switching state(s)
-void rotwing_switch_state(void)
-{
- switch (rotwing_state.current_state) {
- case ROTWING_STATE_HOVER:
- if (rotwing_state.desired_state > ROTWING_STATE_HOVER) {
- rotwing_state_set_skewing_settings();
- } else {
- rotwing_state_set_hover_settings();
- }
- break;
-
- case ROTWING_STATE_SKEWING:
- if (rotwing_state.desired_state < ROTWING_STATE_SKEWING && stateGetAirspeed_f() < ROTWING_MAX_QUAD_AIRSPEED) {
- rotwing_state_set_hover_settings();
- } else {
- rotwing_state_set_skewing_settings();
- }
- break;
-
- case ROTWING_STATE_FW:
- if (rotwing_state.desired_state > ROTWING_STATE_FW) {
- rotwing_state_set_fw_hov_mot_idle_settings();
- } else if (rotwing_state.desired_state < ROTWING_STATE_FW) {
- rotwing_state_set_skewing_settings();
- } else {
- rotwing_state_set_fw_settings();
- }
- break;
-
- case ROTWING_STATE_FW_HOV_MOT_IDLE:
- if (rotwing_state.desired_state > ROTWING_STATE_FW_HOV_MOT_IDLE) {
- rotwing_state_set_fw_hov_mot_off_settings();
- } else if (rotwing_state.desired_state < ROTWING_STATE_FW_HOV_MOT_IDLE) {
- rotwing_state_set_fw_settings();
- } else {
- rotwing_state_set_fw_hov_mot_idle_settings();
- }
- break;
-
- case ROTWING_STATE_FW_HOV_MOT_OFF:
- if (rotwing_state.desired_state < ROTWING_STATE_FW_HOV_MOT_OFF) {
- rotwing_state_set_fw_hov_mot_idle_settings();
- } else {
- rotwing_state_set_fw_hov_mot_off_settings();
- }
- break;
+ else if(rotwing_state.state == ROTWING_STATE_FORCE_HOVER) {
+ rotwing_state.sp_skew_angle_deg = 0.f;
}
-}
-
-void rotwing_state_set_hover_settings(void)
-{
- rotwing_state_settings.wing_scheduler = ROTWING_STATE_WING_QUAD_SETTING;
- rotwing_state_settings.hover_motors_active = true;
- rotwing_state_settings.hover_motors_disable = false;
- rotwing_state_settings.force_forward = false;
- rotwing_state_settings.preferred_pitch = ROTWING_STATE_PITCH_QUAD_SETTING;
- rotwing_state_settings.stall_protection = false;
- rotwing_state_settings.max_v_climb = 2.0;
- rotwing_state_settings.max_v_descend = 1.0;
- rotwing_state_settings.nav_max_speed = rotwing_state_max_hover_speed; // Using setting
- rotwing_state_set_state_settings();
-}
-
-void rotwing_state_set_skewing_settings(void)
-{
- // Wing may be skewed to quad when desired state is hover and skewing settings set by state machine
- if (rotwing_state.desired_state == ROTWING_STATE_HOVER) {
- rotwing_state_settings.wing_scheduler = ROTWING_STATE_WING_QUAD_SETTING;
- } else {
- rotwing_state_settings.wing_scheduler = ROTWING_STATE_WING_SCHEDULING_SETTING;
+ else if(!rotwing_state_hover_motors_running() || !rotwing_state.hover_motors_enabled || rotwing_state.state == ROTWING_STATE_FORCE_FW) {
+ rotwing_state.sp_skew_angle_deg = 90.f;
}
- rotwing_state_settings.hover_motors_active = true;
- rotwing_state_settings.hover_motors_disable = false;
- rotwing_state_settings.force_forward = false;
- rotwing_state_settings.preferred_pitch = ROTWING_STATE_PITCH_TRANSITION_SETTING;
- rotwing_state_settings.stall_protection = false;
- rotwing_state_settings.max_v_climb = 2.0;
- rotwing_state_settings.max_v_descend = 1.0;
- rotwing_state_settings.nav_max_speed = 100; // Big as we use airspeed guidance
- rotwing_state_set_state_settings();
-}
-
-void rotwing_state_set_fw_settings(void)
-{
- rotwing_state_settings.wing_scheduler = ROTWING_STATE_WING_FW_SETTING;
- rotwing_state_settings.hover_motors_active = true;
- rotwing_state_settings.hover_motors_disable = false;
- rotwing_state_settings.force_forward = true;
- rotwing_state_settings.preferred_pitch = ROTWING_STATE_PITCH_FW_SETTING;
- rotwing_state_settings.stall_protection = false;
- rotwing_state_settings.max_v_climb = 4.0;
- rotwing_state_settings.max_v_descend = 4.0;
- rotwing_state_settings.nav_max_speed = 100; // Big as we use airspeed guidance
- rotwing_state_set_state_settings();
-}
-
-void rotwing_state_set_fw_hov_mot_idle_settings(void)
-{
- rotwing_state_settings.wing_scheduler = ROTWING_STATE_WING_FW_SETTING;
- rotwing_state_settings.hover_motors_active = false;
- rotwing_state_settings.hover_motors_disable = false;
- rotwing_state_settings.force_forward = true;
- rotwing_state_settings.preferred_pitch = ROTWING_STATE_PITCH_FW_SETTING;
- rotwing_state_settings.stall_protection = true;
- rotwing_state_settings.max_v_climb = 4.0;
- rotwing_state_settings.max_v_descend = 4.0;
- rotwing_state_settings.nav_max_speed = 100; // Big as we use airspeed guidance
- rotwing_state_set_state_settings();
-}
-
-void rotwing_state_set_fw_hov_mot_off_settings(void)
-{
- rotwing_state_settings.wing_scheduler = ROTWING_STATE_WING_FW_SETTING;
- rotwing_state_settings.hover_motors_active = false;
- rotwing_state_settings.hover_motors_disable = true;
- rotwing_state_settings.force_forward = true;
- rotwing_state_settings.preferred_pitch = ROTWING_STATE_PITCH_FW_SETTING;
- rotwing_state_settings.stall_protection = true;
- rotwing_state_settings.max_v_climb = 4.0;
- rotwing_state_settings.max_v_descend = 4.0;
- rotwing_state_settings.nav_max_speed = 100; // Big as we use airspeed guidance
- rotwing_state_set_state_settings();
-}
-
-void rotwing_state_set_state_settings(void)
-{
-
- if (!rotwing_state_skewing.force_rotation_angle) {
- switch (rotwing_state_settings.wing_scheduler) {
- case ROTWING_STATE_WING_QUAD_SETTING:
- rotwing_state_skewing.airspeed_scheduling = false;
- rotwing_state_skewing.wing_angle_deg_sp = 0;
- break;
- case ROTWING_STATE_WING_SCHEDULING_SETTING:
- rotwing_state_skewing.airspeed_scheduling = true;
- break;
- case ROTWING_STATE_WING_FW_SETTING:
- rotwing_state_skewing.airspeed_scheduling = true;
- break;
- }
- } else {
- rotwing_state_skewing.airspeed_scheduling = false;
+ else if(!rotwing_state_pusher_motor_running()) {
+ rotwing_state.sp_skew_angle_deg = 0.f;
}
-
- hover_motors_active = rotwing_state_settings.hover_motors_active;
-
- bool_disable_hover_motors = rotwing_state_settings.hover_motors_disable;
-
- force_forward = rotwing_state_settings.force_forward;
-
- nav_max_speed = rotwing_state_settings.nav_max_speed;
-
- // TO DO: pitch angle now hard coded scheduled by wing angle
-
- // Stall protection handled by hover_motors_active boolean
-
- // TO DO: Climb and descend speeds now handled by guidance airspeed
-}
-
-void rotwing_state_skewer(void)
-{
- if (rotwing_state_skewing.airspeed_scheduling) {
- float wing_angle_scheduled_sp_deg = 0;
- float airspeed = stateGetAirspeed_f();
- if (airspeed < 8) {
- wing_angle_scheduled_sp_deg = 0;
- } else if (airspeed < 10 && (rotwing_state.desired_state > ROTWING_STATE_HOVER)) {
- wing_angle_scheduled_sp_deg = 55;
- } else if (airspeed > 10) {
- wing_angle_scheduled_sp_deg = ((airspeed - 10.)) / 4. * 35. + 55.;
+ else if(rotwing_state.state == ROTWING_STATE_REQUEST_HOVER && meas_skew_angle <= (ROTWING_SKEW_ANGLE_STEP + ROTWING_SKEW_BACK_MARGIN)) {
+ rotwing_state.sp_skew_angle_deg = 0.f;
+ }
+ else {
+ // SKEWING function based on Vair
+ if (meas_airspeed < ROTWING_SKEW_DOWN_AIRSPEED) {
+ rotwing_state.sp_skew_angle_deg = 0.f;
+ } else if (meas_airspeed < ROTWING_SKEW_UP_AIRSPEED) {
+ // Hysteresis do nothing
+ } else if (meas_airspeed < ROTWING_QUAD_MAX_AIRSPEED) {
+ rotwing_state.sp_skew_angle_deg = ROTWING_SKEW_ANGLE_STEP;
} else {
- wing_angle_scheduled_sp_deg = 0;
+ rotwing_state.sp_skew_angle_deg = ((meas_airspeed - ROTWING_QUAD_MAX_AIRSPEED)) / (rotwing_state.fw_min_airspeed - ROTWING_QUAD_MAX_AIRSPEED) * (90.f - ROTWING_SKEW_ANGLE_STEP) + ROTWING_SKEW_ANGLE_STEP;
}
-
- Bound(wing_angle_scheduled_sp_deg, 0., 90.)
- rotwing_state_skewing.wing_angle_deg_sp = wing_angle_scheduled_sp_deg;
}
-}
+ Bound(rotwing_state.sp_skew_angle_deg, 0.f, 90.f);
-void rotwing_state_free_processor(void)
-{
- // Get current speed vector
- struct EnuCoor_f *groundspeed = stateGetSpeedEnu_f();
- float current_groundspeed = FLOAT_VECT2_NORM(*groundspeed);
- // Get current airspeed
- float airspeed = stateGetAirspeed_f();
+ /* Handle the airspeed bounding */
+ Bound(rotwing_state.cruise_airspeed, rotwing_state.fw_min_airspeed, ROTWING_FW_MAX_AIRSPEED);
+ if((!rotwing_state_hover_motors_running() && rotwing_state.state != ROTWING_STATE_FORCE_HOVER) || rotwing_state.state == ROTWING_STATE_FORCE_FW) {
+ rotwing_state.min_airspeed = rotwing_state.cruise_airspeed;
+ rotwing_state.max_airspeed = rotwing_state.cruise_airspeed;
+ }
+ else if(!rotwing_state_pusher_motor_running()) {
+ rotwing_state.min_airspeed = 0;
+ rotwing_state.max_airspeed = ROTWING_QUAD_NOPUSH_AIRSPEED;
+ }
+ else if(rotwing_state.state == ROTWING_STATE_FORCE_HOVER || rotwing_state.state == ROTWING_STATE_REQUEST_HOVER) {
+ rotwing_state.min_airspeed = skew_min_airspeed;
+ rotwing_state.max_airspeed = fmax(ROTWING_QUAD_MAX_AIRSPEED, skew_min_airspeed);
+ }
+ else if(rotwing_state.state == ROTWING_STATE_REQUEST_FW) {
+ rotwing_state.min_airspeed = fmin(rotwing_state.cruise_airspeed, skew_max_airspeed);
+ rotwing_state.max_airspeed = fmin(rotwing_state.cruise_airspeed, skew_max_airspeed);
+ }
+ else{
+ rotwing_state.min_airspeed = skew_min_airspeed;
+ rotwing_state.max_airspeed = skew_max_airspeed;
+ }
- // Get windspeed vector
- struct FloatEulers eulers_zxy;
- float_eulers_of_quat_zxy(&eulers_zxy, stateGetNedToBodyQuat_f());
+ // Override failing skewing while fwd
+ /*if(meas_skew_angle > 70 && rotwing_state_.skewing_failing) {
+ rotwing_state.min_airspeed = 0; // Vstall + margin
+ rotwing_state.max_airspeed = 0; // Max airspeed FW
+ }*/
- float psi = eulers_zxy.psi;
- float cpsi = cosf(psi);
- float spsi = sinf(psi);
- struct FloatVect2 airspeed_v = { spsi * airspeed, cpsi * airspeed };
- struct FloatVect2 windspeed_v;
- VECT2_DIFF(windspeed_v, *groundspeed, airspeed_v);
+ guidance_indi_set_min_max_airspeed(rotwing_state.min_airspeed, rotwing_state.max_airspeed);
- // Get goto target information
- struct FloatVect2 pos_error;
- struct EnuCoor_f *pos = stateGetPositionEnu_f();
- VECT2_DIFF(pos_error, nav_rotorcraft_base.goto_wp.to, *pos);
- /*
- Calculations
- */
- // speed over pos_error projection
- struct FloatVect2 pos_error_norm;
- VECT2_COPY(pos_error_norm, pos_error);
- float_vect2_normalize(&pos_error_norm);
- float dist_to_target = sqrtf(nav_rotorcraft_base.goto_wp.dist2_to_wp);
- float max_speed_decel2 = fabsf(2.f * dist_to_target * nav_max_deceleration_sp); // dist_to_wp can only be positive, but just in case
- float max_speed_decel = sqrtf(max_speed_decel2);
+ /* Set navigation/guidance settings */
+ nav_max_deceleration_sp = ROTWING_FW_MAX_DECELERATION * meas_skew_angle / 90.f + ROTWING_QUAD_MAX_DECELERATION * (90.f - meas_skew_angle) / 90.f; //TODO: Do we really want to based this on the skew?
- // Check if speed setpoint above set airspeed
- struct FloatVect2 desired_airspeed_v;
- struct FloatVect2 groundspeed_sp;
- groundspeed_sp.x = pos_error.x * nav_hybrid_pos_gain;
- groundspeed_sp.y = pos_error.y * nav_hybrid_pos_gain;
- VECT2_COPY(desired_airspeed_v, groundspeed_sp);
- VECT2_ADD(desired_airspeed_v, windspeed_v);
- float desired_airspeed = FLOAT_VECT2_NORM(desired_airspeed_v);
- float airspeed_error = guidance_indi_max_airspeed - airspeed;
+ /* Calculate the skew command */
+ float servo_pprz_cmd = MAX_PPRZ * (rotwing_state.sp_skew_angle_deg - 45.f) / 45.f;
+ BoundAbs(servo_pprz_cmd, MAX_PPRZ);
- // Request hybrid if we have to decelerate and approaching target
- if (max_speed_decel < current_groundspeed) {
- request_rotwing_state(ROTWING_STATE_SKEWING);
- } else if ((desired_airspeed > 15) && ((current_groundspeed + airspeed_error) < max_speed_decel)) {
- request_rotwing_state(ROTWING_STATE_FW_HOV_MOT_OFF);
- }
-}
-
-void rotwing_state_skew_actuator_periodic(void)
-{
-
- // calc rotation percentage of setpoint (0 deg = -1, 45 deg = 0, 90 deg = 1)
- float wing_rotation_percentage = (rotwing_state_skewing.wing_angle_deg_sp - 45.) / 45.;
- Bound(wing_rotation_percentage, -1., 1.);
-
- float servo_pprz_cmd = MAX_PPRZ * wing_rotation_percentage;
- // Calulcate rotation_cmd
- Bound(servo_pprz_cmd, -MAX_PPRZ, MAX_PPRZ);
-
-#if ROTWING_STATE_USE_ROTATION_REF_MODEL
// Rotate with second order filter
static float rotwing_state_skew_p_cmd = -MAX_PPRZ;
static float rotwing_state_skew_d_cmd = 0;
- float speed_sp = 0.001 * (servo_pprz_cmd - rotwing_state_skew_p_cmd);
- rotwing_state_skew_d_cmd += 0.003 * (speed_sp - rotwing_state_skew_d_cmd);
+
+ float speed_sp = ROTWING_SKEW_REF_MODEL_P_GAIN * (servo_pprz_cmd - rotwing_state_skew_p_cmd);
+ BoundAbs(speed_sp, ROTWING_SKEW_REF_MODEL_MAX_SPEED);
+ rotwing_state_skew_d_cmd += ROTWING_SKEW_REF_MODEL_D_GAIN * (speed_sp - rotwing_state_skew_d_cmd);
rotwing_state_skew_p_cmd += rotwing_state_skew_d_cmd;
- Bound(rotwing_state_skew_p_cmd, -MAX_PPRZ, MAX_PPRZ);
- rotwing_state_skewing.servo_pprz_cmd = rotwing_state_skew_p_cmd;
+ BoundAbs(rotwing_state_skew_p_cmd, MAX_PPRZ);
+ rotwing_state.ref_model_skew_angle_deg = 45.0 / MAX_PPRZ * rotwing_state_skew_p_cmd + 45.0;
+
+#if (ROTWING_SKEW_REF_MODEL || USE_NPS)
+ rotwing_state.skew_cmd = rotwing_state_skew_p_cmd;
#else
- // Directly controlling the wing rotation
- rotwing_state_skewing.servo_pprz_cmd = servo_pprz_cmd;
+ rotwing_state.skew_cmd = servo_pprz_cmd;
#endif
+
+ /* Add simulation feedback for the skewing and RPM */
#if USE_NPS
// Export to the index of the SKEW in the NPS_ACTUATOR_NAMES array
- actuators_pprz[INDI_NUM_ACT] = (rotwing_state_skewing.servo_pprz_cmd + MAX_PPRZ) / 2.; // Scale to simulation command
+ actuators_pprz[INDI_NUM_ACT] = (rotwing_state.skew_cmd + MAX_PPRZ) / 2.f; // Scale to simulation command
- // Simulate wing angle from command
- rotwing_state_skewing.wing_angle_deg = (float) rotwing_state_skewing.servo_pprz_cmd / MAX_PPRZ * 45. + 45.;
-
- // SEND ABI Message to ctr_eff_sched and other modules that want Actuator position feedback
+ // SEND ABI Message to ctr_eff_sched, ourself and other modules that want Actuator position feedback
struct act_feedback_t feedback;
feedback.idx = SERVO_ROTATION_MECH_IDX;
- feedback.position = 0.5 * M_PI - RadOfDeg(rotwing_state_skewing.wing_angle_deg);
+ feedback.position = 0.5f * M_PI - RadOfDeg((float) rotwing_state.skew_cmd / MAX_PPRZ * 45.f + 45.f);
feedback.set.position = true;
- // Send ABI message
- AbiSendMsgACT_FEEDBACK(ACT_FEEDBACK_UAVCAN_ID, &feedback, 1);
+ // Send ABI message (or simulate failure)
+ if(!rotwing_state.fail_skew_angle) {
+ AbiSendMsgACT_FEEDBACK(ACT_FEEDBACK_BOARD_ID, &feedback, 1);
+ }
+
+ // Simulate to always have RPM if on and active feedback
+ rotwing_state.meas_rpm[0] = (actuators[SERVO_MOTOR_FRONT_IDX].pprz_val >= 0)? (ROTWING_QUAD_MIN_RPM + 100) : 0;
+ rotwing_state.meas_rpm[1] = (actuators[SERVO_MOTOR_RIGHT_IDX].pprz_val >= 0)? (ROTWING_QUAD_MIN_RPM + 100) : 0;
+ rotwing_state.meas_rpm[2] = (actuators[SERVO_MOTOR_BACK_IDX].pprz_val >= 0)? (ROTWING_QUAD_MIN_RPM + 100) : 0;
+ rotwing_state.meas_rpm[3] = (actuators[SERVO_MOTOR_LEFT_IDX].pprz_val >= 0)? (ROTWING_QUAD_MIN_RPM + 100) : 0;
+ rotwing_state.meas_rpm[4] = (actuators[SERVO_MOTOR_PUSH_IDX].pprz_val >= 0)? (ROTWING_PUSH_MIN_RPM + 100) : 0;
+ for(uint8_t i = 0; i < 5; i++) {
+ rotwing_state.meas_rpm_time[i] = current_time;
+ }
+
+#ifdef SITL
+ if(rotwing_state.fail_hover_motor) {
+ rotwing_state.meas_rpm[0] = 0;
+ rotwing_state.meas_rpm[1] = 0;
+ rotwing_state.meas_rpm[2] = 0;
+ rotwing_state.meas_rpm[3] = 0;
+ }
+
+ if(rotwing_state.fail_pusher_motor) {
+ rotwing_state.meas_rpm[4] = 0;
+ }
+#endif
+
#endif
}
static void rotwing_state_feedback_cb(uint8_t __attribute__((unused)) sender_id,
struct act_feedback_t UNUSED *feedback_msg, uint8_t UNUSED num_act_message)
{
+ float current_time = get_sys_time_float();
for (int i = 0; i < num_act_message; i++) {
+ int idx = feedback_msg[i].idx;
- for (int i = 0; i < num_act_message; i++) {
- // Check for wing rotation feedback
- if ((feedback_msg[i].set.position) && (feedback_msg[i].idx == SERVO_ROTATION_MECH_IDX)) {
- // Get wing rotation angle from sensor
- float wing_angle_rad = 0.5 * M_PI - feedback_msg[i].position;
- rotwing_state_skewing.wing_angle_deg = DegOfRad(wing_angle_rad);
-
- // Bound wing rotation angle
- Bound(rotwing_state_skewing.wing_angle_deg, 0, 90.);
- }
+ // Check for wing rotation feedback
+ if ((feedback_msg[i].set.position) && (idx == SERVO_ROTATION_MECH_IDX || idx == SERVO_BROTATION_MECH_IDX)) {
+ // Get wing rotation angle from sensor
+ float skew_angle_rad = 0.5 * M_PI - feedback_msg[i].position;
+ rotwing_state.meas_skew_angle_deg = DegOfRad(skew_angle_rad);
+ rotwing_state.meas_skew_angle_time = current_time;
}
- // Sanity check that index is valid
- int idx = feedback_msg[i].idx;
+ // Get the RPM feedbacks of the motors
if (feedback_msg[i].set.rpm) {
if ((idx == SERVO_MOTOR_FRONT_IDX) || (idx == SERVO_BMOTOR_FRONT_IDX)) {
- rotwing_state_hover_rpm[0] = feedback_msg->rpm;
+ rotwing_state.meas_rpm[0] = feedback_msg->rpm;
+ rotwing_state.meas_rpm_time[0] = current_time;
} else if ((idx == SERVO_MOTOR_RIGHT_IDX) || (idx == SERVO_BMOTOR_RIGHT_IDX)) {
- rotwing_state_hover_rpm[1] = feedback_msg->rpm;
+ rotwing_state.meas_rpm[1] = feedback_msg->rpm;
+ rotwing_state.meas_rpm_time[1] = current_time;
} else if ((idx == SERVO_MOTOR_BACK_IDX) || (idx == SERVO_BMOTOR_BACK_IDX)) {
- rotwing_state_hover_rpm[2] = feedback_msg->rpm;
+ rotwing_state.meas_rpm[2] = feedback_msg->rpm;
+ rotwing_state.meas_rpm_time[2] = current_time;
} else if ((idx == SERVO_MOTOR_LEFT_IDX) || (idx == SERVO_BMOTOR_LEFT_IDX)) {
- rotwing_state_hover_rpm[3] = feedback_msg->rpm;
+ rotwing_state.meas_rpm[3] = feedback_msg->rpm;
+ rotwing_state.meas_rpm_time[3] = current_time;
+ } else if ((idx == SERVO_MOTOR_PUSH_IDX) || (idx == SERVO_BMOTOR_PUSH_IDX)) {
+ rotwing_state.meas_rpm[4] = feedback_msg->rpm;
+ rotwing_state.meas_rpm_time[4] = current_time;
}
}
}
}
bool rotwing_state_hover_motors_running(void) {
+ float current_time = get_sys_time_float();
// Check if hover motors are running
-
-#if USE_NPS
- return true;
-#endif
-
- if (rotwing_state_hover_rpm[0] > ROTWING_HOV_MOT_RUN_RPM_TH
- && rotwing_state_hover_rpm[1] > ROTWING_HOV_MOT_RUN_RPM_TH
- && rotwing_state_hover_rpm[2] > ROTWING_HOV_MOT_RUN_RPM_TH
- && rotwing_state_hover_rpm[3] > ROTWING_HOV_MOT_RUN_RPM_TH) {
+ if (rotwing_state.meas_rpm[0] > ROTWING_QUAD_MIN_RPM
+ && rotwing_state.meas_rpm[1] > ROTWING_QUAD_MIN_RPM
+ && rotwing_state.meas_rpm[2] > ROTWING_QUAD_MIN_RPM
+ && rotwing_state.meas_rpm[3] > ROTWING_QUAD_MIN_RPM
+ && (current_time - rotwing_state.meas_rpm_time[0]) < ROTWING_RPM_TIMEOUT
+ && (current_time - rotwing_state.meas_rpm_time[1]) < ROTWING_RPM_TIMEOUT
+ && (current_time - rotwing_state.meas_rpm_time[2]) < ROTWING_RPM_TIMEOUT
+ && (current_time - rotwing_state.meas_rpm_time[3]) < ROTWING_RPM_TIMEOUT) {
return true;
} else {
return false;
}
}
+bool rotwing_state_pusher_motor_running(void) {
+ // Check if pusher motor is running
+ if (rotwing_state.meas_rpm[4] > ROTWING_PUSH_MIN_RPM && (get_sys_time_float() - rotwing_state.meas_rpm_time[4]) < ROTWING_RPM_TIMEOUT) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool rotwing_state_skew_angle_valid(void) {
+ // Check if the measured skew angle is timed out and the reference model is matching
+ bool skew_timeout = (get_sys_time_float() - rotwing_state.meas_skew_angle_time) > ROTWING_RPM_TIMEOUT;
+ bool skew_angle_match = fabs(rotwing_state.meas_skew_angle_deg - rotwing_state.ref_model_skew_angle_deg) < ROTWING_SKEW_REF_MODEL_MAX_DIFF;
+
+ return (!skew_timeout && skew_angle_match);
+}
+
void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_angle, float pitch_angle)
{
// adjust weights
- float fixed_wing_percentage = !hover_motors_active; // TODO: when hover props go below 40%, ...
- Bound(fixed_wing_percentage, 0, 1);
+ float fixed_wing_percentile = (rotwing_state_hover_motors_idling())? 1:0; // TODO: when hover props go below 40%, ...
+ Bound(fixed_wing_percentile, 0, 1);
#define AIRSPEED_IMPORTANCE_IN_FORWARD_WEIGHT 16
float Wv_original[GUIDANCE_INDI_HYBRID_V] = GUIDANCE_INDI_WLS_PRIORITIES;
// Increase importance of forward acceleration in forward flight
- wls_guid_p.Wv[0] = Wv_original[0] * (1.0f + fixed_wing_percentage *
+ wls_guid_p.Wv[0] = Wv_original[0] * (1.0f + fixed_wing_percentile *
AIRSPEED_IMPORTANCE_IN_FORWARD_WEIGHT); // stall n low hover motor_off (weight 16x more important than vertical weight)
struct FloatEulers eulers_zxy;
float_eulers_of_quat_zxy(&eulers_zxy, stateGetNedToBodyQuat_f());
- // Evaluate motors_on boolean
- if (!hover_motors_active) {
- if (stateGetAirspeed_f() < 15.) {
- hover_motors_active = true;
- bool_disable_hover_motors = false;
- } else if (eulers_zxy.theta > RadOfDeg(15.0)) {
- hover_motors_active = true;
- bool_disable_hover_motors = false;
- }
- } else {
- bool_disable_hover_motors = false;
- }
-
float du_min_thrust_z = ((MAX_PPRZ - actuator_state_filt_vect[0]) * g1g2[3][0] + (MAX_PPRZ -
actuator_state_filt_vect[1]) * g1g2[3][1] + (MAX_PPRZ - actuator_state_filt_vect[2]) * g1g2[3][2] +
- (MAX_PPRZ - actuator_state_filt_vect[3]) * g1g2[3][3]) * hover_motors_active;
+ (MAX_PPRZ - actuator_state_filt_vect[3]) * g1g2[3][3]) * rotwing_state_hover_motors_running();
Bound(du_min_thrust_z, -50., 0.);
float du_max_thrust_z = -(actuator_state_filt_vect[0] * g1g2[3][0] + actuator_state_filt_vect[1] * g1g2[3][1] +
actuator_state_filt_vect[2] * g1g2[3][2] + actuator_state_filt_vect[3] * g1g2[3][3]);
@@ -772,19 +479,24 @@ void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_angle, fl
float fwd_pitch_limit_rad = RadOfDeg(GUIDANCE_INDI_MAX_PITCH);
float quad_pitch_limit_rad = RadOfDeg(5.0);
- float scheduled_pitch_angle = 0;
+ float airspeed = stateGetAirspeed_f();
+
+ float scheduled_pitch_angle = 0.f;
float pitch_angle_range = 3.;
- if (rotwing_state_skewing.wing_angle_deg < 55) {
- scheduled_pitch_angle = 0;
+ float meas_skew_angle = rotwing_state.meas_skew_angle_deg;
+ Bound(meas_skew_angle, 0, 90); // Bound to prevent errors
+ if (meas_skew_angle < ROTWING_SKEW_ANGLE_STEP) {
+ scheduled_pitch_angle = ROTWING_QUAD_PREF_PITCH;
wls_guid_p.Wu[1] = Wu_gih_original[1];
max_pitch_limit_rad = quad_pitch_limit_rad;
} else {
- float pitch_progression = (rotwing_state_skewing.wing_angle_deg - 55) / 35.;
- scheduled_pitch_angle = pitch_angle_range * pitch_progression;
- wls_guid_p.Wu[1] = Wu_gih_original[1] * (1.f - pitch_progression*0.9);
+ float pitch_progression = (airspeed - rotwing_state.fw_min_airspeed) / 2.f;
+ Bound(pitch_progression, 0.f, 1.f);
+ scheduled_pitch_angle = pitch_angle_range * pitch_progression + ROTWING_QUAD_PREF_PITCH*(1.f-pitch_progression);
+ wls_guid_p.Wu[1] = Wu_gih_original[1] * (1.f - pitch_progression*0.99);
max_pitch_limit_rad = quad_pitch_limit_rad + (fwd_pitch_limit_rad - quad_pitch_limit_rad) * pitch_progression;
}
- if (!hover_motors_active) {
+ if (!rotwing_state_hover_motors_running()) {
scheduled_pitch_angle = 8.;
max_pitch_limit_rad = fwd_pitch_limit_rad;
}
@@ -796,14 +508,26 @@ void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_angle, fl
// Set lower limits
wls_guid_p.u_min[0] = -roll_limit_rad - roll_angle; //roll
wls_guid_p.u_min[1] = min_pitch_limit_rad - pitch_angle; // pitch
- wls_guid_p.u_min[2] = du_min_thrust_z;
- wls_guid_p.u_min[3] = (-actuator_state_filt_vect[8] * g1g2[4][8]);
// Set upper limits limits
wls_guid_p.u_max[0] = roll_limit_rad - roll_angle; //roll
wls_guid_p.u_max[1] = max_pitch_limit_rad - pitch_angle; // pitch
- wls_guid_p.u_max[2] = du_max_thrust_z;
- wls_guid_p.u_max[3] = 9.0; // Hacky value to prevent drone from pitching down in transition
+
+ if(rotwing_state_hover_motors_running()) {
+ wls_guid_p.u_min[2] = du_min_thrust_z;
+ wls_guid_p.u_max[2] = du_max_thrust_z;
+ } else {
+ wls_guid_p.u_min[2] = 0.;
+ wls_guid_p.u_max[2] = 0.;
+ }
+
+ if(rotwing_state_pusher_motor_running()) {
+ wls_guid_p.u_min[3] = (-actuator_state_filt_vect[8] * g1g2[4][8]);
+ wls_guid_p.u_max[3] = 9.0; // Hacky value to prevent drone from pitching down in transition
+ } else {
+ wls_guid_p.u_min[3] = 0.;
+ wls_guid_p.u_max[3] = 0.;
+ }
// Set prefered states
wls_guid_p.u_pref[0] = 0; // prefered delta roll angle
@@ -811,3 +535,86 @@ void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_angle, fl
wls_guid_p.u_pref[2] = wls_guid_p.u_max[2]; // Low thrust better for efficiency
wls_guid_p.u_pref[3] = body_v[0]; // solve the body acceleration
}
+
+void rotwing_state_set(enum rotwing_states_t state) {
+ rotwing_state.nav_state = state;
+}
+
+
+/* TODO move these rotwing navigation helper functions to an appropriate module/file */
+bool rotwing_state_choose_circle_direction(uint8_t wp_id) {
+ // Get circle waypoint coordinates in NED
+ struct FloatVect3 circ_ned = {.x = waypoints[wp_id].enu_f.y,
+ .y = waypoints[wp_id].enu_f.x,
+ .z = -waypoints[wp_id].enu_f.z};
+
+ // Get drone position coordinates in NED
+ struct FloatVect3 pos_ned = {.x = stateGetPositionNed_f()->x,
+ .y = stateGetPositionNed_f()->y,
+ .z = stateGetPositionNed_f()->z};
+
+ // Get vector pointing from drone to waypoint
+ struct FloatVect3 vect_pos_circ;
+ VECT3_DIFF(vect_pos_circ, circ_ned, pos_ned);
+
+ static struct FloatVect3 x_axis = {.x = 1, .y = 0, .z = 0};
+ static struct FloatVect3 z_axis = {.x = 0, .y = 0, .z = 1};
+ struct FloatVect3 att_NED;
+ struct FloatVect3 cross_att_circ;
+
+ float_rmat_transp_vmult(&att_NED, stateGetNedToBodyRMat_f(), &x_axis);
+
+ VECT3_CROSS_PRODUCT(cross_att_circ, vect_pos_circ, att_NED);
+ float y = VECT3_DOT_PRODUCT(cross_att_circ, z_axis);
+ float x = VECT3_DOT_PRODUCT(vect_pos_circ, att_NED);
+
+ float body_to_wp_angle_rad = atan2f(y, x);
+
+ if (body_to_wp_angle_rad >= 0.f) {
+ return true; // CCW circle
+ } else {
+ return false; // CW circle
+ }
+}
+
+void rotwing_state_set_transition_wp(uint8_t wp_id) {
+
+ // Get drone position coordinates in NED
+ struct EnuCoor_f target_enu = {.x = stateGetPositionNed_f()->y,
+ .y = stateGetPositionNed_f()->x,
+ .z = -stateGetPositionNed_f()->z};
+
+ static struct FloatVect3 x_axis = {.x = 1, .y = 0, .z = 0};
+ struct FloatVect3 x_att_NED;
+
+ float_rmat_transp_vmult(&x_att_NED, stateGetNedToBodyRMat_f(), &x_axis);
+
+ // set the new transition WP coordinates 100m ahead of the drone
+ target_enu.x = 100.f * x_att_NED.y + target_enu.x;
+ target_enu.y = 100.f * x_att_NED.x + target_enu.y;
+
+ waypoint_set_enu(wp_id, &target_enu);
+
+ // Send waypoint update every half second
+ RunOnceEvery(100 / 2, {
+ // Send to the GCS that the waypoint has been moved
+ DOWNLINK_SEND_WP_MOVED_ENU(DefaultChannel, DefaultDevice, &wp_id,
+ &waypoints[wp_id].enu_i.x,
+ &waypoints[wp_id].enu_i.y,
+ &waypoints[wp_id].enu_i.z);
+ });
+
+}
+
+void rotwing_state_update_WP_height(uint8_t wp_id, float height) {
+ struct EnuCoor_f target_enu = {.x = waypoints[wp_id].enu_f.x,
+ .y = waypoints[wp_id].enu_f.y,
+ .z = height};
+
+ waypoint_set_enu(wp_id, &target_enu);
+
+ DOWNLINK_SEND_WP_MOVED_ENU(DefaultChannel, DefaultDevice, &wp_id,
+ &waypoints[wp_id].enu_i.x,
+ &waypoints[wp_id].enu_i.y,
+ &waypoints[wp_id].enu_i.z);
+}
diff --git a/sw/airborne/modules/rotwing_drone/rotwing_state.h b/sw/airborne/modules/rotwing_drone/rotwing_state.h
index 981f7977b1..cfb03d887c 100644
--- a/sw/airborne/modules/rotwing_drone/rotwing_state.h
+++ b/sw/airborne/modules/rotwing_drone/rotwing_state.h
@@ -28,70 +28,66 @@
#include "std.h"
-/** Rotwing States
- */
-#define ROTWING_STATE_HOVER 0 // Wing is skewed in 0 degrees (quad)
-#define ROTWING_STATE_SKEWING 1 // WIng is skewing
-#define ROTWING_STATE_FW 2 // Wing is skewed at 90 degrees (fixed wing), hover motors have full authority
-#define ROTWING_STATE_FW_HOV_MOT_IDLE 3 // Wing is skewed at 90 degrees (fixed wing), hover motors are forced to idle
-#define ROTWING_STATE_FW_HOV_MOT_OFF 4 // Wing is skewed at 90 degrees (fixed wubg), hover motors are switched off
-#define ROTWING_STATE_FREE 5 // This is a desired state for which the controller has to decide the desired state itself
-
-/** Rotwing Configurations
- */
-#define ROTWING_CONFIGURATION_HOVER 0 // UAV is in hover
-#define ROTWING_CONFIGURATION_HYBRID 1 // UAV can fly forward and hover if airspeed low, hover motors on
-#define ROTWING_CONFIGURATION_EFFICIENT 2 // UAV flies efficiently forward (FW)
-#define ROTWING_CONFIGURATION_FREE 3 // UAV switched between efficient and hybrid dependent on deceleration
-
-struct RotwingState {
- uint8_t current_state;
- uint8_t desired_state;
- uint8_t requested_config;
+enum rotwing_states_t {
+ ROTWING_STATE_FORCE_HOVER,
+ ROTWING_STATE_REQUEST_HOVER,
+ ROTWING_STATE_FORCE_FW,
+ ROTWING_STATE_REQUEST_FW,
+ ROTWING_STATE_FREE,
};
-#define ROTWING_STATE_WING_QUAD_SETTING 0 // Wing skew at 0 degrees
-#define ROTWING_STATE_WING_SCHEDULING_SETTING 1 // Wing skew handled by airspeed scheduler
-#define ROTWING_STATE_WING_FW_SETTING 2 // Wing skew at 90 degrees
-
-#define ROTWING_STATE_PITCH_QUAD_SETTING 0 // Pitch at prefered hover
-#define ROTWING_STATE_PITCH_TRANSITION_SETTING 1 // Pitch scheduled
-#define ROTWING_STATE_PITCH_FW_SETTING 2 // Pitch at prefered forward
-
-struct RotWingStateSettings {
- uint8_t wing_scheduler;
- bool hover_motors_active;
- bool hover_motors_disable;
- bool force_forward;
- uint8_t preferred_pitch;
- bool stall_protection;
- float max_v_climb;
- float max_v_descend;
- float nav_max_speed;
+union rotwing_bitmask_t {
+ uint16_t value;
+ struct {
+ bool skew_angle_valid : 1; // Skew angle didn't timeout
+ bool hover_motors_enabled : 1; // Hover motors command is enabled
+ bool hover_motors_idle : 1; // Hover motors are idling (throttle < IDLE_THROTTLE)
+ bool hover_motors_running : 1; // Hover motors are running (RPM >= MIN_RPM)
+ bool pusher_motor_running : 1; // Pusher motor is running (RPM >= MIN_RPM)
+ bool skew_forced : 1; // Skew angle is forced
+ };
};
-struct RotWingStateSkewing {
- float wing_angle_deg_sp; // Wing angle setpoint in deg
- float wing_angle_deg; // Wing angle from sensor in deg
- int32_t servo_pprz_cmd; // Wing rotation servo pprz cmd
- bool airspeed_scheduling; // Airspeed scheduling on or off
- bool force_rotation_angle; // Setting to force wing_angle_deg_sp
+struct rotwing_state_t {
+ /* Control */
+ enum rotwing_states_t state; // Current state
+ enum rotwing_states_t nav_state; // Desired navigation state (requested only by NAV and can be overruled by RC)
+ bool hover_motors_enabled; // Hover motors enabled (> idle throttle)
+
+ /* Skew */
+ float sp_skew_angle_deg; // Setpoint skew angle in degrees
+ float ref_model_skew_angle_deg; // Reference model skew angle in degrees
+ float meas_skew_angle_deg; // Measured skew angle in degrees
+ float meas_skew_angle_time; // Time of the last skew angle measurement
+ bool force_skew; // Force skew angle to a certain value by the GCS
+ int16_t skew_cmd; // Skewing command in pprz values
+
+ /* Airspeeds */
+ float fw_min_airspeed; // Minimum airspeed (stall+margin)
+ float cruise_airspeed; // Airspeed for cruising
+ float min_airspeed; // Minimum airspeed for bounding
+ float max_airspeed; // Maximum airspeed for bounding
+
+ /* RPM measurements*/
+ int32_t meas_rpm[5]; // Measured RPM of the hover and pusher motors
+ float meas_rpm_time[5]; // Time of the last RPM measurement
+
+ /* Sim failures */
+ bool fail_skew_angle; // Skew angle sensor failure
+ bool fail_hover_motor; // Hover motor failure
+ bool fail_pusher_motor; // Pusher motor failure
};
+extern struct rotwing_state_t rotwing_state;
-extern struct RotwingState rotwing_state;
-extern struct RotWingStateSettings rotwing_state_settings;
-extern struct RotWingStateSkewing rotwing_state_skewing;
+void rotwing_state_init(void);
+void rotwing_state_periodic(void);
+bool rotwing_state_hover_motors_running(void);
+bool rotwing_state_pusher_motor_running(void);
+bool rotwing_state_skew_angle_valid(void);
-extern float rotwing_state_max_hover_speed;
-
-extern bool hover_motors_active;
-extern bool bool_disable_hover_motors;
-
-extern void init_rotwing_state(void);
-extern void periodic_rotwing_state(void);
-extern void request_rotwing_state(uint8_t state);
-extern void rotwing_request_configuration(uint8_t configuration);
-extern void rotwing_state_skew_actuator_periodic(void);
-extern bool rotwing_state_hover_motors_running(void);
+void rotwing_state_set(enum rotwing_states_t state);
+bool rotwing_state_choose_circle_direction(uint8_t wp_id);
+void rotwing_state_set_transition_wp(uint8_t wp_id);
+void rotwing_state_update_WP_height(uint8_t wp_id, float height);
#endif // ROTWING_STATE_H
diff --git a/sw/ext/pprzlink b/sw/ext/pprzlink
index 27ddd6516e..3f994e7f9b 160000
--- a/sw/ext/pprzlink
+++ b/sw/ext/pprzlink
@@ -1 +1 @@
-Subproject commit 27ddd6516e384d204d68314503df469b80c72b6e
+Subproject commit 3f994e7f9b9b898f2c500406f57df0349f30ce3f
diff --git a/sw/ground_segment/python/rotwing_visualizer/rotwing_vis_o3d_app.py b/sw/ground_segment/python/rotwing_visualizer/rotwing_vis_o3d_app.py
index a39987eac6..1fac92d8a4 100755
--- a/sw/ground_segment/python/rotwing_visualizer/rotwing_vis_o3d_app.py
+++ b/sw/ground_segment/python/rotwing_visualizer/rotwing_vis_o3d_app.py
@@ -70,14 +70,14 @@ class AHRSRefQuatMessage(object):
class RotWingControllerMessage(object):
def __init__(self, msg):
- self.wing_angle_deg = msg['wing_angle_deg']
- self.wing_angle_deg_sp = msg['wing_angle_deg_sp']
+ self.meas_skew_angle_deg = msg['meas_skew_angle']
+ self.sp_skew_angle_deg = msg['sp_skew_angle']
def get_wing_angle(self):
- return np.deg2rad(float(self.wing_angle_deg))
+ return np.deg2rad(float(self.meas_skew_angle_deg))
def get_wing_angle_sp(self):
- return np.deg2rad(float(self.wing_angle_deg_sp))
+ return np.deg2rad(float(self.sp_skew_angle_deg))
class ActuatorsMessage(object):
def __init__(self, msg):