Compare commits
390 Commits
beacons
...
stable_fli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6461d9622 | ||
|
|
1f83916e0f | ||
|
|
3abaee8250 | ||
|
|
8cbcf17b11 | ||
|
|
d1b2f866e0 | ||
|
|
b3b2a9fe61 | ||
|
|
19367da170 | ||
|
|
02b60650ba | ||
|
|
8f537fbc48 | ||
|
|
e16e083dd0 | ||
|
|
e8f7c1610a | ||
|
|
443e1b8765 | ||
|
|
7935787cec | ||
|
|
fdc15dbe37 | ||
|
|
b3a9b4bf90 | ||
|
|
4062d145f9 | ||
|
|
6467007795 | ||
|
|
9b915ee698 | ||
|
|
40ea450b78 | ||
|
|
0935a1b328 | ||
|
|
4fa2387c85 | ||
|
|
4a5a8eb25e | ||
|
|
af85c1fc20 | ||
|
|
3412fe75c1 | ||
|
|
c95191af5f | ||
|
|
9c7c90653d | ||
|
|
6ae6de7b98 | ||
|
|
a38ca838fd | ||
|
|
e7e06cf6d7 | ||
|
|
1c0e6ade6d | ||
|
|
f18b00867d | ||
|
|
b2254dec57 | ||
|
|
06eb59901e | ||
|
|
9bca57a915 | ||
|
|
10ae3f3e3b | ||
|
|
d50758cb73 | ||
|
|
61ee751642 | ||
|
|
25a9aa3509 | ||
|
|
8cb032b8d7 | ||
|
|
3d74ee2c41 | ||
|
|
3ee881772c | ||
|
|
d1c8ca537f | ||
|
|
33872ab999 | ||
|
|
e240058f44 | ||
|
|
1575afc49c | ||
|
|
dcd707fb34 | ||
|
|
03e9b2f20f | ||
|
|
71a7c30cef | ||
|
|
f080d283f6 | ||
|
|
4257b90da7 | ||
|
|
0c86cdcb53 | ||
|
|
eb599f7641 | ||
|
|
5654e44088 | ||
|
|
fa16f6e304 | ||
|
|
e245e143ca | ||
|
|
f58fb50f26 | ||
|
|
a670aa8c1a | ||
|
|
ff9b01cc79 | ||
|
|
5b4c6c149c | ||
|
|
2c4f601759 | ||
|
|
46d32066a2 | ||
|
|
6b7481da84 | ||
|
|
3b41f4f81d | ||
|
|
eae3620848 | ||
|
|
3ba698cc5c | ||
|
|
94c71e4aa0 | ||
|
|
e4e9d60ead | ||
|
|
cdc8a9fed2 | ||
|
|
503d8f80a9 | ||
|
|
ceb1c8222b | ||
|
|
77262e42e5 | ||
|
|
55e7af159f | ||
|
|
3da7ac0306 | ||
|
|
6bc357b6f8 | ||
|
|
10191e122b | ||
|
|
b20a75dc92 | ||
|
|
9faab231e7 | ||
|
|
9785136a48 | ||
|
|
5424cfb3f4 | ||
|
|
89a37a8f9c | ||
|
|
567604033b | ||
|
|
436051db5e | ||
|
|
3665d0ddd7 | ||
|
|
b3d170a3db | ||
|
|
8a94168414 | ||
|
|
1d5ecf96c8 | ||
|
|
55ec3d7f89 | ||
|
|
7ad74287e4 | ||
|
|
b1dbd291a8 | ||
|
|
678d0e5443 | ||
|
|
e9b80144c7 | ||
|
|
1036530ed2 | ||
|
|
35207a0c04 | ||
|
|
b178db9c33 | ||
|
|
d0800b90ab | ||
|
|
6880dcc8b2 | ||
|
|
905360db88 | ||
|
|
6c4050742b | ||
|
|
fdab7ff112 | ||
|
|
e739736477 | ||
|
|
021b75dd39 | ||
|
|
097ca3c533 | ||
|
|
57662f42b4 | ||
|
|
e4c0db4553 | ||
|
|
31f3959de4 | ||
|
|
7ff51fc904 | ||
|
|
5aad5c4ce2 | ||
|
|
5d07a5975f | ||
|
|
1fb07c5cc3 | ||
|
|
8fb2121056 | ||
|
|
1d80e9530c | ||
|
|
c7fac34a23 | ||
|
|
59871da656 | ||
|
|
4117f415c7 | ||
|
|
ecc49c0751 | ||
|
|
63b40d7e8f | ||
|
|
cc78c73349 | ||
|
|
475d2c20c0 | ||
|
|
228b140c95 | ||
|
|
3366364778 | ||
|
|
93b09a49a9 | ||
|
|
68dd9d4a01 | ||
|
|
ed68bf3a03 | ||
|
|
43e8245844 | ||
|
|
7d82c1f33a | ||
|
|
d9707d6157 | ||
|
|
3cb0184771 | ||
|
|
f83520c29a | ||
|
|
124466c65b | ||
|
|
a236b0d52f | ||
|
|
10d03949ca | ||
|
|
44b3f135a9 | ||
|
|
0a1ef8af3d | ||
|
|
6a29220bc9 | ||
|
|
07f0202d51 | ||
|
|
615190ca06 | ||
|
|
b93a616f58 | ||
|
|
4f4c148b69 | ||
|
|
5bd2885ad8 | ||
|
|
3baad7c7bd | ||
|
|
e9e6e033d1 | ||
|
|
97a72d5a4a | ||
|
|
5ab0a39ee3 | ||
|
|
2485647c72 | ||
|
|
7133a11e92 | ||
|
|
96edc69227 | ||
|
|
be2ef48f0e | ||
|
|
78d5221633 | ||
|
|
2b287c561d | ||
|
|
5f90c53128 | ||
|
|
741fa5b096 | ||
|
|
c88e82d42d | ||
|
|
adac3eb022 | ||
|
|
db1322e2de | ||
|
|
2c3123039e | ||
|
|
72b252a970 | ||
|
|
bb26e74f54 | ||
|
|
a23286f282 | ||
|
|
fbef263682 | ||
|
|
6db6c89bd3 | ||
|
|
779a5c9987 | ||
|
|
85b56aef7b | ||
|
|
bb426cf1dc | ||
|
|
80fa83a42f | ||
|
|
4fd44cec46 | ||
|
|
1b48c1d4b7 | ||
|
|
cfa773231e | ||
|
|
d23a16358b | ||
|
|
e5ae3dedfb | ||
|
|
8a017bd7b9 | ||
|
|
5b779a9ae3 | ||
|
|
0a56a1fbb9 | ||
|
|
66880f710d | ||
|
|
1ea831d1c4 | ||
|
|
ade2b38a58 | ||
|
|
d084827f67 | ||
|
|
796c74f318 | ||
|
|
09b6c6110e | ||
|
|
0a18a68f5c | ||
|
|
b0f261848c | ||
|
|
38079342ff | ||
|
|
5b04a69e78 | ||
|
|
7d2624e717 | ||
|
|
dab4077cef | ||
|
|
a62a640c73 | ||
|
|
b971c7989e | ||
|
|
9852edb8b6 | ||
|
|
a65c6b5894 | ||
|
|
e134bb2b72 | ||
|
|
dd474bf8ea | ||
|
|
2a69321147 | ||
|
|
b058713903 | ||
|
|
e25abc3973 | ||
|
|
1e521ea890 | ||
|
|
517240a463 | ||
|
|
ce89e730fa | ||
|
|
716c80d905 | ||
|
|
f23415f60d | ||
|
|
0b5d4c2c4f | ||
|
|
4249f2b589 | ||
|
|
d149b72c24 | ||
|
|
767c658900 | ||
|
|
2513e56631 | ||
|
|
a9b91d7a49 | ||
|
|
64464d06a5 | ||
|
|
0f0c84cf0c | ||
|
|
bb3942c301 | ||
|
|
c219359487 | ||
|
|
ea4cfb17ec | ||
|
|
8efa23948d | ||
|
|
a919c5b7f7 | ||
|
|
8be8a6d1f3 | ||
|
|
a24c145968 | ||
|
|
baad3abae2 | ||
|
|
0b98dfbf02 | ||
|
|
4846ee5052 | ||
|
|
22126929a7 | ||
|
|
d74b7db6b3 | ||
|
|
8f7e496107 | ||
|
|
de2af0cf7c | ||
|
|
9abee2b965 | ||
|
|
f4819381a5 | ||
|
|
1ff1218359 | ||
|
|
1c995253bd | ||
|
|
8f807bdfa3 | ||
|
|
b9b8c99f20 | ||
|
|
6129216d80 | ||
|
|
5996ac225a | ||
|
|
e7582c5760 | ||
|
|
db2b25e60d | ||
|
|
fb34e50b38 | ||
|
|
d82b1925a4 | ||
|
|
3e740de48e | ||
|
|
c7dd7a25a0 | ||
|
|
65cd11ca11 | ||
|
|
eeb67733d3 | ||
|
|
568197a95a | ||
|
|
500356f4e9 | ||
|
|
7b0520c920 | ||
|
|
3f2ffd6dc7 | ||
|
|
04cad041b6 | ||
|
|
ac759ace13 | ||
|
|
a739fb51c3 | ||
|
|
a9c63cc235 | ||
|
|
e0c9c2601d | ||
|
|
6348e5371f | ||
|
|
4eb876df0c | ||
|
|
9c3dcb463d | ||
|
|
048a1b4929 | ||
|
|
346e41f475 | ||
|
|
33d173d1e0 | ||
|
|
088af872f9 | ||
|
|
60033323d4 | ||
|
|
6b33ded940 | ||
|
|
ae18d7834a | ||
|
|
4449c6cc1f | ||
|
|
23a59a449c | ||
|
|
3fe7b60374 | ||
|
|
19d1987484 | ||
|
|
c0d327165c | ||
|
|
799ef4237e | ||
|
|
0c543614a9 | ||
|
|
c4e9e3bb10 | ||
|
|
37b5f14f72 | ||
|
|
1515206e2e | ||
|
|
52f237fcb5 | ||
|
|
a037b7f00e | ||
|
|
b775f8015c | ||
|
|
10c0b5ae5f | ||
|
|
4b063ce9b2 | ||
|
|
f767ee2583 | ||
|
|
1224735954 | ||
|
|
a3b0b761e7 | ||
|
|
806317a04c | ||
|
|
b03951faab | ||
|
|
5b935af894 | ||
|
|
7545a8a2a8 | ||
|
|
9464dbf5ac | ||
|
|
c9f546cb0c | ||
|
|
f883d826ec | ||
|
|
5a7a54fc53 | ||
|
|
7a2f19d311 | ||
|
|
b8f572d86f | ||
|
|
c8a61cac40 | ||
|
|
52132684d2 | ||
|
|
8acd7f2c73 | ||
|
|
b4494a726d | ||
|
|
c44dcb7f89 | ||
|
|
29931565e2 | ||
|
|
abd5931461 | ||
|
|
7fa1cd5816 | ||
|
|
1775cae443 | ||
|
|
d24f91512f | ||
|
|
bd8cec8516 | ||
|
|
388963511a | ||
|
|
e3466a1077 | ||
|
|
0107bb3c0b | ||
|
|
6bdb10dd5c | ||
|
|
5496e400cf | ||
|
|
4ed6dde80e | ||
|
|
78ac1963df | ||
|
|
fd2ace29ce | ||
|
|
455c495685 | ||
|
|
4540a24d85 | ||
|
|
a12d1836fe | ||
|
|
43f3838979 | ||
|
|
5b6c097bd9 | ||
|
|
b5daa4a77a | ||
|
|
15e530067e | ||
|
|
8b1790f763 | ||
|
|
010559ea9b | ||
|
|
9ace6a70b3 | ||
|
|
5ea8d5674f | ||
|
|
f53385ae0a | ||
|
|
c748bc5da8 | ||
|
|
5c4d47b590 | ||
|
|
0d52a66d2a | ||
|
|
40facd933b | ||
|
|
59421316b4 | ||
|
|
078a4a1a1a | ||
|
|
39ca39e983 | ||
|
|
9af542d4ad | ||
|
|
48b5016897 | ||
|
|
09cda4e1d0 | ||
|
|
8aa5e6fe35 | ||
|
|
8fb86a5e2d | ||
|
|
ed542e2f21 | ||
|
|
df18c9bba6 | ||
|
|
1c1ea30dc0 | ||
|
|
b258131480 | ||
|
|
5f98cb2f10 | ||
|
|
8cbf27cd63 | ||
|
|
85390c0d4d | ||
|
|
6da45f1240 | ||
|
|
9942e65bd3 | ||
|
|
0c944ce3b6 | ||
|
|
2103260f0f | ||
|
|
1fc71c7ca7 | ||
|
|
8fd8662e0d | ||
|
|
e8ecc7eac4 | ||
|
|
fd83eb616a | ||
|
|
3110abcbf0 | ||
|
|
076bb6507b | ||
|
|
de9510c096 | ||
|
|
32d73ba229 | ||
|
|
91354beb0b | ||
|
|
a1b778b74b | ||
|
|
be267f2aff | ||
|
|
615d026eb6 | ||
|
|
263f1c154e | ||
|
|
68cb8effa9 | ||
|
|
a444ce3193 | ||
|
|
091fe9a4ee | ||
|
|
988c546f15 | ||
|
|
225c9ef7ae | ||
|
|
16192c6c8b | ||
|
|
cedff67864 | ||
|
|
682b18d396 | ||
|
|
38a34a6de7 | ||
|
|
1ac0bfead3 | ||
|
|
8712315b92 | ||
|
|
7ae5295134 | ||
|
|
bec6025654 | ||
|
|
4d4647f348 | ||
|
|
98668938cc | ||
|
|
99b34fa55e | ||
|
|
f3e4468339 | ||
|
|
645754e56f | ||
|
|
200f1f97ec | ||
|
|
1c3ab27707 | ||
|
|
4e8e1c8177 | ||
|
|
0f0324ab9d | ||
|
|
126ff49a35 | ||
|
|
345e796392 | ||
|
|
e5ddab280e | ||
|
|
9e5f2363f6 | ||
|
|
4f530da21d | ||
|
|
1df349b478 | ||
|
|
24fc0c2ca5 | ||
|
|
31503b8b70 | ||
|
|
a6fd08738c | ||
|
|
b88d8beb39 | ||
|
|
4df0d69b53 | ||
|
|
ed71dfb0e9 | ||
|
|
353bf74930 | ||
|
|
015d7d7596 | ||
|
|
f0f63b1817 | ||
|
|
eaeb2dba5a | ||
|
|
ee2d5c4d54 | ||
|
|
5ce3d43841 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.vscode/
|
||||
build/
|
||||
install/
|
||||
log/
|
||||
|
||||
5
.vscode/c_cpp_properties.json
vendored
5
.vscode/c_cpp_properties.json
vendored
@@ -10,7 +10,10 @@
|
||||
"/home/ubuntu/ros2_ws/src/beacon_positioning/include/**",
|
||||
"/usr/include/**",
|
||||
"/mnt/Homework/Avans/AFSTUDEERSTAGE/positioning_systems_api/rtls_driver/include/**",
|
||||
"/mnt/Homework/Avans/AFSTUDEERSTAGE/positioning_systems_api/serial_communication/include/**"
|
||||
"/mnt/Homework/Avans/AFSTUDEERSTAGE/positioning_systems_api/serial_communication/include/**",
|
||||
"/mnt/Homework/Avans/AFSTUDEERSTAGE/terabee_api/include/**",
|
||||
"/home/ubuntu/ros2_ws/build/px4_msgs/rosidl_generator_cpp/px4_msgs/msg/**",
|
||||
"/home/ubuntu/ros2_ws/src/px4_connection/include/**"
|
||||
],
|
||||
"name": "ROS",
|
||||
"intelliSenseMode": "gcc-x64",
|
||||
|
||||
61
.vscode/settings.json
vendored
61
.vscode/settings.json
vendored
@@ -1,7 +1,66 @@
|
||||
{
|
||||
"ros.distro": "humble",
|
||||
"files.associations": {
|
||||
"chrono": "cpp"
|
||||
"chrono": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"functional": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"memory": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ratio": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"thread": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"tuple": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"utility": "cpp",
|
||||
"variant": "cpp"
|
||||
},
|
||||
"python.autoComplete.extraPaths": [
|
||||
"/home/ubuntu/ros2_ws/install/px4_msgs/lib/python3.8/site-packages",
|
||||
|
||||
0
TerabeeLog.log
Normal file
0
TerabeeLog.log
Normal file
1
call_attitude.sh
Executable file
1
call_attitude.sh
Executable file
@@ -0,0 +1 @@
|
||||
ros2 service call /drone/set_attitude drone_services/srv/SetAttitude "{pitch: $1, yaw: $2, roll: $3, thrust: $4}"
|
||||
0
drone_scripts/TerabeeLog.log
Normal file
0
drone_scripts/TerabeeLog.log
Normal file
32
drone_scripts/find_id.sh
Executable file
32
drone_scripts/find_id.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
lidarserial=00000000001A
|
||||
heightserial=369A378F3439
|
||||
|
||||
find_by_id(){
|
||||
v=${1%:*}; p=${1#*:} # split vid:pid into 2 vars
|
||||
v=${v#${v%%[!0]*}}; p=${p#${p%%[!0]*}} # strip leading zeros
|
||||
grep -il "^PRODUCT=$v/$p" /sys/bus/usb/devices/*:*/uevent |
|
||||
sed s,uevent,, |
|
||||
xargs -r grep -r '^DEVNAME=' --include uevent
|
||||
}
|
||||
ids=$(find_by_id 0483:5740)
|
||||
echo $ids
|
||||
|
||||
for device in $ids
|
||||
do
|
||||
id=$(echo $device | cut -d "=" -f 2)
|
||||
serial=$(/bin/udevadm info --name=/dev/$id | grep SERIAL_SHORT | cut -d = -f 2)
|
||||
echo "device "$id" has serial number "$serial
|
||||
if [ $serial = $lidarserial ]
|
||||
then
|
||||
echo "LIDAR on port" $id
|
||||
echo $id > /home/ubuntu/drone_conf/lidar.conf
|
||||
elif [ $serial = $heightserial ]
|
||||
then
|
||||
echo "height sensor on port" $id
|
||||
echo $id > /home/ubuntu/drone_conf/height.conf
|
||||
else
|
||||
echo "unknown serial number" $serial
|
||||
fi
|
||||
done
|
||||
10
drone_scripts/start_height_sensor.sh
Executable file
10
drone_scripts/start_height_sensor.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
. /home/ubuntu/source_ros2.sh
|
||||
|
||||
SERIAL=$(cat /home/ubuntu/drone_conf/height.conf)
|
||||
echo "serial port is "$SERIAL
|
||||
echo ros2 run height height_reader --ros-args -p height_serial_port:=/dev/${SERIAL}
|
||||
ros2 run height height_reader --ros-args -p height_serial_port:=/dev/${SERIAL} | tee /home/ubuntu/drone_log/height.log
|
||||
|
||||
|
||||
10
drone_scripts/start_lidar.sh
Executable file
10
drone_scripts/start_lidar.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
. /home/ubuntu/source_ros2.sh
|
||||
|
||||
SERIAL=$(cat /home/ubuntu/drone_conf/lidar.conf)
|
||||
echo "serial port is "$SERIAL
|
||||
echo ros2 run object_detection lidar_reader --ros-args -p lidar_serial_port:=/dev/${SERIAL}
|
||||
ros2 run object_detection lidar_reader --ros-args -p lidar_serial_port:=/dev/${SERIAL} | tee /home/ubuntu/drone_log/lidar.log
|
||||
|
||||
|
||||
7
get_build.sh
Executable file
7
get_build.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
echo "updating git..."
|
||||
./fgit.sh
|
||||
echo "building package..."
|
||||
colcon build --packages-select px4_connection
|
||||
#echo "launching controller..."
|
||||
#ros2 run px4_connection px4_controller
|
||||
1
get_usb_device_port.sh
Normal file
1
get_usb_device_port.sh
Normal file
@@ -0,0 +1 @@
|
||||
/bin/udevadm info --name=/dev/ttyACM0 | grep SERIAL_SHORT | cut -d = -f 2
|
||||
BIN
mav.tlog.raw
Normal file
BIN
mav.tlog.raw
Normal file
Binary file not shown.
1120
script_outputs/microxrcedds.log
Normal file
1120
script_outputs/microxrcedds.log
Normal file
File diff suppressed because it is too large
Load Diff
5474
script_outputs/script-output-25-05-1123.txt
Normal file
5474
script_outputs/script-output-25-05-1123.txt
Normal file
File diff suppressed because one or more lines are too long
12
services/drone_find_usb_devices.service
Normal file
12
services/drone_find_usb_devices.service
Normal file
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=Service to start the script that sets the serial ports for the USB sensors
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
User=ubuntu
|
||||
ExecStart=/home/ubuntu/drone_scripts/find_id.sh
|
||||
WorkingDirectory=/home/ubuntu
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
14
services/drone_height_sensor.service
Normal file
14
services/drone_height_sensor.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Height sensor for drone running in ROS 2
|
||||
After=drone_find_usb_devices.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
User=ubuntu
|
||||
ExecStart=/home/ubuntu/drone_scripts/start_height_sensor.sh
|
||||
Environment="HOME=root"
|
||||
WorkingDirectory=/home/ubuntu
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
14
services/drone_lidar.service
Normal file
14
services/drone_lidar.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Height sensor for drone running in ROS 2
|
||||
After=drone_find_usb_devices.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
User=ubuntu
|
||||
ExecStart=/home/ubuntu/drone_scripts/start_lidar.sh
|
||||
Environment="HOME=root"
|
||||
WorkingDirectory=/home/ubuntu
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -31,7 +31,9 @@ rosidl_generate_interfaces(${PROJECT_NAME}
|
||||
)
|
||||
|
||||
add_executable(tracker_position src/tracker_position.cpp)
|
||||
ament_target_dependencies(tracker_position rclcpp std_msgs beacon_positioning)
|
||||
ament_target_dependencies(tracker_position rclcpp std_msgs
|
||||
beacon_positioning
|
||||
)
|
||||
|
||||
target_link_libraries(tracker_position
|
||||
positioning_systems_api::serial_communication
|
||||
|
||||
@@ -149,7 +149,7 @@ int main(int argc, char **argv)
|
||||
if (tracker_msg.is_valid_position)
|
||||
{
|
||||
RCLCPP_INFO(node->get_logger(), "x = %f, y = %f, z = %f", tracker_msg.tracker_position_xyz.at(0), tracker_msg.tracker_position_xyz.at(1), tracker_msg.tracker_position_xyz.at(2));
|
||||
for (int i = 0; i < tracker_msg.anchors_data.size(); i++)
|
||||
for (size_t i = 0; i < tracker_msg.anchors_data.size(); i++)
|
||||
{
|
||||
RCLCPP_INFO(node->get_logger(), "anchor number= %d, distance = %d, x = %d, y = %d, z = %d", tracker_msg.anchors_data[i].number, tracker_msg.anchors_data[i].distance, tracker_msg.anchors_data[i].pos_x, tracker_msg.anchors_data[i].pos_y, tracker_msg.anchors_data[i].pos_z);
|
||||
}
|
||||
@@ -160,7 +160,7 @@ int main(int argc, char **argv)
|
||||
message.y_pos = tracker_msg.tracker_position_xyz.at(1);
|
||||
message.z_pos = tracker_msg.tracker_position_xyz.at(2);
|
||||
message.anchor_distances = {0, 0, 0, 0};
|
||||
for (int i = 0; i < tracker_msg.anchors_data.size(); i++)
|
||||
for (size_t i = 0; i < tracker_msg.anchors_data.size(); i++)
|
||||
{
|
||||
message.anchor_distances[i] = tracker_msg.anchors_data[i].distance;
|
||||
}
|
||||
|
||||
0
src/camera/camera/__init__.py
Normal file
0
src/camera/camera/__init__.py
Normal file
50
src/camera/camera/camera_controller.py
Normal file
50
src/camera/camera/camera_controller.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
from drone_services.srv import TakePicture
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
# import cv2
|
||||
|
||||
RES_4K_H = 3496
|
||||
RES_4K_W = 4656
|
||||
|
||||
|
||||
class CameraController(Node):
|
||||
def __init__(self):
|
||||
super().__init__('camera_controller')
|
||||
|
||||
self.get_logger().info("Camera controller started. Waiting for service call...")
|
||||
self.srv = self.create_service(
|
||||
TakePicture, 'drone/picture', self.take_picture_callback)
|
||||
|
||||
def take_picture_callback(self, request, response):
|
||||
if (request.input_name == "default"):
|
||||
self.get_logger().info("Taking picture with default filename")
|
||||
now = datetime.now().strftime("droneimage_%Y-%m-%d_%H-%M-%S")
|
||||
imagename = "/home/ubuntu/drone_img/" + now + ".jpg"
|
||||
response.filename = imagename
|
||||
else:
|
||||
response.filename = request.input_name
|
||||
os.system('fswebcam -r ' + RES_4K_W + 'x' + RES_4K_H + ' ' + response.filename)
|
||||
self.get_logger().info("Picture saved as " + response.filename)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
test_controller = CameraController()
|
||||
rclpy.spin(test_controller)
|
||||
|
||||
# Destroy the node explicitly
|
||||
# (optional - otherwise it will be done automatically
|
||||
# when the garbage collector destroys the node object)
|
||||
test_controller.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
21
src/camera/package.xml
Normal file
21
src/camera/package.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>camera</name>
|
||||
<version>0.0.0</version>
|
||||
<description>Package for controlling the camera of the drone</description>
|
||||
<maintainer email="semmer99@gmail.com">ubuntu</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
<exec_depend>drone_services</exec_depend>
|
||||
|
||||
<test_depend>ament_copyright</test_depend>
|
||||
<test_depend>ament_flake8</test_depend>
|
||||
<test_depend>ament_pep257</test_depend>
|
||||
<test_depend>python3-pytest</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_python</build_type>
|
||||
</export>
|
||||
</package>
|
||||
0
src/camera/resource/camera
Normal file
0
src/camera/resource/camera
Normal file
4
src/camera/setup.cfg
Normal file
4
src/camera/setup.cfg
Normal file
@@ -0,0 +1,4 @@
|
||||
[develop]
|
||||
script-dir=$base/lib/camera
|
||||
[install]
|
||||
install-scripts=$base/lib/camera
|
||||
26
src/camera/setup.py
Normal file
26
src/camera/setup.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from setuptools import setup
|
||||
|
||||
package_name = 'camera'
|
||||
|
||||
setup(
|
||||
name=package_name,
|
||||
version='0.0.0',
|
||||
packages=[package_name],
|
||||
data_files=[
|
||||
('share/ament_index/resource_index/packages',
|
||||
['resource/' + package_name]),
|
||||
('share/' + package_name, ['package.xml']),
|
||||
],
|
||||
install_requires=['setuptools'],
|
||||
zip_safe=True,
|
||||
maintainer='ubuntu',
|
||||
maintainer_email='semmer99@gmail.com',
|
||||
description='Package for controlling the camera of the drone',
|
||||
license='Apache License 2.0',
|
||||
tests_require=['pytest'],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'camera_controller = camera.camera_controller:main'
|
||||
],
|
||||
},
|
||||
)
|
||||
23
src/camera/test/test_copyright.py
Normal file
23
src/camera/test/test_copyright.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_copyright.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.copyright
|
||||
@pytest.mark.linter
|
||||
def test_copyright():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found errors'
|
||||
25
src/camera/test/test_flake8.py
Normal file
25
src/camera/test/test_flake8.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_flake8.main import main_with_errors
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.flake8
|
||||
@pytest.mark.linter
|
||||
def test_flake8():
|
||||
rc, errors = main_with_errors(argv=[])
|
||||
assert rc == 0, \
|
||||
'Found %d code style errors / warnings:\n' % len(errors) + \
|
||||
'\n'.join(errors)
|
||||
23
src/camera/test/test_pep257.py
Normal file
23
src/camera/test/test_pep257.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_pep257.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.linter
|
||||
@pytest.mark.pep257
|
||||
def test_pep257():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found code style errors / warnings'
|
||||
33
src/drone_controls/CMakeLists.txt
Normal file
33
src/drone_controls/CMakeLists.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(drone_controls)
|
||||
|
||||
# Default to C99
|
||||
if(NOT CMAKE_C_STANDARD)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
endif()
|
||||
|
||||
# Default to C++14
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# find dependencies
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
# the following line skips the linter which checks for copyrights
|
||||
# uncomment the line when a copyright and license is not present in all source files
|
||||
#set(ament_cmake_copyright_FOUND TRUE)
|
||||
# the following line skips cpplint (only works in a git repo)
|
||||
# uncomment the line when this package is not in a git repo
|
||||
#set(ament_cmake_cpplint_FOUND TRUE)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
endif()
|
||||
|
||||
ament_package()
|
||||
20
src/drone_controls/package.xml
Normal file
20
src/drone_controls/package.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>drone_controls</name>
|
||||
<version>0.0.0</version>
|
||||
<description>TODO: Package description</description>
|
||||
<maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
|
||||
<license>TODO: License declaration</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
|
||||
<depend>rclcpp</depend>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
46
src/drone_services/CMakeLists.txt
Normal file
46
src/drone_services/CMakeLists.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(drone_services)
|
||||
|
||||
# Default to C99
|
||||
if(NOT CMAKE_C_STANDARD)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
endif()
|
||||
|
||||
# Default to C++14
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# find dependencies
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(rosidl_default_generators REQUIRED)
|
||||
|
||||
rosidl_generate_interfaces(${PROJECT_NAME}
|
||||
"srv/SetAttitude.srv"
|
||||
"srv/SetTrajectory.srv"
|
||||
"srv/SetVelocity.srv"
|
||||
"srv/TakePicture.srv"
|
||||
"srv/SetVehicleControl.srv"
|
||||
"srv/ArmDrone.srv"
|
||||
"srv/DisarmDrone.srv"
|
||||
"srv/ControlRelais.srv"
|
||||
"msg/DroneControlMode.msg"
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
# the following line skips the linter which checks for copyrights
|
||||
# uncomment the line when a copyright and license is not present in all source files
|
||||
#set(ament_cmake_copyright_FOUND TRUE)
|
||||
# the following line skips cpplint (only works in a git repo)
|
||||
# uncomment the line when this package is not in a git repo
|
||||
#set(ament_cmake_cpplint_FOUND TRUE)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
endif()
|
||||
|
||||
ament_package()
|
||||
1
src/drone_services/msg/DroneArmStatus.msg
Normal file
1
src/drone_services/msg/DroneArmStatus.msg
Normal file
@@ -0,0 +1 @@
|
||||
bool armed false
|
||||
5
src/drone_services/msg/DroneControlMode.msg
Normal file
5
src/drone_services/msg/DroneControlMode.msg
Normal file
@@ -0,0 +1,5 @@
|
||||
# control mode of the drone
|
||||
# 1: Attitude
|
||||
# 2: Velocity
|
||||
# 3: Position
|
||||
int8 control_mode
|
||||
2
src/drone_services/msg/DroneRouteStatus.msg
Normal file
2
src/drone_services/msg/DroneRouteStatus.msg
Normal file
@@ -0,0 +1,2 @@
|
||||
int32 current_setpoint_index
|
||||
float32[5] current_setpoint # x,y,z,angle,take_picture
|
||||
5
src/drone_services/msg/DroneStatus.msg
Normal file
5
src/drone_services/msg/DroneStatus.msg
Normal file
@@ -0,0 +1,5 @@
|
||||
float32 battery_percentage
|
||||
float32 cpu_usage
|
||||
int32 route_setpoint # -1 if no route
|
||||
wstring control_mode
|
||||
bool armed
|
||||
23
src/drone_services/package.xml
Normal file
23
src/drone_services/package.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>drone_services</name>
|
||||
<version>0.0.0</version>
|
||||
<description>TODO: Package description</description>
|
||||
<maintainer email="ubuntu@todo.todo">ubuntu</maintainer>
|
||||
<license>TODO: License declaration</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
|
||||
<depend>rclcpp</depend>
|
||||
<buildtool_depend>rosidl_default_generators</buildtool_depend>
|
||||
<exec_depend>rosidl_default_runtime</exec_depend>
|
||||
<member_of_group>rosidl_interface_packages</member_of_group>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
2
src/drone_services/srv/ArmDrone.srv
Normal file
2
src/drone_services/srv/ArmDrone.srv
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
bool success
|
||||
5
src/drone_services/srv/ControlRelais.srv
Normal file
5
src/drone_services/srv/ControlRelais.srv
Normal file
@@ -0,0 +1,5 @@
|
||||
#to turn the relais on or off
|
||||
bool relais1_on false
|
||||
bool relais2_on false
|
||||
---
|
||||
int8 bits # relais 1 = bit 0, relais 2 is bit 1
|
||||
2
src/drone_services/srv/DisarmDrone.srv
Normal file
2
src/drone_services/srv/DisarmDrone.srv
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
bool success
|
||||
11
src/drone_services/srv/SetAttitude.srv
Normal file
11
src/drone_services/srv/SetAttitude.srv
Normal file
@@ -0,0 +1,11 @@
|
||||
#service to set attitude setpoints for manual attitude control
|
||||
|
||||
#all angles are in degrees
|
||||
float32 yaw
|
||||
float32 pitch
|
||||
float32 roll
|
||||
|
||||
#thrust between -1 and 1
|
||||
float32 thrust
|
||||
---
|
||||
bool success
|
||||
7
src/drone_services/srv/SetTrajectory.srv
Normal file
7
src/drone_services/srv/SetTrajectory.srv
Normal file
@@ -0,0 +1,7 @@
|
||||
# control mode velocity or position, refer to drone_services/msg/DroneControlMode.msg
|
||||
int8 control_mode
|
||||
# x, y, z values
|
||||
float32[3] values
|
||||
float32 yaw
|
||||
---
|
||||
bool success
|
||||
16
src/drone_services/srv/SetVehicleControl.srv
Normal file
16
src/drone_services/srv/SetVehicleControl.srv
Normal file
@@ -0,0 +1,16 @@
|
||||
# service to set control mode for heartbeat messages
|
||||
# bitmask for control:
|
||||
# bit 0: actuator
|
||||
# bit 1: body rate
|
||||
# bit 2: attitude
|
||||
# bit 3: acceleration
|
||||
# bit 4: velocity
|
||||
# bit 5: position
|
||||
|
||||
# used control modes:
|
||||
# 4: attitude and thrust
|
||||
# 16: velocity
|
||||
# 32: position
|
||||
int32 control # control bitmask
|
||||
---
|
||||
bool success # if operation succeeded
|
||||
9
src/drone_services/srv/SetVelocity.srv
Normal file
9
src/drone_services/srv/SetVelocity.srv
Normal file
@@ -0,0 +1,9 @@
|
||||
#all speeds are in meters/second
|
||||
float32 x_speed
|
||||
float32 y_speed
|
||||
float32 z_speed
|
||||
|
||||
#angle is in degrees
|
||||
float32 angle
|
||||
---
|
||||
bool success
|
||||
3
src/drone_services/srv/TakePicture.srv
Normal file
3
src/drone_services/srv/TakePicture.srv
Normal file
@@ -0,0 +1,3 @@
|
||||
wstring input_name "default" # name of the input file
|
||||
---
|
||||
wstring filename # output file name
|
||||
0
src/drone_status/drone_status/__init__.py
Normal file
0
src/drone_status/drone_status/__init__.py
Normal file
63
src/drone_status/drone_status/drone_status.py
Normal file
63
src/drone_status/drone_status/drone_status.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
from drone_services.msg import DroneStatus
|
||||
from drone_services.msg import DroneControlMode
|
||||
from drone_services.msg import DroneArmStatus
|
||||
from drone_services.msg import DroneRouteStatus
|
||||
from px4_msgs.msg import BatteryStatus
|
||||
from px4_msgs.msg import Cpuload
|
||||
|
||||
CONTROL_MODE_ATTITUDE = 1
|
||||
CONTROL_MODE_VELOCITY = 2
|
||||
CONTROL_MODE_POSITION = 3
|
||||
|
||||
class DroneStatus(Node):
|
||||
def __init__(self):
|
||||
super().__init__('drone_status')
|
||||
#publish to drone/status topic
|
||||
self.publisher = self.create_publisher(DroneStatus, '/drone/status', 10)
|
||||
self.control_mode_subscriber = self.create_subscription(DroneControlMode, '/drone/control_mode', self.control_mode_callback, 10)
|
||||
self.arm_status_subscriber = self.create_subscription(DroneArmStatus, '/drone/arm_status', self.arm_status_callback, 10)
|
||||
self.route_status_subscriber = self.create_subscription(DroneRouteStatus, '/drone/route_status', self.route_status_callback, 10)
|
||||
self.battery_status_subscriber = self.create_subscription(BatteryStatus, '/fmu/out/battery_status', self.battery_status_callback, 10)
|
||||
self.cpu_load_subscriber = self.create_subscription(Cpuload, '/fmu/out/cpuload', self.cpu_load_callback, 10)
|
||||
#publish every 0.5 seconds
|
||||
self.timer = self.create_timer(0.5, self.publish_status)
|
||||
self.armed = False
|
||||
self.control_mode = "attitude"
|
||||
self.battery_percentage = 100.0
|
||||
self.cpu_usage = 0.0
|
||||
self.route_setpoint = 0
|
||||
|
||||
def publish_status(self):
|
||||
msg = DroneStatus()
|
||||
msg.armed = self.armed
|
||||
msg.control_mode = self.control_mode
|
||||
msg.battery_percentage = self.battery_percentage
|
||||
msg.cpu_usage = self.cpu_usage
|
||||
msg.route_setpoint = self.route_setpoint
|
||||
self.publisher.publish(msg)
|
||||
self.get_logger().info('Publishing: "%s"' % msg.status)
|
||||
|
||||
def control_mode_callback(self,msg):
|
||||
if msg.control_mode == CONTROL_MODE_ATTITUDE:
|
||||
self.control_mode = "attitude"
|
||||
elif msg.control_mode == CONTROL_MODE_VELOCITY:
|
||||
self.control_mode = "velocity"
|
||||
elif msg.control_mode == CONTROL_MODE_POSITION:
|
||||
self.control_mode = "position"
|
||||
else:
|
||||
self.control_mode = "unknown"
|
||||
|
||||
def arm_status_callback(self,msg):
|
||||
self.armed = msg.armed
|
||||
|
||||
def route_status_callback(self,msg):
|
||||
self.route_setpoint = msg.current_setpoint_index
|
||||
|
||||
def battery_status_callback(self, msg):
|
||||
self.battery_percentage = msg.remaining * 100.0
|
||||
|
||||
def cpu_load_callback(self, msg):
|
||||
self.cpu_usage = msg.load
|
||||
21
src/drone_status/package.xml
Normal file
21
src/drone_status/package.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>drone_status</name>
|
||||
<version>0.0.0</version>
|
||||
<description>Package for combining several data points from the drone into a single topic</description>
|
||||
<maintainer email="semmer99@gmail.com">ubuntu</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
<exec_depend>drone_services</exec_depend>
|
||||
<exec_depend>px4_msgs</exec_depend>
|
||||
|
||||
<test_depend>ament_copyright</test_depend>
|
||||
<test_depend>ament_flake8</test_depend>
|
||||
<test_depend>ament_pep257</test_depend>
|
||||
<test_depend>python3-pytest</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_python</build_type>
|
||||
</export>
|
||||
</package>
|
||||
0
src/drone_status/resource/drone_status
Normal file
0
src/drone_status/resource/drone_status
Normal file
4
src/drone_status/setup.cfg
Normal file
4
src/drone_status/setup.cfg
Normal file
@@ -0,0 +1,4 @@
|
||||
[develop]
|
||||
script-dir=$base/lib/drone_status
|
||||
[install]
|
||||
install-scripts=$base/lib/drone_status
|
||||
25
src/drone_status/setup.py
Normal file
25
src/drone_status/setup.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from setuptools import setup
|
||||
|
||||
package_name = 'drone_status'
|
||||
|
||||
setup(
|
||||
name=package_name,
|
||||
version='0.0.0',
|
||||
packages=[package_name],
|
||||
data_files=[
|
||||
('share/ament_index/resource_index/packages',
|
||||
['resource/' + package_name]),
|
||||
('share/' + package_name, ['package.xml']),
|
||||
],
|
||||
install_requires=['setuptools'],
|
||||
zip_safe=True,
|
||||
maintainer='ubuntu',
|
||||
maintainer_email='semmer99@gmail.com',
|
||||
description='TODO: Package description',
|
||||
license='TODO: License declaration',
|
||||
tests_require=['pytest'],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
],
|
||||
},
|
||||
)
|
||||
23
src/drone_status/test/test_copyright.py
Normal file
23
src/drone_status/test/test_copyright.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_copyright.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.copyright
|
||||
@pytest.mark.linter
|
||||
def test_copyright():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found errors'
|
||||
25
src/drone_status/test/test_flake8.py
Normal file
25
src/drone_status/test/test_flake8.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_flake8.main import main_with_errors
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.flake8
|
||||
@pytest.mark.linter
|
||||
def test_flake8():
|
||||
rc, errors = main_with_errors(argv=[])
|
||||
assert rc == 0, \
|
||||
'Found %d code style errors / warnings:\n' % len(errors) + \
|
||||
'\n'.join(errors)
|
||||
23
src/drone_status/test/test_pep257.py
Normal file
23
src/drone_status/test/test_pep257.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_pep257.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.linter
|
||||
@pytest.mark.pep257
|
||||
def test_pep257():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found code style errors / warnings'
|
||||
58
src/height/CMakeLists.txt
Normal file
58
src/height/CMakeLists.txt
Normal file
@@ -0,0 +1,58 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(height)
|
||||
|
||||
# Default to C99
|
||||
if(NOT CMAKE_C_STANDARD)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
endif()
|
||||
|
||||
# Default to C++14
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# find dependencies
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(TerabeeApi REQUIRED)
|
||||
find_package(rosidl_default_generators REQUIRED)
|
||||
find_package(height REQUIRED)
|
||||
|
||||
rosidl_generate_interfaces(${PROJECT_NAME}
|
||||
"msg/HeightData.msg"
|
||||
)
|
||||
|
||||
add_executable(height_reader src/height_reader.cpp)
|
||||
target_include_directories(height_reader PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
target_link_libraries(height_reader ${TerabeeApi_LIBRARIES})
|
||||
target_include_directories(height_reader PUBLIC ${TerabeeApi_INCLUDE_DIRS})
|
||||
|
||||
ament_target_dependencies(
|
||||
height_reader
|
||||
rclcpp
|
||||
TerabeeApi
|
||||
height
|
||||
)
|
||||
|
||||
install(TARGETS height_reader
|
||||
DESTINATION lib/${PROJECT_NAME})
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
# the following line skips the linter which checks for copyrights
|
||||
# uncomment the line when a copyright and license is not present in all source files
|
||||
#set(ament_cmake_copyright_FOUND TRUE)
|
||||
# the following line skips cpplint (only works in a git repo)
|
||||
# uncomment the line when this package is not in a git repo
|
||||
#set(ament_cmake_cpplint_FOUND TRUE)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
endif()
|
||||
|
||||
ament_package()
|
||||
2
src/height/msg/HeightData.msg
Normal file
2
src/height/msg/HeightData.msg
Normal file
@@ -0,0 +1,2 @@
|
||||
float32[4] heights
|
||||
float32 min_height
|
||||
27
src/height/package.xml
Normal file
27
src/height/package.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>height</name>
|
||||
<version>0.0.0</version>
|
||||
<description>package to read Terabee node</description>
|
||||
<maintainer email="semmer99@gmail.com">ubuntu</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
<build_depend>rosidl_default_generators</build_depend>
|
||||
<exec_depend>rosidl_default_runtime</exec_depend>
|
||||
<member_of_group>rosidl_interface_packages</member_of_group>
|
||||
|
||||
<depend>rclcpp</depend>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<build_depend>TerabeeApi</build_depend>
|
||||
<exec_depend>TerabeeApi</exec_depend>
|
||||
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
101
src/height/src/height_reader.cpp
Normal file
101
src/height/src/height_reader.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @file height_reader.cpp
|
||||
* @author Sem van der Hoeven (sem.hoeven@gmail.com)
|
||||
* @brief Uses the Terabee API to read the Terabee Evo Mini
|
||||
* height sensor data and publishes it on a /drone/height topic
|
||||
*/
|
||||
#include <chrono>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "height/msg/height_data.hpp"
|
||||
|
||||
#include <terabee/ITerarangerFactory.hpp>
|
||||
#include <terabee/ITerarangerEvoMini.hpp>
|
||||
#include <terabee/DistanceData.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using terabee::DistanceData;
|
||||
using terabee::ITerarangerEvoMini;
|
||||
|
||||
class HeightReader : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
HeightReader() : rclcpp::Node("height_reader")
|
||||
{
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor = rcl_interfaces::msg::ParameterDescriptor{};
|
||||
descriptor.description = "serial port for the USB port of the height sensor";
|
||||
|
||||
this->declare_parameter("height_serial_port", "/dev/ttyACM0", descriptor);
|
||||
|
||||
factory = terabee::ITerarangerFactory::getFactory();
|
||||
evo_mini = factory->createTerarangerEvoMini(this->get_parameter("height_serial_port").as_string());
|
||||
|
||||
if (!evo_mini)
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to create Evo Mini!");
|
||||
return;
|
||||
}
|
||||
|
||||
evo_mini->setPixelMode(ITerarangerEvoMini::Px4Mode);
|
||||
|
||||
if (!evo_mini->initialize())
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to initialize evo mini!");
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "Succesfully initialized Evo mini!");
|
||||
|
||||
timer_ = this->create_wall_timer(500ms, std::bind(&HeightReader::read_height, this));
|
||||
publisher_ = this->create_publisher<height::msg::HeightData>("drone/height", 10);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief reads the height value from the Terabee Evo Mini sensor and publishes a
|
||||
*
|
||||
*/
|
||||
void read_height()
|
||||
{
|
||||
auto msg = height::msg::HeightData();
|
||||
|
||||
// high initial minimal value
|
||||
float min = 255;
|
||||
terabee::DistanceData distance_data = evo_mini->getDistance();
|
||||
// add readings and calculate mimimum value
|
||||
for (size_t i = 0; i < distance_data.size(); i++)
|
||||
{
|
||||
msg.heights[i] = distance_data.distance[i];
|
||||
if (distance_data.distance[i] < min && distance_data.distance[i] >= 0)
|
||||
{
|
||||
min = distance_data.distance[i];
|
||||
}
|
||||
}
|
||||
// add minimum value and publish message
|
||||
msg.min_height = min;
|
||||
publisher_->publish(msg);
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "publishing message with min distance %f", msg.min_height);
|
||||
}
|
||||
|
||||
// timer for publishing height readings
|
||||
rclcpp::TimerBase::SharedPtr timer_;
|
||||
// publisher for height readings
|
||||
rclcpp::Publisher<height::msg::HeightData>::SharedPtr publisher_;
|
||||
|
||||
// factory for height sensor
|
||||
std::unique_ptr<terabee::ITerarangerFactory> factory;
|
||||
// height sensor object pointer
|
||||
std::unique_ptr<terabee::ITerarangerEvoMini> evo_mini;
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
rclcpp::init(argc, argv);
|
||||
rclcpp::spin(std::make_shared<HeightReader>());
|
||||
rclcpp::shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
71
src/object_detection/CMakeLists.txt
Normal file
71
src/object_detection/CMakeLists.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(object_detection)
|
||||
|
||||
# Default to C99
|
||||
if(NOT CMAKE_C_STANDARD)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
endif()
|
||||
|
||||
# Default to C++14
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# find dependencies
|
||||
find_package(ament_cmake REQUIRED)
|
||||
# uncomment the following section in order to fill in
|
||||
# further dependencies manually.
|
||||
# find_package(<dependency> REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(TerabeeApi REQUIRED)
|
||||
find_package(rosidl_default_generators REQUIRED)
|
||||
find_package(object_detection REQUIRED)
|
||||
|
||||
rosidl_generate_interfaces(${PROJECT_NAME}
|
||||
"msg/LidarReading.msg"
|
||||
"msg/MultiflexReading.msg"
|
||||
)
|
||||
|
||||
add_executable(lidar_reader src/lidar_reader.cpp)
|
||||
ament_target_dependencies(lidar_reader rclcpp
|
||||
object_detection
|
||||
)
|
||||
|
||||
target_link_libraries(lidar_reader ${TerabeeApi_LIBRARIES})
|
||||
target_include_directories(lidar_reader PUBLIC ${TerabeeApi_INCLUDE_DIRS})
|
||||
|
||||
add_executable(multiflex_reader src/multiflex_reader.cpp)
|
||||
ament_target_dependencies(multiflex_reader rclcpp
|
||||
object_detection
|
||||
)
|
||||
|
||||
target_link_libraries(multiflex_reader ${TerabeeApi_LIBRARIES})
|
||||
target_include_directories(multiflex_reader PUBLIC ${TerabeeApi_INCLUDE_DIRS})
|
||||
|
||||
install(TARGETS
|
||||
lidar_reader
|
||||
multiflex_reader
|
||||
DESTINATION lib/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY launch
|
||||
DESTINATION share/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
# the following line skips the linter which checks for copyrights
|
||||
# uncomment the line when a copyright and license is not present in all source files
|
||||
#set(ament_cmake_copyright_FOUND TRUE)
|
||||
# the following line skips cpplint (only works in a git repo)
|
||||
# uncomment the line when this package is not in a git repo
|
||||
#set(ament_cmake_cpplint_FOUND TRUE)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
endif()
|
||||
|
||||
ament_package()
|
||||
23
src/object_detection/launch/object_detection_launch_both.py
Normal file
23
src/object_detection/launch/object_detection_launch_both.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from launch import LaunchDescription
|
||||
from launch_ros.actions import Node
|
||||
|
||||
def generate_launch_description():
|
||||
return LaunchDescription([
|
||||
Node(
|
||||
package="object_detection",
|
||||
executable="multiflex_reader",
|
||||
name="multiflex_reader",
|
||||
parameters=[
|
||||
{"multiflex_serial_port": "/dev/ttyACM0"}
|
||||
]
|
||||
),
|
||||
Node(
|
||||
package="object_detection",
|
||||
executable="lidar_reader",
|
||||
name="lidar_reader",
|
||||
parameters=[
|
||||
{"lidar_serial_port": "/dev/ttyUSB0"} # TODO test
|
||||
]
|
||||
)
|
||||
|
||||
])
|
||||
@@ -0,0 +1,15 @@
|
||||
from launch import LaunchDescription
|
||||
from launch_ros.actions import Node
|
||||
|
||||
def generate_launch_description():
|
||||
return LaunchDescription([
|
||||
Node(
|
||||
package="object_detection",
|
||||
executable="multiflex_reader",
|
||||
name="multiflex_reader",
|
||||
parameters=[
|
||||
{"multiflex_serial_port": "/dev/ttyACM0"}
|
||||
]
|
||||
)
|
||||
|
||||
])
|
||||
6
src/object_detection/msg/LidarReading.msg
Normal file
6
src/object_detection/msg/LidarReading.msg
Normal file
@@ -0,0 +1,6 @@
|
||||
float32 sensor_1
|
||||
float32 sensor_2
|
||||
float32 sensor_3
|
||||
float32 sensor_4
|
||||
float32[] imu_data
|
||||
|
||||
1
src/object_detection/msg/MultiflexReading.msg
Normal file
1
src/object_detection/msg/MultiflexReading.msg
Normal file
@@ -0,0 +1 @@
|
||||
float32[6] distance_data
|
||||
27
src/object_detection/package.xml
Normal file
27
src/object_detection/package.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>object_detection</name>
|
||||
<version>0.0.0</version>
|
||||
<description>Package to read the TeraBee lidar and multiflex sensors</description>
|
||||
<maintainer email="semmer99@gmail.com">sem</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
<build_depend>rosidl_default_generators</build_depend>
|
||||
<exec_depend>rosidl_default_runtime</exec_depend>
|
||||
<member_of_group>rosidl_interface_packages</member_of_group>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<build_depend>rclcpp</build_depend>
|
||||
<build_depend>TerabeeApi</build_depend>
|
||||
|
||||
<exec_depend>TerabeeApi</exec_depend>
|
||||
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
94
src/object_detection/src/lidar_reader.cpp
Normal file
94
src/object_detection/src/lidar_reader.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <chrono>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "object_detection/msg/lidar_reading.hpp"
|
||||
|
||||
#include <terabee/ITerarangerFactory.hpp>
|
||||
#include <terabee/ITerarangerTowerEvo.hpp>
|
||||
#include <terabee/TowerDistanceData.hpp>
|
||||
#include <terabee/ImuData.hpp>
|
||||
|
||||
using terabee::ImuData;
|
||||
using terabee::ITerarangerTowerEvo;
|
||||
using terabee::TowerDistanceData;
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class LidarReader : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
LidarReader()
|
||||
: Node("lidar_reader")
|
||||
{
|
||||
// get serial port of sensor through parameter
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor = rcl_interfaces::msg::ParameterDescriptor{};
|
||||
descriptor.description = "serial port for the USB port of the LIDAR";
|
||||
this->declare_parameter("lidar_serial_port", "/dev/ttyACM0", descriptor);
|
||||
|
||||
// create publisher and bind timer to publish function
|
||||
publisher_ = this->create_publisher<object_detection::msg::LidarReading>("drone/object_detection", 10);
|
||||
timer_ = this->create_wall_timer(500ms, std::bind(&LidarReader::read_lidar_data, this));
|
||||
|
||||
factory = terabee::ITerarangerFactory::getFactory();
|
||||
tower = factory->createTerarangerTowerEvo(this->get_parameter("lidar_serial_port").as_string());
|
||||
|
||||
if (!tower) // check if the object could be created
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to create TerarangerTowerEvo");
|
||||
return;
|
||||
}
|
||||
|
||||
// set lidar to measure including IMU
|
||||
tower->setImuMode(ITerarangerTowerEvo::QuaternionLinearAcc);
|
||||
|
||||
if (!tower->initialize()) // check if communication with the sensor works
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to initialize TerarangerTowerEvo");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// publisher for lidar data
|
||||
rclcpp::Publisher<object_detection::msg::LidarReading>::SharedPtr publisher_;
|
||||
// timer for publishing readings
|
||||
rclcpp::TimerBase::SharedPtr timer_;
|
||||
|
||||
// terabee tower evo variables
|
||||
std::unique_ptr<terabee::ITerarangerTowerEvo> tower;
|
||||
std::unique_ptr<terabee::ITerarangerFactory> factory;
|
||||
|
||||
/**
|
||||
* @brief Reads the data from the LIDAR distance modules and the IMU, and publishes it onto the drone/object_detection topic
|
||||
*
|
||||
*/
|
||||
void read_lidar_data()
|
||||
{
|
||||
auto msg = object_detection::msg::LidarReading();
|
||||
|
||||
// read distance data from all sensors
|
||||
msg.sensor_1 = tower->getDistance().distance.at(0);
|
||||
msg.sensor_2 = tower->getDistance().distance.at(2);
|
||||
msg.sensor_3 = tower->getDistance().distance.at(4);
|
||||
msg.sensor_4 = tower->getDistance().distance.at(6);
|
||||
|
||||
// read data from built-in IMU
|
||||
ImuData imu_data = tower->getImuData();
|
||||
for (size_t i = 0; i < imu_data.data.size(); i++)
|
||||
{
|
||||
msg.imu_data.push_back(imu_data.data[i]);
|
||||
}
|
||||
|
||||
// publish message
|
||||
publisher_->publish(msg);
|
||||
RCLCPP_INFO(this->get_logger(), "Publishing message");
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
rclcpp::init(argc, argv);
|
||||
rclcpp::spin(std::make_shared<LidarReader>());
|
||||
rclcpp::shutdown();
|
||||
return 0;
|
||||
}
|
||||
92
src/object_detection/src/multiflex_reader.cpp
Normal file
92
src/object_detection/src/multiflex_reader.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#include <chrono>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "object_detection/msg/multiflex_reading.hpp"
|
||||
|
||||
#include <terabee/ITerarangerFactory.hpp>
|
||||
#include <terabee/ITerarangerMultiflex.hpp>
|
||||
#include <terabee/DistanceData.hpp>
|
||||
|
||||
// #include <iostream>
|
||||
|
||||
using terabee::DistanceData;
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class MultiflexReader : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
MultiflexReader()
|
||||
: Node("multiflex_reader")
|
||||
{
|
||||
// get serial port of sensor through parameter
|
||||
rcl_interfaces::msg::ParameterDescriptor serial_port_descriptor = rcl_interfaces::msg::ParameterDescriptor{};
|
||||
serial_port_descriptor.description = "Serial port of the USB port that the multiflex PCB is connected to.";
|
||||
this->declare_parameter("multiflex_serial_port", "/dev/ttyACM0", serial_port_descriptor);
|
||||
|
||||
// create the sensor object
|
||||
factory = terabee::ITerarangerFactory::getFactory();
|
||||
multiflex = factory->createTerarangerMultiflex(this->get_parameter("multiflex_serial_port").as_string());
|
||||
|
||||
if (!multiflex) // check if the object can be created
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to create multiflex");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!multiflex->initialize()) // check if communication with the sensor works
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to initialize multiflex");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!multiflex->configureNumberOfSensors(0x7)) // check if all 6 distance sensors work
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to set the number of sensors to 3!");
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "Multiflex initialized");
|
||||
|
||||
publisher_ = this->create_publisher<object_detection::msg::MultiflexReading>("drone/object_detection", 10);
|
||||
timer_ = this->create_wall_timer(500ms, std::bind(&MultiflexReader::read_multiflex_data, this));
|
||||
}
|
||||
|
||||
private:
|
||||
// factory and object for multiflex sensor
|
||||
std::unique_ptr<terabee::ITerarangerFactory> factory;
|
||||
std::unique_ptr<terabee::ITerarangerMultiflex> multiflex;
|
||||
|
||||
// timer and publisher for publishing message onto topic
|
||||
rclcpp::TimerBase::SharedPtr timer_;
|
||||
rclcpp::Publisher<object_detection::msg::MultiflexReading>::SharedPtr publisher_;
|
||||
|
||||
/**
|
||||
* @brief Reads distance data from the sensor and publishes it onto the drone/object_detection topic
|
||||
*
|
||||
*/
|
||||
void read_multiflex_data()
|
||||
{
|
||||
// get distance reading
|
||||
terabee::DistanceData data = multiflex->getDistance();
|
||||
|
||||
// populate message with readings
|
||||
auto msg = object_detection::msg::MultiflexReading();
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "distance %f", data.distance[i]);
|
||||
// msg.distance_data[i] = data.distance[i];
|
||||
}
|
||||
|
||||
// publish message
|
||||
publisher_->publish(msg);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
rclcpp::init(argc, argv);
|
||||
rclcpp::spin(std::make_shared<MultiflexReader>());
|
||||
rclcpp::shutdown();
|
||||
return 0;
|
||||
}
|
||||
75
src/px4_connection/CMakeLists.txt
Normal file
75
src/px4_connection/CMakeLists.txt
Normal file
@@ -0,0 +1,75 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(px4_connection)
|
||||
|
||||
# Default to C99
|
||||
if(NOT CMAKE_C_STANDARD)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
endif()
|
||||
|
||||
# Default to C++14
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# find dependencies
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(px4_ros_com REQUIRED)
|
||||
find_package(px4_msgs REQUIRED)
|
||||
find_package(drone_services REQUIRED)
|
||||
find_package(std_srvs REQUIRED)
|
||||
|
||||
include_directories(include)
|
||||
add_executable(heartbeat src/heartbeat.cpp)
|
||||
ament_target_dependencies(
|
||||
heartbeat
|
||||
rclcpp
|
||||
drone_services
|
||||
px4_ros_com
|
||||
px4_msgs
|
||||
drone_services
|
||||
)
|
||||
|
||||
add_executable(px4_controller src/px4_controller.cpp)
|
||||
ament_target_dependencies(
|
||||
px4_controller
|
||||
rclcpp
|
||||
px4_ros_com
|
||||
px4_msgs
|
||||
drone_services
|
||||
std_srvs
|
||||
)
|
||||
|
||||
target_include_directories(heartbeat PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
target_include_directories(px4_controller PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
install(TARGETS heartbeat px4_controller
|
||||
DESTINATION lib/${PROJECT_NAME})
|
||||
|
||||
install(
|
||||
DIRECTORY launch
|
||||
DESTINATION share/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
|
||||
# the following line skips the linter which checks for copyrights
|
||||
# uncomment the line when a copyright and license is not present in all source files
|
||||
# set(ament_cmake_copyright_FOUND TRUE)
|
||||
# the following line skips cpplint (only works in a git repo)
|
||||
# uncomment the line when this package is not in a git repo
|
||||
# set(ament_cmake_cpplint_FOUND TRUE)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
endif()
|
||||
|
||||
ament_package()
|
||||
8
src/px4_connection/include/attitude_msg_code.hpp
Normal file
8
src/px4_connection/include/attitude_msg_code.hpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef ATTITUDE_MSG_CODE_HPP
|
||||
#define ATTITUDE_MSG_CODE_HPP
|
||||
|
||||
#define ATTITUDE_STATUS_OK 0
|
||||
#define ATTITUDE_STATUS_ERROR 1
|
||||
|
||||
|
||||
#endif
|
||||
20
src/px4_connection/include/drone_control_modes.h
Normal file
20
src/px4_connection/include/drone_control_modes.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef DRONE_CONTROL_MODES_H
|
||||
#define DRONE_CONTROL_MODES_H
|
||||
|
||||
#define CONTROL_MODE_ATTITUDE 1
|
||||
#define CONTROL_MODE_VELOCITY 2
|
||||
#define CONTROL_MODE_POSITION 3
|
||||
|
||||
#define CONTROL_MODE_MIN CONTROL_MODE_ATTITUDE
|
||||
#define CONTROL_MODE_MAX CONTROL_MODE_POSITION
|
||||
|
||||
#define CONTROL_ACTUATOR_POS 0
|
||||
#define CONTROL_BODY_RATE_POS 1
|
||||
#define CONTROL_ATTITUDE_POS 2
|
||||
#define CONTROL_ACCELERATION_POS 3
|
||||
#define CONTROL_VELOCITY_POS 4
|
||||
#define CONTROL_POSITION_POS 5
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
15
src/px4_connection/launch/px4_controller_heardbeat_launch.py
Normal file
15
src/px4_connection/launch/px4_controller_heardbeat_launch.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from launch import LaunchDescription
|
||||
from launch_ros.actions import Node
|
||||
|
||||
def generate_launch_description():
|
||||
return LaunchDescription([
|
||||
Node(
|
||||
package="px4_connection",
|
||||
executable="heartbeat"
|
||||
),
|
||||
Node(
|
||||
package="px4_connection",
|
||||
executable="px4_controller"
|
||||
)
|
||||
|
||||
])
|
||||
24
src/px4_connection/package.xml
Normal file
24
src/px4_connection/package.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>px4_connection</name>
|
||||
<version>0.0.0</version>
|
||||
<description>Package to communicate with PX4 through the XRCE-DDS bridge</description>
|
||||
<maintainer email="semmer99@gmail.com">ubuntu</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
|
||||
<depend>rclcpp</depend>
|
||||
<depend>px4_ros_com</depend>
|
||||
<depend>px4_msgs</depend>
|
||||
<depend>drone_services</depend>
|
||||
<depend>std_srvs</depend>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
130
src/px4_connection/src/heartbeat.cpp
Normal file
130
src/px4_connection/src/heartbeat.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
|
||||
/**
|
||||
* @file heartbeat.cpp
|
||||
* @author Sem van der Hoeven (sem.hoeven@gmail.com)
|
||||
* @brief Heartbeat node that keeps the connection between the flight computer
|
||||
* and PX4 flight controller alive by sending OffboardControl messages
|
||||
*/
|
||||
#include <chrono>
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include <px4_msgs/msg/offboard_control_mode.hpp>
|
||||
#include <drone_services/srv/set_vehicle_control.hpp>
|
||||
#include <drone_services/msg/drone_control_mode.hpp>
|
||||
|
||||
#include "drone_control_modes.h"
|
||||
|
||||
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class HeartBeat : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
HeartBeat() : Node("heartbeat")
|
||||
{
|
||||
vehicle_control_mode_service_ = this->create_service<drone_services::srv::SetVehicleControl>("/drone/set_vehicle_control", std::bind(&HeartBeat::handle_vehicle_control_change, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
RCLCPP_INFO(this->get_logger(), "initialized service /drone/set_vehicle_control");
|
||||
// create a publisher on the drone control mode topic
|
||||
drone_control_mode_publisher_ = this->create_publisher<drone_services::msg::DroneControlMode>("/drone/control_mode", 10);
|
||||
// create a publisher on the offboard control mode topic
|
||||
offboard_control_mode_publisher_ = this->create_publisher<px4_msgs::msg::OffboardControlMode>("/fmu/in/offboard_control_mode", 10);
|
||||
// create timer to send heartbeat messages (offboard control) every 100ms
|
||||
timer_ = this->create_wall_timer(100ms, std::bind(&HeartBeat::send_heartbeat, this));
|
||||
start_time = this->get_clock()->now().seconds();
|
||||
RCLCPP_INFO(this->get_logger(), "done initializing at %d seconds. Sending heartbeat...", start_time);
|
||||
}
|
||||
|
||||
private:
|
||||
// publisher for offboard control mode messages
|
||||
rclcpp::Publisher<px4_msgs::msg::OffboardControlMode>::SharedPtr offboard_control_mode_publisher_;
|
||||
// publisher for the control mode of the drone
|
||||
rclcpp::Publisher<drone_services::msg::DroneControlMode>::SharedPtr drone_control_mode_publisher_;
|
||||
// timer for sending the heartbeat
|
||||
rclcpp::TimerBase::SharedPtr timer_;
|
||||
// service to change vehicle_mode
|
||||
rclcpp::Service<drone_services::srv::SetVehicleControl>::SharedPtr vehicle_control_mode_service_;
|
||||
|
||||
// start time of node in seconds
|
||||
double start_time;
|
||||
// which level of control is needed, only attitude control by default
|
||||
int control_mode = 1 << CONTROL_ATTITUDE_POS;
|
||||
/**
|
||||
* @brief Publish offboard control mode messages as a heartbeat.
|
||||
* Only the attitude is enabled, because that is how the drone will be controlled.
|
||||
*
|
||||
*/
|
||||
void send_heartbeat()
|
||||
{
|
||||
auto msg = px4_msgs::msg::OffboardControlMode();
|
||||
|
||||
msg.position = (this->control_mode >> CONTROL_POSITION_POS) & 1 ? true : false;
|
||||
msg.velocity = (this->control_mode >> CONTROL_VELOCITY_POS) & 1 ? true : false;
|
||||
msg.acceleration = (this->control_mode >> CONTROL_ACCELERATION_POS) & 1 ? true : false;
|
||||
msg.attitude = (this->control_mode >> CONTROL_ATTITUDE_POS) & 1 ? true : false;
|
||||
msg.body_rate = (this->control_mode >> CONTROL_BODY_RATE_POS) & 1 ? true : false;
|
||||
msg.actuator = (this->control_mode >> CONTROL_ACTUATOR_POS) & 1 ? true : false;
|
||||
// get timestamp and publish message
|
||||
msg.timestamp = this->get_clock()->now().nanoseconds() / 1000;
|
||||
offboard_control_mode_publisher_->publish(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish the current control mode of the drone onto the 'drone/control_mode' topic
|
||||
*
|
||||
*/
|
||||
void publish_new_control_mode()
|
||||
{
|
||||
auto msg = drone_services::msg::DroneControlMode();
|
||||
if (this->control_mode & (1 << CONTROL_ATTITUDE_POS))
|
||||
{
|
||||
msg.control_mode = CONTROL_MODE_ATTITUDE;
|
||||
RCLCPP_INFO(this->get_logger(), "set control mode to attitude");
|
||||
}
|
||||
else if (this->control_mode & (1 << CONTROL_VELOCITY_POS))
|
||||
{
|
||||
msg.control_mode = CONTROL_MODE_VELOCITY;
|
||||
RCLCPP_INFO(this->get_logger(), "set control mode to velocity");
|
||||
}
|
||||
else if (this->control_mode & (1 << CONTROL_POSITION_POS))
|
||||
{
|
||||
msg.control_mode = CONTROL_MODE_POSITION;
|
||||
RCLCPP_INFO(this->get_logger(), "set control mode to position");
|
||||
}
|
||||
RCLCPP_INFO(this->get_logger(), "publishing new control mode %d", msg.control_mode);
|
||||
drone_control_mode_publisher_->publish(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle a request to change the vehicle control mode
|
||||
*
|
||||
* @param request_header the header of the service request
|
||||
* @param request the request that was sent to the service
|
||||
* @param response the reponse that the service sends back to the client.
|
||||
*/
|
||||
|
||||
void handle_vehicle_control_change(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<drone_services::srv::SetVehicleControl::Request> request,
|
||||
const std::shared_ptr<drone_services::srv::SetVehicleControl::Response> response)
|
||||
{
|
||||
if (request->control < 0 || request->control > (1 << CONTROL_POSITION_POS))
|
||||
{
|
||||
response->success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->control_mode = request->control;
|
||||
RCLCPP_INFO(this->get_logger(), "set control mode to %d", this->control_mode);
|
||||
publish_new_control_mode();
|
||||
response->success = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
rclcpp::init(argc, argv);
|
||||
rclcpp::spin(std::make_shared<HeartBeat>());
|
||||
rclcpp::shutdown();
|
||||
return 0;
|
||||
}
|
||||
542
src/px4_connection/src/px4_controller.cpp
Normal file
542
src/px4_connection/src/px4_controller.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
/**
|
||||
* @file px4_controller.cpp
|
||||
* @author Sem van der Hoeven (sem.hoeven@gmail.com)
|
||||
* @brief Controller node to contol the PX4 using attitude or trajectory setpoints.
|
||||
* It subscribes to the /drone/set_attitude topic to receive control commands
|
||||
*/
|
||||
|
||||
#include <chrono>
|
||||
#include <math.h>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include <px4_msgs/msg/vehicle_attitude_setpoint.hpp>
|
||||
#include <px4_msgs/msg/trajectory_setpoint.hpp>
|
||||
#include <px4_msgs/msg/vehicle_command.hpp>
|
||||
#include <px4_msgs/msg/vehicle_control_mode.hpp>
|
||||
#include <px4_msgs/msg/vehicle_attitude.hpp>
|
||||
#include <px4_msgs/msg/vehicle_local_position.hpp>
|
||||
|
||||
#include <drone_services/srv/set_attitude.hpp>
|
||||
#include <drone_services/srv/set_trajectory.hpp>
|
||||
#include <drone_services/srv/arm_drone.hpp>
|
||||
#include <drone_services/srv/disarm_drone.hpp>
|
||||
#include <drone_services/msg/drone_control_mode.hpp>
|
||||
#include <drone_services/msg/drone_arm_status.hpp>
|
||||
|
||||
#include <std_srvs/srv/empty.hpp>
|
||||
|
||||
#include "drone_control_modes.h"
|
||||
|
||||
#define DEFAULT_YAW_SPEED 0.6 // default turning speed in radians per second
|
||||
#define D_SPEED(x) -x - 9.81 // a speed up of x m/s has to be ajusted for the earths gravity
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class PX4Controller : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
PX4Controller() : Node("px4_controller")
|
||||
{
|
||||
|
||||
rmw_qos_profile_t qos_profile = rmw_qos_profile_sensor_data;
|
||||
auto qos = rclcpp::QoS(rclcpp::QoSInitialization(qos_profile.history, 5), qos_profile);
|
||||
|
||||
// create a publisher on the vehicle attitude setpoint topic
|
||||
vehicle_setpoint_publisher_ = this->create_publisher<px4_msgs::msg::VehicleAttitudeSetpoint>("/fmu/in/vehicle_attitude_setpoint", 10);
|
||||
vehicle_command_publisher_ = this->create_publisher<px4_msgs::msg::VehicleCommand>("/fmu/in/vehicle_command", 10);
|
||||
trajectory_setpoint_publisher = this->create_publisher<px4_msgs::msg::TrajectorySetpoint>("/fmu/in/trajectory_setpoint", 10);
|
||||
arm_status_publisher_ = this->create_publisher<drone_services::msg::DroneArmStatus>("/drone/arm_status", 10);
|
||||
// offboard_control_mode_publisher_ = this->create_publisher<px4_msgs::msg::OffboardControlMode>("/fmu/in/offboard_control_mode", 10);
|
||||
|
||||
vehicle_attitude_subscription_ = this->create_subscription<px4_msgs::msg::VehicleAttitude>("/fmu/out/vehicle_attitude", qos, std::bind(&PX4Controller::on_attitude_receive, this, std::placeholders::_1));
|
||||
vehicle_local_position_subscription_ = this->create_subscription<px4_msgs::msg::VehicleLocalPosition>("/fmu/out/vehicle_local_position", qos, std::bind(&PX4Controller::on_local_position_receive, this, std::placeholders::_1));
|
||||
control_mode_subscription_ = this->create_subscription<drone_services::msg::DroneControlMode>("/drone/control_mode", qos, std::bind(&PX4Controller::on_control_mode_receive, this, std::placeholders::_1));
|
||||
|
||||
|
||||
set_attitude_service_ = this->create_service<drone_services::srv::SetAttitude>("/drone/set_attitude", std::bind(&PX4Controller::handle_attitude_setpoint, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
set_trajectory_service_ = this->create_service<drone_services::srv::SetTrajectory>("/drone/set_trajectory", std::bind(&PX4Controller::handle_trajectory_setpoint, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
disarm_service_ = this->create_service<drone_services::srv::DisarmDrone>("/drone/disarm", std::bind(&PX4Controller::handle_disarm_request, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
arm_service_ = this->create_service<drone_services::srv::ArmDrone>("/drone/arm", std::bind(&PX4Controller::handle_arm_request, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
// create timer to send vehicle attitude setpoints every second
|
||||
timer_ = this->create_wall_timer(100ms, std::bind(&PX4Controller::send_setpoint, this));
|
||||
|
||||
start_time_ = this->get_clock()->now().seconds();
|
||||
RCLCPP_INFO(this->get_logger(), "finished initializing at %f seconds.", start_time_);
|
||||
}
|
||||
|
||||
private:
|
||||
rclcpp::Publisher<px4_msgs::msg::VehicleAttitudeSetpoint>::SharedPtr vehicle_setpoint_publisher_;
|
||||
rclcpp::Publisher<px4_msgs::msg::TrajectorySetpoint>::SharedPtr trajectory_setpoint_publisher;
|
||||
rclcpp::Publisher<px4_msgs::msg::VehicleCommand>::SharedPtr vehicle_command_publisher_;
|
||||
rclcpp::Publisher<drone_services::msg::DroneArmStatus>::SharedPtr arm_status_publisher_;
|
||||
|
||||
rclcpp::Subscription<px4_msgs::msg::VehicleAttitude>::SharedPtr vehicle_attitude_subscription_;
|
||||
rclcpp::Subscription<px4_msgs::msg::VehicleLocalPosition>::SharedPtr vehicle_local_position_subscription_;
|
||||
rclcpp::Subscription<drone_services::msg::DroneControlMode>::SharedPtr control_mode_subscription_;
|
||||
|
||||
rclcpp::Service<drone_services::srv::SetAttitude>::SharedPtr set_attitude_service_;
|
||||
rclcpp::Service<drone_services::srv::SetTrajectory>::SharedPtr set_trajectory_service_;
|
||||
rclcpp::Service<drone_services::srv::DisarmDrone>::SharedPtr disarm_service_;
|
||||
rclcpp::Service<drone_services::srv::ArmDrone>::SharedPtr arm_service_;
|
||||
|
||||
// rclcpp::Publisher<px4_msgs::msg::OffboardControlMode>::SharedPtr offboard_control_mode_publisher_;
|
||||
|
||||
rclcpp::TimerBase::SharedPtr timer_;
|
||||
double start_time_;
|
||||
bool has_sent_status = false;
|
||||
bool user_in_control = false; // if user has taken over control
|
||||
bool armed = false;
|
||||
bool has_swithed = false;
|
||||
int setpoint_count = 0;
|
||||
float thrust = 0.0;
|
||||
bool ready_to_fly = false;
|
||||
float cur_yaw = 0;
|
||||
bool new_setpoint = false; // for printing new q_d when a new setpoint has been received
|
||||
|
||||
float last_setpoint[3] = {0, 0, 0};
|
||||
float last_angle = 0; // angle in radians (-PI .. PI)
|
||||
float last_thrust = 0; // default 10% thrust for when the drone gets armed
|
||||
|
||||
float velocity[3] = {0, 0, 0};
|
||||
float position[3] = {0, 0, 0};
|
||||
|
||||
float base_q[4] = {0, 0, 0, 0};
|
||||
int base_q_amount = 0;
|
||||
|
||||
char current_control_mode = CONTROL_MODE_ATTITUDE; // start with attitude control
|
||||
|
||||
bool start_trajectory = false;
|
||||
const float omega = 0.3; // angular speed of the POLAR trajectory
|
||||
const float K = 0; // [m] gain that regulates the spiral pitch
|
||||
|
||||
float rho_0 = 0;
|
||||
float theta_0 = 0;
|
||||
const float p0_z = -0.0;
|
||||
float p0_x = rho_0 * cos(theta_0);
|
||||
float p0_y = rho_0 * sin(theta_0);
|
||||
float des_x = p0_x, des_y = p0_y, des_z = p0_z;
|
||||
float dot_des_x = 0.0, dot_des_y = 0.0;
|
||||
float gamma = M_PI_4;
|
||||
|
||||
float X;
|
||||
float Y;
|
||||
|
||||
float local_x = 0;
|
||||
float local_y = 0;
|
||||
|
||||
uint32_t discrete_time_index = 0;
|
||||
|
||||
// result quaternion
|
||||
std::array<float, 4> q = {0, 0, 0, 0};
|
||||
|
||||
void handle_attitude_setpoint(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<drone_services::srv::SetAttitude::Request> request,
|
||||
const std::shared_ptr<drone_services::srv::SetAttitude::Response> response)
|
||||
{
|
||||
if (armed)
|
||||
{
|
||||
if (request->yaw == 0 && request->pitch == 0 && request->roll == 0 && request->thrust == 0)
|
||||
{
|
||||
last_setpoint[0] = degrees_to_radians(request->yaw);
|
||||
last_setpoint[1] = degrees_to_radians(request->pitch);
|
||||
last_setpoint[2] = degrees_to_radians(request->roll);
|
||||
last_thrust = request->thrust;
|
||||
RCLCPP_INFO(this->get_logger(), "STOPPING MOTORS");
|
||||
}
|
||||
else
|
||||
{
|
||||
last_setpoint[0] += degrees_to_radians(request->yaw);
|
||||
last_setpoint[1] += degrees_to_radians(request->pitch);
|
||||
last_setpoint[2] += degrees_to_radians(request->roll);
|
||||
last_thrust += request->thrust;
|
||||
if (last_thrust > 1)
|
||||
last_thrust = 1;
|
||||
else if (last_thrust < 0)
|
||||
last_thrust = 0;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "got values: yaw:%f pitch:%f roll:%f thrust:%f", request->yaw, request->pitch, request->roll, request->thrust);
|
||||
RCLCPP_INFO(this->get_logger(), "New setpoint: yaw:%f pitch:%f roll:%f thrust:%f", last_setpoint[0], last_setpoint[1], last_setpoint[2], last_thrust);
|
||||
|
||||
response->success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_thrust = 0;
|
||||
last_setpoint[0] = 0;
|
||||
last_setpoint[1] = 0;
|
||||
last_setpoint[2] = 0;
|
||||
response->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_trajectory_setpoint(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<drone_services::srv::SetTrajectory::Request> request,
|
||||
const std::shared_ptr<drone_services::srv::SetTrajectory::Response> response)
|
||||
{
|
||||
if (!(request->control_mode == CONTROL_MODE_VELOCITY || request->control_mode == CONTROL_MODE_POSITION))
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "Got invalid trajectory control mode: %d", request->control_mode);
|
||||
response->success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "Got new trajectory setpoint with control mode: %d", request->control_mode);
|
||||
if (request->control_mode == CONTROL_MODE_VELOCITY)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
velocity[i] += request->values[i];
|
||||
}
|
||||
RCLCPP_INFO(this->get_logger(), "Got new velocity setpoint. %f %f %f", velocity[0], velocity[1], velocity[2]);
|
||||
}
|
||||
else if (request->control_mode == CONTROL_MODE_POSITION)
|
||||
{
|
||||
position[0] += request->values[0];
|
||||
position[1] += request->values[1];
|
||||
position[2] -= request->values[2]; // height is negative
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "Got new position setpoint: %f %f %f", position[0], position[1], position[2]);
|
||||
}
|
||||
|
||||
last_angle += request->yaw;
|
||||
new_setpoint = true;
|
||||
RCLCPP_INFO(this->get_logger(), "Yaw: %f", last_angle);
|
||||
response->success = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief disarms the drone when a call to the disarm service is made
|
||||
*
|
||||
* @param request_header the header for the service request
|
||||
* @param request the request (empty)
|
||||
* @param response the response (empty)
|
||||
*/
|
||||
void handle_disarm_request(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<drone_services::srv::DisarmDrone::Request> request,
|
||||
const std::shared_ptr<drone_services::srv::DisarmDrone::Response> response)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "Got disarm request...");
|
||||
|
||||
if (armed)
|
||||
{
|
||||
armed = false;
|
||||
user_in_control = false;
|
||||
publish_vehicle_command(px4_msgs::msg::VehicleCommand::VEHICLE_CMD_COMPONENT_ARM_DISARM, 0.0, 0);
|
||||
|
||||
auto msg = drone_services::msg::DroneArmStatus();
|
||||
msg.armed = false;
|
||||
arm_status_publisher_->publish(msg);
|
||||
|
||||
response->success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Got disarm request but drone was not armed!");
|
||||
response->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief arms the drone when a call to the arm service is made
|
||||
*
|
||||
* @param request_header the header for the service request
|
||||
* @param request the request (empty)
|
||||
* @param response the response (empty)
|
||||
*/
|
||||
void handle_arm_request(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<drone_services::srv::ArmDrone::Request> request,
|
||||
const std::shared_ptr<drone_services::srv::ArmDrone::Response> response)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "Got arm request...");
|
||||
|
||||
if (!armed)
|
||||
{
|
||||
this->publish_vehicle_command(px4_msgs::msg::VehicleCommand::VEHICLE_CMD_DO_SET_MODE, 1, 6);
|
||||
RCLCPP_INFO(this->get_logger(), "Set to offboard mode");
|
||||
// arm the drone
|
||||
this->publish_vehicle_command(px4_msgs::msg::VehicleCommand::VEHICLE_CMD_COMPONENT_ARM_DISARM, 1.0, 0);
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "Arm command sent");
|
||||
this->last_thrust = -0.1; // spin motors at 10% thrust
|
||||
armed = true;
|
||||
|
||||
auto msg = drone_services::msg::DroneArmStatus();
|
||||
msg.armed = true;
|
||||
arm_status_publisher_->publish(msg);
|
||||
|
||||
response->success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Arm request received but the drone is already armed!");
|
||||
response->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
void send_attitude_setpoint()
|
||||
{
|
||||
|
||||
// set message to enable attitude
|
||||
auto msg = px4_msgs::msg::VehicleAttitudeSetpoint();
|
||||
|
||||
// move up?
|
||||
msg.thrust_body[0] = 0; // north
|
||||
msg.thrust_body[1] = 0; // east
|
||||
msg.thrust_body[2] = -last_thrust;
|
||||
|
||||
calculate_quaternion(q, last_setpoint[0], last_setpoint[1], last_setpoint[2]);
|
||||
// set quaternion
|
||||
msg.q_d[0] = q.at(0);
|
||||
msg.q_d[1] = base_q[1] + q.at(1);
|
||||
msg.q_d[2] = base_q[2] + q.at(2);
|
||||
msg.q_d[3] = base_q[3] + q.at(3);
|
||||
|
||||
msg.yaw_sp_move_rate = 0;
|
||||
msg.reset_integral = false;
|
||||
msg.fw_control_yaw_wheel = false;
|
||||
|
||||
msg.timestamp = this->get_clock()->now().nanoseconds() / 1000;
|
||||
vehicle_setpoint_publisher_->publish(msg);
|
||||
}
|
||||
|
||||
void send_velocity_setpoint()
|
||||
{
|
||||
auto msg = px4_msgs::msg::TrajectorySetpoint();
|
||||
|
||||
msg.velocity[0] = velocity[0];
|
||||
msg.velocity[1] = velocity[1];
|
||||
msg.velocity[2] = -velocity[2];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
msg.position[i] = NAN;
|
||||
}
|
||||
|
||||
publish_trajectory_setpoint(msg);
|
||||
}
|
||||
|
||||
void send_position_setpoint()
|
||||
{
|
||||
auto msg = px4_msgs::msg::TrajectorySetpoint();
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "Sending position setpoint: %f %f %f", des_x, des_y, des_z);
|
||||
RCLCPP_INFO(this->get_logger(),"local position: %f %f", local_x, local_y);
|
||||
msg.position = {local_x, local_y, des_z};
|
||||
msg.velocity = {dot_des_x, dot_des_y, 0.0};
|
||||
msg.yaw = gamma; //-3.14; // [-PI:PI]
|
||||
|
||||
msg.timestamp = this->get_clock()->now().nanoseconds() / 1000;
|
||||
trajectory_setpoint_publisher->publish(msg);
|
||||
}
|
||||
|
||||
void publish_trajectory_setpoint(px4_msgs::msg::TrajectorySetpoint msg)
|
||||
{
|
||||
msg.yaw = last_angle;
|
||||
msg.yawspeed = DEFAULT_YAW_SPEED;
|
||||
msg.timestamp = this->get_clock()->now().nanoseconds() / 1000;
|
||||
trajectory_setpoint_publisher->publish(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send setpoints to PX4. First, 20 setpoints will be sent before offboard mode will be engaged and the drone will be armed.
|
||||
*
|
||||
*/
|
||||
void send_setpoint()
|
||||
{
|
||||
// the spiral, in polar coordinates (theta, rho), is given by
|
||||
// theta = theta_0 + omega*t
|
||||
// rho = rho_0 + K*theta
|
||||
float theta = theta_0 + omega * 0.1 * discrete_time_index;
|
||||
float rho = rho_0 + K * theta;
|
||||
|
||||
// from polar to cartesian coordinates
|
||||
des_x = rho * cos(theta);
|
||||
des_y = rho * sin(theta);
|
||||
des_z = position[2]; // the z position can be set to the received height
|
||||
|
||||
// velocity computation
|
||||
float dot_rho = K * omega;
|
||||
dot_des_x = dot_rho * cos(theta) - rho * sin(theta) * omega;
|
||||
dot_des_y = dot_rho * sin(theta) + rho * cos(theta) * omega;
|
||||
// desired heading direction
|
||||
gamma = atan2(dot_des_y, dot_des_x);
|
||||
|
||||
if (!user_in_control)
|
||||
{
|
||||
// RCLCPP_INFO(this->get_logger(), "Sending idle attitude setpoint");
|
||||
send_attitude_setpoint();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (current_control_mode == CONTROL_MODE_ATTITUDE)
|
||||
{
|
||||
// RCLCPP_INFO(this->get_logger(), "Sending attitude setpoint");
|
||||
send_attitude_setpoint();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!new_setpoint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (current_control_mode == CONTROL_MODE_VELOCITY)
|
||||
{
|
||||
// RCLCPP_INFO(this->get_logger(), "Sending velocity setpoint");
|
||||
send_velocity_setpoint();
|
||||
}
|
||||
else if (current_control_mode == CONTROL_MODE_POSITION)
|
||||
{
|
||||
// RCLCPP_INFO(this->get_logger(), "Sending position setpoint");
|
||||
send_position_setpoint();
|
||||
}
|
||||
new_setpoint = false;
|
||||
}
|
||||
}
|
||||
if (start_trajectory)
|
||||
{
|
||||
discrete_time_index++;
|
||||
}
|
||||
}
|
||||
|
||||
void on_attitude_receive(const px4_msgs::msg::VehicleAttitude::SharedPtr msg)
|
||||
{
|
||||
/*
|
||||
average q:
|
||||
- 0.7313786745071411
|
||||
- 0.005042835604399443
|
||||
- 0.0002370707516092807
|
||||
- 0.6819528937339783
|
||||
*/
|
||||
if (!armed)
|
||||
{
|
||||
if (base_q_amount > 2)
|
||||
{
|
||||
base_q[1] = (base_q[1] + msg->q[1]) / 2;
|
||||
base_q[2] = (base_q[2] + msg->q[2]) / 2;
|
||||
base_q[3] = (base_q[3] + msg->q[3]) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
base_q[1] = msg->q[1];
|
||||
base_q[2] = msg->q[2];
|
||||
base_q[3] = msg->q[3];
|
||||
base_q_amount++;
|
||||
}
|
||||
|
||||
// RCLCPP_INFO(this->get_logger(), "base_q: %f %f %f %f", base_q[0], base_q[1], base_q[2], base_q[3]);
|
||||
}
|
||||
}
|
||||
|
||||
void on_local_position_receive(const px4_msgs::msg::VehicleLocalPosition::SharedPtr msg)
|
||||
{
|
||||
// set start values to current position
|
||||
if (!user_in_control)
|
||||
{
|
||||
// https://www.math.usm.edu/lambers/mat169/fall09/lecture33.pdf
|
||||
rho_0 = pow(msg->x,2) + pow(msg->y,2);
|
||||
theta_0 = atan2(msg->y, msg->x);
|
||||
last_angle = msg->heading;
|
||||
|
||||
local_x = msg->x;
|
||||
local_y = msg->y;
|
||||
}
|
||||
X = msg->x;
|
||||
Y = msg->y;
|
||||
float Z = msg->z;
|
||||
if (!start_trajectory && (p0_x + 1.0 > X && p0_x - 1.0 < X) && (p0_y + 1.0 > Y && p0_y - 1.0 < Y) && (p0_z + 1.0 > Z && p0_z - 1.0 < Z))
|
||||
{
|
||||
start_trajectory = true;
|
||||
RCLCPP_INFO(this->get_logger(), "start trajectory");
|
||||
}
|
||||
}
|
||||
|
||||
void on_control_mode_receive(const drone_services::msg::DroneControlMode::SharedPtr msg)
|
||||
{
|
||||
if (msg->control_mode >= CONTROL_MODE_MIN && msg->control_mode <= CONTROL_MODE_MAX)
|
||||
{
|
||||
current_control_mode = msg->control_mode;
|
||||
RCLCPP_INFO(this->get_logger(), "Got valid control mode");
|
||||
user_in_control = true; // user has taken over control
|
||||
}
|
||||
else
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "Received invalid control mode %d", msg->control_mode);
|
||||
}
|
||||
RCLCPP_INFO(this->get_logger(), "Control mode set to %d", current_control_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Publish vehicle commands
|
||||
* @param command Command code (matches VehicleCommand and MAVLink MAV_CMD codes)
|
||||
* @param param1 Command parameter 1
|
||||
* @param param2 Command parameter 2
|
||||
*/
|
||||
void publish_vehicle_command(uint16_t command, float param1, float param2)
|
||||
{
|
||||
px4_msgs::msg::VehicleCommand msg{};
|
||||
msg.param1 = param1;
|
||||
msg.param2 = param2;
|
||||
msg.command = command;
|
||||
msg.target_system = 1;
|
||||
msg.target_component = 1;
|
||||
msg.source_system = 1;
|
||||
msg.source_component = 1;
|
||||
msg.from_external = true;
|
||||
msg.timestamp = this->get_clock()->now().nanoseconds() / 1000;
|
||||
vehicle_command_publisher_->publish(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief calculates a quaternion based on the given input values
|
||||
*
|
||||
* @param ptr array of result quaternion. Must be of size 4.
|
||||
* @param heading desired heading (yaw) in radians.
|
||||
* @param attitude desired attitude (pitch) in radians.
|
||||
* @param bank desired bank (roll) in radians.
|
||||
*/
|
||||
static void calculate_quaternion(std::array<float, 4> &ptr, float heading, float attitude, float bank)
|
||||
{
|
||||
|
||||
float c1 = cos(heading / 2);
|
||||
float c2 = cos(attitude / 2);
|
||||
float c3 = cos(bank / 2);
|
||||
float s1 = sin(heading / 2);
|
||||
float s2 = sin(attitude / 2);
|
||||
float s3 = sin(bank / 2);
|
||||
|
||||
float c1c2 = c1 * c2;
|
||||
float s1s2 = s1 * s2;
|
||||
|
||||
ptr.at(0) = c1c2 * c3 - s1s2 * s3; // w
|
||||
ptr.at(1) = c1c2 * s3 + s1s2 * c3; // x
|
||||
ptr.at(2) = s1 * c2 * c3 + c1 * s2 * s3; // y
|
||||
ptr.at(3) = c1 * s2 * c3 - s1 * c2 * s3; // z
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief converts degrees to radians
|
||||
*
|
||||
* @param deg angle in degrees
|
||||
* @return float new angle in radians
|
||||
*/
|
||||
static float degrees_to_radians(float deg)
|
||||
{
|
||||
return deg * (M_PI / 180.0);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
rclcpp::init(argc, argv);
|
||||
|
||||
rclcpp::Node::SharedPtr node = std::make_shared<PX4Controller>();
|
||||
rclcpp::spin(node);
|
||||
rclcpp::shutdown();
|
||||
return 0;
|
||||
}
|
||||
Submodule src/px4_msgs updated: 4db0a3f14e...ffc3a4cd57
21
src/relais_control/package.xml
Normal file
21
src/relais_control/package.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>relais_control</name>
|
||||
<version>0.0.0</version>
|
||||
<description>package to control the relais that enables Pixhawk RX and TX communication</description>
|
||||
<maintainer email="semmer99@gmail.com">ubuntu</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
<exec_depend>drone_services</exec_depend>
|
||||
|
||||
|
||||
<test_depend>ament_copyright</test_depend>
|
||||
<test_depend>ament_flake8</test_depend>
|
||||
<test_depend>ament_pep257</test_depend>
|
||||
<test_depend>python3-pytest</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_python</build_type>
|
||||
</export>
|
||||
</package>
|
||||
0
src/relais_control/relais_control/__init__.py
Normal file
0
src/relais_control/relais_control/__init__.py
Normal file
66
src/relais_control/relais_control/relais_controller.py
Normal file
66
src/relais_control/relais_control/relais_controller.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
try:
|
||||
import RPi.GPIO as GPIO
|
||||
except RuntimeError:
|
||||
print("Error importing RPi.GPIO! This is probably because you need superuser privileges. You can achieve this by using 'sudo' to run your script")
|
||||
|
||||
from drone_services.srv import ControlRelais
|
||||
class RelaisController(Node):
|
||||
def __init__(self):
|
||||
super().__init__('relais_controller')
|
||||
self.srv = self.create_service(ControlRelais, '/drone/control_relais', self.control_relais_callback)
|
||||
|
||||
self.relais1_pin = 17
|
||||
self.relais2_pin = 27
|
||||
self.init_gpio()
|
||||
self.turn_relais_on()
|
||||
|
||||
def init_gpio(self):
|
||||
GPIO.setwarnings(False)
|
||||
|
||||
self.get_logger().info(str(GPIO.RPI_INFO))
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
|
||||
GPIO.setup(self.relais1_pin, GPIO.OUT)
|
||||
GPIO.setup(self.relais2_pin, GPIO.OUT)
|
||||
self.get_logger().info("GPIO initialized")
|
||||
|
||||
def turn_relais_on(self):
|
||||
GPIO.output(self.relais1_pin, GPIO.HIGH)
|
||||
GPIO.output(self.relais2_pin, GPIO.HIGH)
|
||||
self.get_logger().info("Relais turned on")
|
||||
|
||||
def control_relais_callback(self, request, response):
|
||||
if request.relais1_on:
|
||||
GPIO.output(self.relais1_pin, GPIO.HIGH)
|
||||
response.bits = response.bits | 1
|
||||
else:
|
||||
GPIO.output(self.relais1_pin, GPIO.LOW)
|
||||
response.bits = response.bits & ~(1 << 0)
|
||||
if request.relais2_on:
|
||||
GPIO.output(self.relais2_pin, GPIO.HIGH)
|
||||
response.bits = response.bits | (1 << 1)
|
||||
else:
|
||||
GPIO.output(self.relais2_pin, GPIO.LOW)
|
||||
response.bits = response.bits & ~(1 << 1)
|
||||
return response
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
relais_controller = RelaisController()
|
||||
|
||||
rclpy.spin(relais_controller)
|
||||
|
||||
# Destroy the node explicitly
|
||||
# (optional - otherwise it will be done automatically
|
||||
# when the garbage collector destroys the node object)
|
||||
relais_controller.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
0
src/relais_control/resource/relais_control
Normal file
0
src/relais_control/resource/relais_control
Normal file
4
src/relais_control/setup.cfg
Normal file
4
src/relais_control/setup.cfg
Normal file
@@ -0,0 +1,4 @@
|
||||
[develop]
|
||||
script-dir=$base/lib/relais_control
|
||||
[install]
|
||||
install-scripts=$base/lib/relais_control
|
||||
26
src/relais_control/setup.py
Normal file
26
src/relais_control/setup.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from setuptools import setup
|
||||
|
||||
package_name = 'relais_control'
|
||||
|
||||
setup(
|
||||
name=package_name,
|
||||
version='0.0.0',
|
||||
packages=[package_name],
|
||||
data_files=[
|
||||
('share/ament_index/resource_index/packages',
|
||||
['resource/' + package_name]),
|
||||
('share/' + package_name, ['package.xml']),
|
||||
],
|
||||
install_requires=['setuptools'],
|
||||
zip_safe=True,
|
||||
maintainer='ubuntu',
|
||||
maintainer_email='semmer99@gmail.com',
|
||||
description='TODO: Package description',
|
||||
license='TODO: License declaration',
|
||||
tests_require=['pytest'],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'relais_controller = relais_control.relais_controller:main'
|
||||
],
|
||||
},
|
||||
)
|
||||
23
src/relais_control/test/test_copyright.py
Normal file
23
src/relais_control/test/test_copyright.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_copyright.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.copyright
|
||||
@pytest.mark.linter
|
||||
def test_copyright():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found errors'
|
||||
25
src/relais_control/test/test_flake8.py
Normal file
25
src/relais_control/test/test_flake8.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_flake8.main import main_with_errors
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.flake8
|
||||
@pytest.mark.linter
|
||||
def test_flake8():
|
||||
rc, errors = main_with_errors(argv=[])
|
||||
assert rc == 0, \
|
||||
'Found %d code style errors / warnings:\n' % len(errors) + \
|
||||
'\n'.join(errors)
|
||||
23
src/relais_control/test/test_pep257.py
Normal file
23
src/relais_control/test/test_pep257.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_pep257.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.linter
|
||||
@pytest.mark.pep257
|
||||
def test_pep257():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found code style errors / warnings'
|
||||
21
src/test_controls/package.xml
Normal file
21
src/test_controls/package.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>test_controls</name>
|
||||
<version>0.0.0</version>
|
||||
<description>test controls</description>
|
||||
<maintainer email="semmer99@gmail.com">ubuntu</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
<exec_depend>drone_services</exec_depend>
|
||||
|
||||
<test_depend>ament_copyright</test_depend>
|
||||
<test_depend>ament_flake8</test_depend>
|
||||
<test_depend>ament_pep257</test_depend>
|
||||
<test_depend>python3-pytest</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_python</build_type>
|
||||
</export>
|
||||
</package>
|
||||
0
src/test_controls/resource/test_controls
Normal file
0
src/test_controls/resource/test_controls
Normal file
4
src/test_controls/setup.cfg
Normal file
4
src/test_controls/setup.cfg
Normal file
@@ -0,0 +1,4 @@
|
||||
[develop]
|
||||
script-dir=$base/lib/test_controls
|
||||
[install]
|
||||
install-scripts=$base/lib/test_controls
|
||||
26
src/test_controls/setup.py
Normal file
26
src/test_controls/setup.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from setuptools import setup
|
||||
|
||||
package_name = 'test_controls'
|
||||
|
||||
setup(
|
||||
name=package_name,
|
||||
version='0.0.0',
|
||||
packages=[package_name],
|
||||
data_files=[
|
||||
('share/ament_index/resource_index/packages',
|
||||
['resource/' + package_name]),
|
||||
('share/' + package_name, ['package.xml']),
|
||||
],
|
||||
install_requires=['setuptools'],
|
||||
zip_safe=True,
|
||||
maintainer='ubuntu',
|
||||
maintainer_email='semmer99@gmail.com',
|
||||
description='test controls',
|
||||
license='Apache License 2.0',
|
||||
tests_require=['pytest'],
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'test_controller = test_controls.test_controller:main'
|
||||
],
|
||||
},
|
||||
)
|
||||
23
src/test_controls/test/test_copyright.py
Normal file
23
src/test_controls/test/test_copyright.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_copyright.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.copyright
|
||||
@pytest.mark.linter
|
||||
def test_copyright():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found errors'
|
||||
25
src/test_controls/test/test_flake8.py
Normal file
25
src/test_controls/test/test_flake8.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_flake8.main import main_with_errors
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.flake8
|
||||
@pytest.mark.linter
|
||||
def test_flake8():
|
||||
rc, errors = main_with_errors(argv=[])
|
||||
assert rc == 0, \
|
||||
'Found %d code style errors / warnings:\n' % len(errors) + \
|
||||
'\n'.join(errors)
|
||||
23
src/test_controls/test/test_pep257.py
Normal file
23
src/test_controls/test/test_pep257.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ament_pep257.main import main
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.linter
|
||||
@pytest.mark.pep257
|
||||
def test_pep257():
|
||||
rc = main(argv=['.', 'test'])
|
||||
assert rc == 0, 'Found code style errors / warnings'
|
||||
0
src/test_controls/test_controls/__init__.py
Normal file
0
src/test_controls/test_controls/__init__.py
Normal file
273
src/test_controls/test_controls/test_controller.py
Normal file
273
src/test_controls/test_controls/test_controller.py
Normal file
@@ -0,0 +1,273 @@
|
||||
import rclpy
|
||||
from rclpy.node import Node
|
||||
|
||||
from sshkeyboard import listen_keyboard_manual
|
||||
import asyncio
|
||||
|
||||
from drone_services.srv import SetAttitude
|
||||
from drone_services.srv import SetTrajectory
|
||||
from drone_services.srv import SetVehicleControl
|
||||
from drone_services.srv import ArmDrone
|
||||
|
||||
CONTROL_MODE_ATTITUDE = 4
|
||||
CONTROL_MODE_VELOCITY = 16
|
||||
CONTROL_MODE_POSITION = 32
|
||||
|
||||
class TestController(Node):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__('test_controller')
|
||||
self.cli = self.create_client(SetAttitude, 'drone/set_attitude')
|
||||
while not self.cli.wait_for_service(timeout_sec=1.0):
|
||||
self.get_logger().info('set attitude service not available, waiting again...')
|
||||
self.get_logger().info('successfully connected to set attitude service')
|
||||
self.vehicle_control_cli = self.create_client(
|
||||
SetVehicleControl, '/drone/set_vehicle_control')
|
||||
while not self.vehicle_control_cli.wait_for_service(timeout_sec=1.0):
|
||||
self.get_logger().info('set vehicle control service not available, waiting again...')
|
||||
self.get_logger().info('successfully connected to set vehicle control service')
|
||||
self.traj_cli = self.create_client(SetTrajectory, '/drone/set_trajectory')
|
||||
while not self.traj_cli.wait_for_service(timeout_sec=1.0):
|
||||
self.get_logger().info('set trajectory service not available, waiting again...')
|
||||
self.get_logger().info('successfully connected to set trajectory service')
|
||||
self.arm_cli = self.create_client(ArmDrone, '/drone/arm')
|
||||
while not self.arm_cli.wait_for_service(timeout_sec=1.0):
|
||||
self.get_logger().info('arm service not available, waiting again...')
|
||||
self.get_logger().info('successfully connected to arm service')
|
||||
|
||||
self.get_logger().info('all services available')
|
||||
self.control_mode = 1
|
||||
|
||||
self.attitude_req = SetAttitude.Request()
|
||||
self.vehicle_control_req = SetVehicleControl.Request()
|
||||
self.traj_req = SetTrajectory.Request()
|
||||
self.arm_req = ArmDrone.Request()
|
||||
|
||||
self.get_logger().info("\nControls:\n1 - Attitude control\n2 - Velocity control\n3 - Position control\n/ - Arm drone\nW - forward\nS - backward\nA - left\nD - right\nQ - rotate left\nE - rotate right\nSpace - up\nZ - down\nV - Down nudge\nF - Up nudge\nN - emergency stop\nCTRL-C - exit")
|
||||
|
||||
def spin(self):
|
||||
while rclpy.ok():
|
||||
asyncio.run(listen_keyboard_manual(on_press=self.on_press))
|
||||
rclpy.spin_once(self, timeout_sec=0.1)
|
||||
|
||||
def send_arm(self):
|
||||
self.future = self.arm_cli.call_async(self.arm_req)
|
||||
rclpy.spin_until_future_complete(self, self.future)
|
||||
self.get_logger().info('publishing message arm msg on service')
|
||||
return self.future.result()
|
||||
|
||||
def send_control_mode(self):
|
||||
self.vehicle_control_req.control = self.control_mode
|
||||
self.future = self.vehicle_control_cli.call_async(self.vehicle_control_req)
|
||||
rclpy.spin_until_future_complete(self, self.future)
|
||||
self.get_logger().info('publishing message vehicle control msg on service')
|
||||
return self.future.result()
|
||||
|
||||
def send_attitude_request(self, yaw, pitch, roll, thrust):
|
||||
self.attitude_req.yaw = yaw
|
||||
self.attitude_req.pitch = pitch
|
||||
self.attitude_req.roll = roll
|
||||
self.attitude_req.thrust = thrust
|
||||
self.get_logger().info('set request to %f %f %f %f' % (yaw, pitch, roll, thrust))
|
||||
self.future = self.cli.call_async(self.attitude_req)
|
||||
rclpy.spin_until_future_complete(self, self.future)
|
||||
self.get_logger().info('publishing attitude message on service')
|
||||
return self.future.result()
|
||||
|
||||
def send_velocity_request(self, x, y, z, angle):
|
||||
self.traj_req.control_mode = 2
|
||||
self.traj_req.yaw = angle
|
||||
self.traj_req.values = [x, y, z]
|
||||
self.get_logger().info('set request to %f %f %f %f' % (x, y, z, angle))
|
||||
self.future = self.traj_cli.call_async(self.traj_req)
|
||||
rclpy.spin_until_future_complete(self, self.future)
|
||||
self.get_logger().info('publishing velocity message on service')
|
||||
return self.future.result()
|
||||
|
||||
def send_position_request(self, x, y, z, angle):
|
||||
self.traj_req.control_mode = 3
|
||||
self.traj_req.yaw = angle
|
||||
self.traj_req.values = [x, y, z]
|
||||
self.get_logger().info('set request to %f %f %f %f' % (x, y, z, angle))
|
||||
self.future = self.traj_cli.call_async(self.traj_req)
|
||||
rclpy.spin_until_future_complete(self, self.future)
|
||||
self.get_logger().info('publishing position message on service')
|
||||
return self.future.result()
|
||||
|
||||
def on_release(self, key):
|
||||
# self.get_logger().info('released ' + str(key))
|
||||
pass
|
||||
|
||||
def move_up(self):
|
||||
pass
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=0.0,
|
||||
roll=0.0, thrust=0.05)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=0.0, z=0.1, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=0.0, z=0.5, angle=0.0)
|
||||
|
||||
def move_right(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=0.0,
|
||||
roll=1.0, thrust=0.0)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=1.0, y=0.0, z=0.0, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=1.0, y=0.0, z=0.0, angle=0.0)
|
||||
|
||||
def move_down(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=0.0,
|
||||
roll=0.0, thrust=-0.05)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=0.0, z=-0.1, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=0.0, z=-0.5, angle=0.0)
|
||||
|
||||
def move_left(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=0.0,
|
||||
roll=-1.0, thrust=0.0)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=-1.0, y=0.0, z=0.0, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=-1.0, y=0.0, z=0.0, angle=0.0)
|
||||
|
||||
def rotate_right(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=1.0,
|
||||
roll=0.0, thrust=0.0)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=0.0, z=0.0, angle=1.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=0.0, z=0.0, angle=1.0)
|
||||
|
||||
def rotate_left(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=-1.0,
|
||||
roll=0.0, thrust=0.0)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=0.0, z=0.0, angle=-1.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=0.0, z=0.0, angle=-1.0)
|
||||
|
||||
def move_forward(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=-1.0, yaw=0.0,
|
||||
roll=0.0, thrust=0.0)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=1.0, z=0.0, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=1.0, z=0.0, angle=0.0)
|
||||
|
||||
def move_backward(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=1.0, yaw=0.0,
|
||||
roll=0.0, thrust=0.0)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=-1.0, z=0.0, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=-1.0, z=0.0, angle=0.0)
|
||||
|
||||
def stop(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=0.0,
|
||||
roll=0.0, thrust=0.0)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=0.0, z=0.0, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=0.0, z=0.0, angle=0.0)
|
||||
|
||||
def move_up_little(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=0.0,
|
||||
roll=0.0, thrust=0.01)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=0.0, z=0.05, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=0.0, z=1.0, angle=0.0)
|
||||
|
||||
def move_down_little(self):
|
||||
if (self.control_mode == CONTROL_MODE_ATTITUDE):
|
||||
self.send_attitude_request(pitch=0.0, yaw=0.0,
|
||||
roll=0.0, thrust=-0.01)
|
||||
elif (self.control_mode == CONTROL_MODE_VELOCITY):
|
||||
self.send_velocity_request(x=0.0, y=0.0, z=-0.05, angle=0.0)
|
||||
else:
|
||||
self.send_position_request(x=0.0, y=0.0, z=-1.0, angle=0.0)
|
||||
|
||||
def on_press(self, key):
|
||||
try:
|
||||
# self.get_logger().info('pressed ' + char)
|
||||
if key == 'w':
|
||||
self.get_logger().info('forward')
|
||||
self.move_forward()
|
||||
if key == 's':
|
||||
self.get_logger().info('backward')
|
||||
self.move_backward()
|
||||
if key == 'a':
|
||||
self.get_logger().info('left')
|
||||
self.move_left()
|
||||
if key == 'd':
|
||||
self.get_logger().info('right')
|
||||
self.move_right()
|
||||
if key == 'q':
|
||||
self.get_logger().info('rotate left')
|
||||
self.rotate_left()
|
||||
if key == 'e':
|
||||
self.get_logger().info('rotate right')
|
||||
self.rotate_right()
|
||||
if key == 'z':
|
||||
self.get_logger().info('down')
|
||||
self.move_down()
|
||||
if key == 'space':
|
||||
self.get_logger().info('up')
|
||||
self.move_up()
|
||||
if key == 'v':
|
||||
self.get_logger().info('down a little')
|
||||
self.move_down_little()
|
||||
if key == 'f':
|
||||
self.get_logger().info('up a little')
|
||||
self.move_up_little()
|
||||
if key == 'n':
|
||||
self.get_logger().info('stop')
|
||||
self.stop()
|
||||
if key == '1':
|
||||
self.get_logger().info('attitude control')
|
||||
self.control_mode = CONTROL_MODE_ATTITUDE
|
||||
self.send_control_mode()
|
||||
if key == '2':
|
||||
self.get_logger().info('velocity control')
|
||||
self.control_mode = CONTROL_MODE_VELOCITY
|
||||
self.send_control_mode()
|
||||
if key == '3':
|
||||
self.get_logger().info('position control')
|
||||
self.control_mode = CONTROL_MODE_POSITION
|
||||
self.send_control_mode()
|
||||
if key == '/':
|
||||
self.get_logger().info('arming')
|
||||
self.send_arm()
|
||||
|
||||
except Exception as e:
|
||||
self.get_logger().error(str(e))
|
||||
raise e
|
||||
|
||||
|
||||
def main(args=None):
|
||||
rclpy.init(args=args)
|
||||
|
||||
test_controller = TestController()
|
||||
|
||||
test_controller.spin()
|
||||
|
||||
# Destroy the node explicitly
|
||||
# (optional - otherwise it will be done automatically
|
||||
# when the garbage collector destroys the node object)
|
||||
test_controller.destroy_node()
|
||||
rclpy.shutdown()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user