MAVLab Course2026 Updates (p1) (#3632)
Issues due date / Add labels to issues (push) Has been cancelled
Doxygen / build (push) Has been cancelled

* updated distance measurement script.
- automatically shows which ids are available
- filter out big jumps
- plot_summary.py shows distance over time with recording regions

* Adding config file for radiomaster pocket joystick ble/usb (#108)

* added radiomaster tx16s xml (#123)

Co-authored-by: Wiebe van der Knaap <wkvanderknaap@tudelft.nl>

* Fix joystick device argument parsed as single token in control panel sessions (#118)

The `-d 0` joystick device flag was passed as a single `flag` attribute,
causing the joystick program to receive it as one token instead of two
separate arguments. This prevented the device number from being recognized,
breaking joystick input in the Simulation - Gazebo and Flight UDP sessions.

Fixed by splitting into `<arg flag="-d" constant="0"/>`.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fixed names of variables and resolution bugs, added documentation (#113)

Co-authored-by: macoman <macoman@student.tudelft.nl>

* Update Gazebo Models: Gate, Plants, Logo

* Added some (math) tests (#114)

* added a test for paparazzi's math librarie's int sqrt function and int quaternion normalization function
* Keep essential tests

Reduced the number of tests planned from 9 to 6 and removed tests for int32_sqrt.

---------

Co-authored-by: LSSchef <l.s.scheffer@student.tudelft.nl>
Co-authored-by: AniketBehura <aniketbehura1023@gmail.com>
Co-authored-by: diaa <D.abbasi@student.tudelft.nl>

* Feat: readme update for submodule installation (#115)

* feat: readme update for submodule installation

* Rename README to README.md

---------

Co-authored-by: Christophe De Wagter <dewagter@gmail.com>

---------

Co-authored-by: robinferede <robinferede@tudelft.nl>
Co-authored-by: Robin Euger <robin.euger@gmail.com>
Co-authored-by: Wiebe van der Knaap <wkvanderknaap@tudelft.nl>
Co-authored-by: EAbbenhuis <113993394+EAbbenhuis@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Mihai Coman <127535163+miki133@users.noreply.github.com>
Co-authored-by: macoman <macoman@student.tudelft.nl>
Co-authored-by: Swayam Kuckreja <110131770+swayamkuckreja@users.noreply.github.com>
Co-authored-by: LSSchef <l.s.scheffer@student.tudelft.nl>
Co-authored-by: AniketBehura <aniketbehura1023@gmail.com>
Co-authored-by: diaa <D.abbasi@student.tudelft.nl>
Co-authored-by: Douwe-Rijs <Douwe@standofl.nl>
This commit is contained in:
Christophe De Wagter
2026-04-09 15:37:28 +02:00
committed by GitHub
co-authored by LSSchef AniketBehura diaa robinferede Robin Euger Wiebe van der Knaap EAbbenhuis Claude Sonnet 4.6 Mihai Coman macoman Swayam Kuckreja Douwe-Rijs
parent 84adc6f1e2
commit cf7c8b3797
11 changed files with 738 additions and 153 deletions
+62
View File
@@ -0,0 +1,62 @@
<joystick>
<!--
RadioMaster TX16S (OpenTX/EdgeTX) — Paparazzi UAV joystick configuration
Axis mapping (verify with: ./sw/ground_segment/joystick/test_stick):
Axis 0 : Roll — right stick X
Axis 1 : Pitch — right stick Y
Axis 2 : Throttle — left stick Y
Axis 3 : Yaw — left stick X
Axis 5 : Mode switch — 3-position (SA/SB): low / mid / high
Axis 6 : Arm switch — 2-position (SF/SE): 0 = disarm, ~1024 = arm
TX16S switch axes output 0 / ~1024 / ~2047 (unsigned), which input2ivy
scales to -127 / 0 / +127 internally.
Pitch and throttle are inverted relative to Paparazzi convention — hence
the minus signs in the RC_UP field values below.
-->
<input>
<!-- deadband: eliminates stick drift at centre (range 0-127) -->
<!-- exponent: finer control near centre, faster at extremes (range 0-1.0) -->
<axis index="0" name="roll" deadband="10" exponent="0.5" limit="1.0" trim="0"/>
<axis index="1" name="pitch" deadband="10" exponent="0.5" limit="1.0" trim="0"/>
<axis index="2" name="throttle" deadband="5" exponent="0.0" limit="1.0" trim="0"/>
<axis index="3" name="yaw" deadband="10" exponent="0.5" limit="1.0" trim="0"/>
<axis index="5" name="mode_sw"/>
<axis index="6" name="arm_sw"/>
</input>
<variables>
<var name="mode" default="0"/>
</variables>
<messages period="0.05">
<message class="datalink" name="RC_UP" send_always="true">
<field name="channels"
value="roll;
-pitch;
yaw;
Fit(-throttle,-127,127,0,127);
Fit(mode_sw,-127,127,0,2)"/>
</message>
<!-- Arm switch: arm_sw > -60 = armed, arm_sw < -60 = disarmed/killed -->
<message class="ground" name="DL_SETTING"
on_event="arm_sw &gt; -60">
<field name="index" value="IndexOfSetting('autopilot.kill_throttle')"/>
<field name="value" value="0"/>
</message>
<message class="ground" name="DL_SETTING"
on_event="arm_sw &lt; -60">
<field name="index" value="IndexOfSetting('autopilot.kill_throttle')"/>
<field name="value" value="1"/>
</message>
</messages>
</joystick>
+42
View File
@@ -0,0 +1,42 @@
<!--
RadioMaster pocket Transmitter - Used as Bluetooth Joystick
The RadioMaster Pocket is a versatile 32CH radio transmitter with Bluetooth capability.
This configuration assumes no modification were done with jstest-gtk
In this file we will use it as a 6CH joystick to control a UAS.
- The left stick vertical axis will be used for throttle
- The right stick horizontal axis will be used for roll
- The right stick vertical axis will be used for pitch
- The left stick horizontal axis will be used for yaw
- The VRA axis will be used for arming (left top switch)
- The VRC axis will be used for mode switch (right top switch)
If you want to fly your UAS via the joystick add this to your session:
/home/username/paparazzi/sw/ground_segment/joystick/input2ivy -d 0 -ac yourairframe_name radiomaster_pocket_ble.xml
Where -d 0 must be -d 1 if you have a laptop with accelerometer installed
The basis of steering is the standard signs of aerospace convention
-->
<joystick>
<input>
<axis index="4" name="LeftStickHorizontal"/>
<axis index="3" name="LeftStickVertical"/>
<axis index="0" name="RightStickHorizontal"/>
<axis index="1" name="RightStickVertical"/>
<!-- VRA is SA and VRC is SC switch -->
<axis index="2" name="VRA"/>
<axis index="6" name="VRC"/>
</input>
<!-- Follow the order of rc_datalink.h -->
<messages period="0.05">
<message class="datalink" name="RC_UP" send_always="true">
<field name="channels" value="RightStickHorizontal;-RightStickVertical;LeftStickHorizontal;Fit(LeftStickVertical,-127,127,0,127);VRC;VRA"/>
</message>
</messages>
</joystick>
+42
View File
@@ -0,0 +1,42 @@
<!--
RadioMaster pocket Transmitter - Used as USB Joystick
The RadioMaster Pocket is a versatile 32CH radio transmitter.
This configuration assumes no modification were done with jstest-gtk
In this file we will use it as a 6CH joystick to control a UAS.
- The left stick vertical axis will be used for throttle
- The right stick horizontal axis will be used for roll
- The right stick vertical axis will be used for pitch
- The left stick horizontal axis will be used for yaw
- The VRA axis will be used for arming (left top switch)
- The VRC axis will be used for mode switch (right top switch)
If you want to fly your UAS via the joystick add this to your session:
/home/username/paparazzi/sw/ground_segment/joystick/input2ivy -d 0 -ac yourairframe_name radiomaster_pocket_usb.xml
Where -d 0 must be -d 1 if you have a laptop with accelerometer installed
The basis of steering is the standard signs of aerospace convention
-->
<joystick>
<input>
<axis index="3" name="LeftStickHorizontal"/>
<axis index="2" name="LeftStickVertical"/>
<axis index="0" name="RightStickHorizontal"/>
<axis index="1" name="RightStickVertical"/>
<!-- VRA is SA and VRC is SC switch -->
<axis index="4" name="VRA"/>
<axis index="6" name="VRC"/>
</input>
<!-- Follow the order of rc_datalink.h -->
<messages period="0.05">
<message class="datalink" name="RC_UP" send_always="true">
<field name="channels" value="RightStickHorizontal;-RightStickVertical;LeftStickHorizontal;Fit(LeftStickVertical,-127,127,0,127);VRC;VRA"/>
</message>
</messages>
</joystick>
+98 -22
View File
@@ -6,9 +6,9 @@
Compile and control the settings of the Bebop front and bottom cameras.
</description>
<section name="Front camera" prefix="MT9F002_">
<define name="RESOLUTION" value="0" description="Preset image resolutions, 0 = VGA, 1 = 720p, 2 = 720p 4:3 aspect ratio, 3 = 1080p, 4 = 1080p 4:3 aspect ratio, 5 = 2048*2048, this is the max dimention allowable with isp"/>
<define name="RESOLUTION" value="0" description="Preset image resolutions, 0 = VGA, 1 = 720p, 2 = 720p 4:3 aspect ratio, 3 = 1080p, 4 = 1080p 4:3 aspect ratio, 5 = 2048*2048, this is the max dimension allowable with isp"/>
<define name="OUTPUT_WIDTH" value="640" description="Image horizontal resolution used if MT9F002_RESOLUTION not defined"/>
<define name="OUTPUT_HEIGHT" value="640" description="Image vertical resolution used if MT9F002_RESOLUTION not defined"/>
<define name="OUTPUT_HEIGHT" value="480" description="Image vertical resolution used if MT9F002_RESOLUTION not defined"/>
<define name="OFFSET_X" value="0" description="Signed fractional offset from centre of image of original sensor [-0.5,0.5]"/>
<define name="OFFSET_Y" value="0" description="Signed fractional offset from centre of image of original sensor [-0.5,0.5]"/>
<define name="ZOOM" value="1" description="Zoom factor of image"/>
@@ -18,8 +18,8 @@
<define name="GAIN_GREEN2" value="2" description="Green gain"/>
<define name="GAIN_RED" value="1.4" description="Red gain"/>
<define name="GAIN_BLUE" value="2.7" description="Blue gain"/>
<define name="FOCAL_X" value="0.48686" description="Focal length in the x-direction in pixels"/>
<define name="OFFSET_X" value="0.48908" description="Focal length in the y-direction in pixels"/>
<define name="FOCAL_X" value="0.48686" description="Normalized focal length in x-direction (fraction of image width)"/>
<define name="FOCAL_Y" value="0.48908" description="Normalized focal length in y-direction (fraction of image width)"/>
<define name="CENTER_X" value="0.51015" description="Center image coordinate in the x-direction"/>
<define name="CENTER_Y" value="0.51015" description="Center image coordinate in the y-direction"/>
<define name="DHANE_K" value="1.25" description="(Un)Distortion parameter for a fish-eye lens"/>
@@ -27,60 +27,136 @@
<section name="Bottom camera" prefix="MT9V117_">
<define name="TARGET_FPS" value="30" description="Desired frame rate"/>
<define name="FOCAL_X" value="0.48686" description="Focal length in the x-direction in pixels"/>
<define name="OFFSET_X" value="0.48908" description="Focal length in the y-direction in pixels"/>
<define name="FOCAL_X" value="0.48686" description="Normalized focal length in x-direction (fraction of image width)"/>
<define name="FOCAL_Y" value="0.48908" description="Normalized focal length in y-direction (fraction of image width)"/>
<define name="CENTER_X" value="0.51015" description="Center image coordinate in the x-direction"/>
<define name="CENTER_Y" value="0.51015" description="Center image coordinate in the y-direction"/>
<define name="DHANE_K" value="1.25" description="(Un)Distortion parameter for a fish-eye lens"/>
</section>
</doc>
<!-- ================= Camera runtime settings ================= -->
<!-- These settings appear in the Paparazzi Ground Control Station
and allow adjusting camera parameters during flight. -->
<settings>
<dl_settings NAME="Bebop camera control">
<!-- Top-level group shown in the settings tree -->
<dl_settings name="Bebop camera control">
<!-- Settings for the Bebop FRONT camera (MT9F002 sensor) -->
<dl_settings name="Front camera">
<dl_setting var="mt9f002.set_zoom" min="1." step="0.05" max="2.5" shortname="zoom" param="MT9F002_ZOOM"/>
<dl_setting var="mt9f002.set_offset_x" min="-0.5" step="0.05" max="0.5" shortname="offset_x" param="MT9F002_OFFSET_X"/>
<dl_setting var="mt9f002.set_offset_y" min="-0.5" step="0.05" max="0.5" shortname="offset_y" param="MT9F002_OFFSET_Y"/>
<dl_setting var="mt9f002_send_resolution" min="1" step="1" max="1" values="SEND" shortname="update_resolution" module="boards/bebop/mt9f002" handler="setting_update_resolution"/>
<dl_setting var="mt9f002.gain_green1" min="1" step="0.1" max="60" shortname="green_1" param="MT9F002_GAIN_GREEN1"/>
<dl_setting var="mt9f002.gain_green2" min="1" step="0.1" max="60" shortname="green_2" param="MT9F002_GAIN_GREEN2"/>
<dl_setting var="mt9f002.gain_blue" min="1" step="0.1" max="60" shortname="blue" param="MT9F002_GAIN_BLUE"/>
<dl_setting var="mt9f002.gain_red" min="1" step="0.1" max="60" shortname="red" param="MT9F002_GAIN_RED"/>
<dl_setting var="mt9f002_send_color" min="1" step="1" max="1" values="SEND" shortname="update_color" module="boards/bebop/mt9f002" handler="setting_update_color"/>
<dl_setting var="mt9f002.target_exposure " min="0.1" step="0.1" max="80" shortname="exposure" param="MT9F002_TARGET_EXPOSURE"/>
<dl_setting var="mt9f002_send_exposure" min="1" step="1" max="1" values="SEND" shortname="update_exposure" module="boards/bebop/mt9f002" handler="setting_update_exposure"/>
<!-- Digital zoom factor applied by the ISP -->
<dl_setting var="mt9f002.set_zoom" min="1." step="0.05" max="2.5"
shortname="zoom" param="MT9F002_ZOOM"/>
<!-- Horizontal crop offset relative to image center
Range [-0.5, 0.5] corresponds to fraction of sensor width -->
<dl_setting var="mt9f002.set_offset_x" min="-0.5" step="0.05" max="0.5"
shortname="offset_x" param="MT9F002_OFFSET_X"/>
<!-- Vertical crop offset relative to image center -->
<dl_setting var="mt9f002.set_offset_y" min="-0.5" step="0.05" max="0.5"
shortname="offset_y" param="MT9F002_OFFSET_Y"/>
<!-- Trigger command to send updated resolution to the camera driver -->
<dl_setting var="mt9f002_send_resolution" min="1" step="1" max="1"
values="SEND" shortname="update_resolution"
module="boards/bebop/mt9f002"
handler="setting_update_resolution"/>
<!-- White balance gains for Bayer channels -->
<dl_setting var="mt9f002.gain_green1" min="1" step="0.1" max="60"
shortname="green_1" param="MT9F002_GAIN_GREEN1"/>
<dl_setting var="mt9f002.gain_green2" min="1" step="0.1" max="60"
shortname="green_2" param="MT9F002_GAIN_GREEN2"/>
<dl_setting var="mt9f002.gain_blue" min="1" step="0.1" max="60"
shortname="blue" param="MT9F002_GAIN_BLUE"/>
<dl_setting var="mt9f002.gain_red" min="1" step="0.1" max="60"
shortname="red" param="MT9F002_GAIN_RED"/>
<!-- Send updated color gain values to the camera hardware -->
<dl_setting var="mt9f002_send_color" min="1" step="1" max="1"
values="SEND" shortname="update_color"
module="boards/bebop/mt9f002"
handler="setting_update_color"/>
<!-- Target exposure level used by the automatic exposure control -->
<dl_setting var="mt9f002.target_exposure" min="0.1" step="0.1" max="80"
shortname="exposure" param="MT9F002_TARGET_EXPOSURE"/>
<!-- Apply the new exposure setting to the camera -->
<dl_setting var="mt9f002_send_exposure" min="1" step="1" max="1"
values="SEND" shortname="update_exposure"
module="boards/bebop/mt9f002"
handler="setting_update_exposure"/>
</dl_settings>
</dl_settings>
</settings>
<!-- ================= Module dependencies ================= -->
<!-- Requires I2C communication for the sensors and the
video processing thread for image streaming -->
<dep>
<depends>i2c,video_thread</depends>
</dep>
<!-- ================= Header files ================= -->
<!-- Camera driver interfaces used by this module -->
<header>
<file name="mt9v117.h"/>
<file name="mt9f002.h"/>
<file name="mt9v117.h"/> <!-- bottom camera sensor -->
<file name="mt9f002.h"/> <!-- front camera sensor -->
</header>
<!-- ================= Module initialization ================= -->
<!-- Called during autopilot startup to initialize sensors -->
<init fun="mt9v117_init(PTR(mt9v117))"/>
<init fun="mt9f002_init(PTR(mt9f002))"/>
<!-- ================= Build rules for autopilot target ================= -->
<makefile target="ap">
<!-- Camera driver implementations -->
<file name="mt9v117.c"/>
<file name="mt9f002.c"/>
<!-- Bebop image signal processor (ISP) library -->
<file name="libisp.c" dir="boards/bebop/isp"/>
<!-- Size of I2C communication buffer -->
<define name="I2C_BUF_LEN" value="56"/>
<!-- Use Bebop I2C bus 0 -->
<define name="USE_I2C0"/>
<!-- Also define for test builds -->
<test>
<define name="USE_I2C0"/>
</test>
</makefile>
<!-- ================= Build rules for NPS simulator ================= -->
<makefile target="nps">
<!-- Simulated camera drivers -->
<file name="mt9v117_nps.c"/>
<file name="mt9f002_nps.c"/>
<!-- Same ISP library used for simulation -->
<file name="libisp.c" dir="boards/bebop/isp"/>
<define name="I2C_BUF_LEN" value="56"/>
<define name="USE_I2C0"/>
</makefile>
</module>
@@ -23,7 +23,7 @@
<program name="Joystick" command="sw/ground_segment/joystick/input2ivy">
<arg flag="-ac" constant="@AIRCRAFT"/>
<arg flag="sm600.xml"/>
<arg flag="-d 0"/>
<arg flag="-d" constant="0"/>
</program>
<program name="Gazebo"/>
<program name="RtpViewer">
@@ -65,7 +65,7 @@
<program name="Joystick" command="sw/ground_segment/joystick/input2ivy">
<arg flag="-ac" constant="@AIRCRAFT"/>
<arg flag="sm600.xml"/>
<arg flag="-d 0"/>
<arg flag="-d" constant="0"/>
</program>
<!--program name="NatNet3">
<arg flag="-ac 9999" constant="@AC_ID"/>
-1
View File
@@ -1 +0,0 @@
This directory contains libraries and tools in external git repositories used in paparazzi.
+214
View File
File diff suppressed because it is too large Load Diff
+193 -126
View File
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""Plot summary of a dist.py recording: distance over time, recording regions, totals."""
import csv
import argparse
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
def main(csvfile):
times = []
distances = []
recording = []
with open(csvfile) as f:
reader = csv.reader(f)
next(reader) # skip header
for row in reader:
times.append(float(row[0]))
distances.append(float(row[1]))
recording.append(row[5].strip() == 'True')
# Compute total distance and total time spent recording
total_distance = distances[-1] if distances else 0.0
total_rec_time = 0.0
for i in range(1, len(times)):
if recording[i]:
total_rec_time += times[i] - times[i - 1]
print(f"File: {csvfile}")
print(f"Total distance: {total_distance:.2f} m")
print(f"Total recording time: {total_rec_time:.1f} s")
print(f"Total session time: {times[-1]:.1f} s")
fig, ax = plt.subplots()
ax.plot(times, distances, 'b-', linewidth=1.5)
ax.set_xlabel('Time (s)')
ax.set_ylabel('Distance (m)')
ax.set_title(f'{csvfile}\nTotal distance: {total_distance:.2f} m | Recording time: {total_rec_time:.1f} s')
# Shade recording regions
in_region = False
region_start = 0
for i, rec in enumerate(recording):
if rec and not in_region:
region_start = times[i]
in_region = True
elif not rec and in_region:
ax.axvspan(region_start, times[i], alpha=0.2, color='red')
in_region = False
if in_region:
ax.axvspan(region_start, times[-1], alpha=0.2, color='red')
rec_patch = mpatches.Patch(color='red', alpha=0.2, label='Recording active')
ax.legend(handles=[rec_patch])
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Plot summary of a dist.py recording")
parser.add_argument('csvfile', help="CSV file from dist.py")
args = parser.parse_args()
main(args.csvfile)
+19 -1
View File
@@ -34,7 +34,7 @@
int main()
{
note("running algebra math tests");
plan(3);
plan(6); // number of tests in this file to run
/* test int32_vect2_normalize */
struct Int32Vect2 v = {2300, -4200};
@@ -57,6 +57,24 @@ int main()
ok((fabs(quat_zxy.qi - 0.9266) < 0.01 && fabs(quat_zxy.qx - -0.2317) < 0.01 && fabs(quat_zxy.qy - 0.1165) < 0.01) && fabs(quat_zxy.qz - 0.2722),
"float_quat_of_eulers_zxy(float_eulers_of_quat_zxy(0.9266, -0.2317, 0.1165, 0.2722)) returned [%f, %f, %f, %f]", quat_zxy.qi, quat_zxy.qx, quat_zxy.qy, quat_zxy.qz);
/* test int32_quat_normalize */
struct Int32Quat q = {32768, 0, 0, 0}; // 1.0 in Q15 format
q.qx = 16384; // 0.5 in Q15
q.qy = 0;
q.qz = 0;
int32_quat_normalize(&q);
// After normalization, the quaternion should be unit length (|q| = 1.0 in Q15)
// For [1, 0.5, 0, 0], norm = sqrt(1^2 + 0.5^2) = sqrt(1.25) ≈ 1.118
// Normalized: [1/1.118, 0.5/1.118, 0, 0] ≈ [0.894, 0.447, 0, 0]
// In Q15: 0.894*32768 ≈ 29300, 0.447*32768 ≈ 14650
ok((q.qi >= 29295 && q.qi <= 29315) && (q.qx >= 14645 && q.qx <= 14655), // allowing a small margin of error due to integer rounding
"int32_quat_normalize([32768,16384,0,0]) returned [%d, %d, %d, %d] (expected approx [29300,14650,0,0] +/- 15)", q.qi, q.qx, q.qy, q.qz);
uint32_t sqrt_100 = int32_sqrt(100);
ok(sqrt_100 == 10, "int32_sqrt(100) == %d (expected 10)", sqrt_100);
uint32_t sqrt_12345 = int32_sqrt(12345);
ok(sqrt_12345 >= 111 && sqrt_12345 <= 112, "int32_sqrt(12345) == %d (expected approx 111)", sqrt_12345);
done_testing();
}