Compare commits

..

11 Commits

Author SHA1 Message Date
sfalexrog
c8bcede60a Merge branch 'master' into nti2019 2019-04-09 10:32:30 +03:00
sfalexrog
c589235984 Merge remote-tracking branch 'origin/master' into nti2019 2019-04-08 23:30:51 +03:00
Oleg Kalachev
8bb3f751ca Set correct camera frame by default for nti 2019-04-08 20:34:58 +03:00
Oleg Kalachev
d4ab87ad9e docs: small fix for markdownlint 2019-04-08 20:34:54 +03:00
Oleg Kalachev
f90c1a6329 Change some default for NTI 2019 2019-04-08 17:23:52 +03:00
Oleg Kalachev
c63e4265d6 aruco_map: add nti_novgorod map 2019-04-08 17:22:14 +03:00
Oleg Kalachev
60c97d2318 Merge branch 'master' into nti2019 2019-04-08 17:21:11 +03:00
sfalexrog
8dec500702 builder: Add ros_ws281x package 2019-04-07 17:50:31 +03:00
sfalexrog
09a8f702a7 docs: Add note about LED strip 2019-04-06 23:57:21 +03:00
sfalexrog
bcefb03f04 builder: Install paho-mqtt system-wide 2019-04-06 23:23:04 +03:00
sfalexrog
bc1ceb2fa0 Add annotated MQTT sample 2019-04-06 23:20:35 +03:00
228 changed files with 2039 additions and 5475 deletions

View File

@@ -13,59 +13,31 @@
"MD040": false, "MD040": false,
"MD044": { "MD044": {
"names": [ "names": [
"COEX",
"Copter Express",
"Коптер Экспресс",
"Клевер",
"MAVLink", "MAVLink",
"ROS", "ROS",
"ROS Kinetic", "ROS Kinetic",
"OpenCV", "OpenCV",
"Gazebo",
"GitHub", "GitHub",
"FPV", "FPV",
"PPM", "PPM",
"PWM", "PWM",
"Python", "Python",
"C++", "C++",
"JavaScript",
"Node.js",
"Django",
"Flask",
"HTTP",
"HTTPS",
"WebSocket",
"RPC",
"PX4", "PX4",
"ArduPilot",
"jMAVSim",
"px4.io",
"logs.px4.io",
"QGroundControl", "QGroundControl",
"QGC", "QGC",
"WireShark", "WireShark",
"FlightPlot", "FlightPlot",
"OFFBOARD", "OFFBOARD",
"ACRO",
"RPY",
"LPE", "LPE",
"EKF2", "EKF2",
"IMU",
"VPE",
"SITL", "SITL",
"PID", "PID",
"Wi-Fi", "Wi-Fi",
"Raspberry Pi", "Raspberry Pi",
"RPi", "RPi",
"Linux", "Linux",
"GNU",
"GNU/Linux",
"Windows", "Windows",
"Docker",
"RFC",
"Travis",
"travis-ci.org",
"travis-ci.com",
"macOS", "macOS",
"iOS", "iOS",
"Android", "Android",
@@ -73,7 +45,6 @@
"Raspbian", "Raspbian",
"Raspbian Jesse", "Raspbian Jesse",
"Raspbian Stretch", "Raspbian Stretch",
"Raspbian Buster",
"Pixhawk", "Pixhawk",
"Pixracer", "Pixracer",
"Arduino", "Arduino",
@@ -82,19 +53,12 @@
"LIRC", "LIRC",
"GPIO", "GPIO",
"HC-SR04", "HC-SR04",
"RCW-0001",
"RealSense",
"NUC",
"NVIDIA",
"Jetson",
"Jetson Nano",
"STM", "STM",
"LED", "LED",
"USB", "USB",
"FAT32", "FAT32",
"uORB", "uORB",
"SSH", "SSH",
"PuTTY",
"API", "API",
"UART", "UART",
"GND", "GND",

View File

@@ -23,16 +23,7 @@ jobs:
# Check if there are any cached images, copy them to our "images" directory # Check if there are any cached images, copy them to our "images" directory
- if [ -n "$(ls -A imgcache/*.zip)" ]; then mkdir -p images && cp imgcache/*.zip images; fi - if [ -n "$(ls -A imgcache/*.zip)" ]; then mkdir -p images && cp imgcache/*.zip images; fi
script: script:
- if [[ -z ${TRAVIS_TAG} && "${TRAVIS_PULL_REQUEST}" != "false" ]]; then - docker run --privileged --rm -v /dev:/dev -v $(pwd):/builder/repo -e TRAVIS_TAG="${TRAVIS_TAG}" ${DOCKER}
echo "Commit range is ${TRAVIS_COMMIT_RANGE}" &&
if [ $(git diff --name-only ${TRAVIS_COMMIT_RANGE} | grep -v ^"docs/" | wc -l) -eq 0 ]; then
echo " === Docs-only change; skipping build ===" &&
export SKIP_BUILD=true;
fi;
fi
- if [ -z ${SKIP_BUILD} ]; then
docker run --privileged --rm -v /dev:/dev -v $(pwd):/builder/repo -e TRAVIS_TAG="${TRAVIS_TAG}" ${DOCKER};
fi
before_cache: before_cache:
- cp images/*.zip imgcache - cp images/*.zip imgcache
before_deploy: before_deploy:
@@ -62,21 +53,21 @@ jobs:
- markdownlint -V - markdownlint -V
script: script:
- markdownlint docs - markdownlint docs
- ./check_files_size.py
- gitbook install - gitbook install
- gitbook build - gitbook build
deploy: # ***
provider: pages # Disable deployments for now, revisit this later
local-dir: _book # --sfalexrog, 06.02.2019
skip-cleanup: true # ***
github-token: ${GITHUB_OAUTH_TOKEN} # deploy:
keep-history: true # provider: pages
target-branch: master # local-dir: _book
repo: CopterExpress/clever-gitbook # skip-cleanup: true
fqdn: clever.copterexpress.com # github-token: ${GITHUB_OAUTH_TOKEN}
verbose: true # keep-history: true
on: # target-branch: gh-pages
branch: master # on:
# branch: WIP/gitbook-autobuild
- stage: Annotate - stage: Annotate
name: Auto-generate changelog name: Auto-generate changelog
language: python language: python
@@ -85,14 +76,6 @@ jobs:
- pip install GitPython PyGithub - pip install GitPython PyGithub
script: script:
- PYTHONUNBUFFERED=1 python ./gen_changelog.py - PYTHONUNBUFFERED=1 python ./gen_changelog.py
- stage: Build
name: Editorconfig-lint
language: generic
before_script:
- wget https://github.com/okalachev/editorconfig-checker/releases/download/1.2.1-disable-spaces-amount/ec-linux-amd64
- chmod +x ec-linux-amd64
script:
- ./ec-linux-amd64 -spaces-after-tabs -e "roslib.js|ros3d.js|eventemitter2.js|draw.cpp|BinUtils.swift|\.idea|apps/android/app|Assets.xcassets|test_parser_pass.txt|test_node_failure.txt"
stages: stages:
- Build - Build
- Annotate - Annotate

View File

@@ -10,7 +10,7 @@ Copter Express has implemented a large number of different autonomous drone proj
Use it to learn how to assemble, configure, pilot and program autonomous CLEVER drone. Use it to learn how to assemble, configure, pilot and program autonomous CLEVER drone.
## Raspberry Pi image ## Preconfigured RPi 3 image
**Preconfigured image for Raspberry Pi 3 with installed and configured software, ready to fly, is available [in the Releases section](https://github.com/CopterExpress/clever/releases).** **Preconfigured image for Raspberry Pi 3 with installed and configured software, ready to fly, is available [in the Releases section](https://github.com/CopterExpress/clever/releases).**
@@ -30,70 +30,49 @@ API description (in Russian) for autonomous flights is available [on GitBook](ht
## Manual installation ## Manual installation
Install ROS Kinetic according to the [documentation](http://wiki.ros.org/kinetic/Installation), then [create a Catkin workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace). Install ROS Kinetic according to the [documentation](http://wiki.ros.org/kinetic/Installation).
Clone this repo to directory `~/catkin_ws/src/clever`: Clone repo to directory `/home/pi/catkin_ws/src/clever`:
```bash ```bash
cd ~/catkin_ws/src cd ~/catkin_ws/src
git clone https://github.com/CopterExpress/clever.git clever git clone https://github.com/CopterExpress/clever.git clever
``` ```
All the required ROS packages (including `mavros` and `opencv`) can be installed using `rosdep`: Build ROS packages:
```bash
cd ~/catkin_ws/
rosdep install -y --from-paths src --ignore-src
```
Build ROS packages (on memory constrained platforms you might be going to need to use `-j1` key):
```bash ```bash
cd ~/catkin_ws cd ~/catkin_ws
catkin_make -j1 catkin_make -j1
``` ```
To complete `mavros` install you'll need to install `geographiclib` datasets: Enable systemd service `roscore` (if not enabled):
```bash ```bash
curl https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | sudo bash sudo systemctl enable /home/pi/catkin_ws/src/clever/deploy/roscore.service
```
You may optionally install udev rules to provide `/dev/px4fmu` symlink to your PX4-based flight controller connected over USB. Copy `99-px4fmu.rules` to your `/lib/udev/rules.d` folder:
```bash
cd ~/catkin_ws/src/clever/clever/config
sudo cp 99-px4fmu.rules /lib/udev/rules.d
```
Alternatively you may change the `fcu_url` property in `mavros.launch` file to point to your flight controller device.
## Running
Enable systemd service `roscore` (if not running):
```bash
sudo systemctl enable /home/<username>/catkin_ws/src/clever/deploy/roscore.service
sudo systemctl start roscore sudo systemctl start roscore
``` ```
To start connection to SITL, use: Enable systemd service `clever`:
```bash ```bash
roslaunch clever sitl.launch sudo systemctl enable /home/pi/catkin_ws/src/clever/deploy/clever.service
```
To start connection to the flight controller, use:
```bash
roslaunch clever clever.launch
```
> Note that the package is configured to connect to `/dev/px4fmu` by default (see [previous section](#manual-installation)). Install udev rules or specify path to your FCU device in `mavros.launch`.
Also, you can enable and start the systemd service:
```bash
sudo systemctl enable /home/<username>/catkin_ws/src/clever/deploy/clever.service
sudo systemctl start clever sudo systemctl start clever
``` ```
### Dependencies
[ROS Kinetic](http://wiki.ros.org/kinetic).
Necessary ROS packages:
* `opencv3`
* `mavros`
* `rosbridge_suite`
* `web_video_server`
* `cv_camera`
* `nodelet`
* `dynamic_reconfigure`
* `bondcpp`, branch `master`
* `roslint`
* `rosserial`

View File

@@ -23,18 +23,19 @@ function throttle(func, ms) {
} }
function postAppMessage(msg) { function postAppMessage(msg) {
if (window.webkit != undefined) { if (window.webkit != undefined) {
if (window.webkit.messageHandlers.appInterface != undefined) { if (window.webkit.messageHandlers.appInterface != undefined) {
window.webkit.messageHandlers.appInterface.postMessage(JSON.stringify(msg)); window.webkit.messageHandlers.appInterface.postMessage(JSON.stringify(msg));
} }
} else if (window.appInterface != undefined) { }
window.appInterface.postMessage(JSON.stringify(msg)); else if (window.appInterface != undefined) {
} window.appInterface.postMessage(JSON.stringify(msg));
}
} }
function callNativeApp(name, msg) { function callNativeApp(name, msg) {
try { try {
postAppMessage(msg); postAppMessage(msg);
return true; return true;
} catch(err) { } catch(err) {
console.warn('The native context does not exist yet'); console.warn('The native context does not exist yet');
@@ -108,12 +109,12 @@ function stickTouchStart(e) {
function stickTouchMove(e) { function stickTouchMove(e) {
for (touch of e.changedTouches) { for (touch of e.changedTouches) {
onStickTouchMove(touch); onStickTouchMove(touch);
} }
//onStickTouchMove(e.changedTouches[0]); //onStickTouchMove(e.changedTouches[0]);
rcPublishThrottled(); rcPublishThrottled();
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
} }
function stickTouchEnd(e) { function stickTouchEnd(e) {

View File

@@ -173,7 +173,7 @@ target_link_libraries(aruco_pose
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
## Mark executable scripts (Python etc.) for installation ## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination ## in contrast to setup.py, you can choose the destination
# install(PROGRAMS # install(PROGRAMS
# scripts/my_python_script # scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
@@ -216,8 +216,4 @@ target_link_libraries(aruco_pose
if (CATKIN_ENABLE_TESTING) if (CATKIN_ENABLE_TESTING)
find_package(rostest REQUIRED) find_package(rostest REQUIRED)
add_rostest(test/basic.test) add_rostest(test/basic.test)
add_rostest(test/test_parser_pass.test)
add_rostest(test/test_parser_empty_map.test)
add_rostest(test/test_node_failure.test)
add_rostest(test/largemap.test)
endif() endif()

View File

@@ -74,7 +74,6 @@ It's recommended to run it within the same nodelet manager with the camera nodel
* `~image_width` debug image width (default: 2000) * `~image_width` debug image width (default: 2000)
* `~image_height` debug image height (default: 2000) * `~image_height` debug image height (default: 2000)
* `~image_margin`  debug image margin (default: 200) * `~image_margin`  debug image margin (default: 200)
* `~dictionary` (*int*)  ArUco dictionary (default: 2) - should be the same as `dictionary` parameter of `aruco_detect` nodelet
Map file has one marker per line with the following line format: Map file has one marker per line with the following line format:
@@ -110,7 +109,7 @@ See examples in [`map`](map/) directory.
Command for running tests: Command for running tests:
```bash ```bash
catkin_make run_tests && catkin_test_results rostest aruco_pose basic.test
``` ```
## Copyright ## Copyright

View File

@@ -1,100 +0,0 @@
0 0.33 0.0 9.0 0 0 0 0
1 0.33 1.0 9.0 0 0 0 0
2 0.33 2.0 9.0 0 0 0 0
3 0.33 3.0 9.0 0 0 0 0
4 0.33 4.0 9.0 0 0 0 0
5 0.33 5.0 9.0 0 0 0 0
6 0.33 6.0 9.0 0 0 0 0
7 0.33 7.0 9.0 0 0 0 0
8 0.33 8.0 9.0 0 0 0 0
9 0.33 9.0 9.0 0 0 0 0
10 0.33 0.0 8.0 0 0 0 0
11 0.33 1.0 8.0 0 0 0 0
12 0.33 2.0 8.0 0 0 0 0
13 0.33 3.0 8.0 0 0 0 0
14 0.33 4.0 8.0 0 0 0 0
15 0.33 5.0 8.0 0 0 0 0
16 0.33 6.0 8.0 0 0 0 0
#17 0.33 7.0 8.0 0 0 0 0
18 0.33 8.0 8.0 0 0 0 0
19 0.33 9.0 8.0 0 0 0 0
20 0.33 0.0 7.0 0 0 0 0
21 0.33 1.0 7.0 0 0 0 0
22 0.33 2.0 7.0 0 0 0 0
23 0.33 3.0 7.0 0 0 0 0
24 0.33 4.0 7.0 0 0 0 0
25 0.33 5.0 7.0 0 0 0 0
26 0.33 6.0 7.0 0 0 0 0
27 0.33 7.0 7.0 0 0 0 0
28 0.33 8.0 7.0 0 0 0 0
29 0.33 9.0 7.0 0 0 0 0
30 0.33 0.0 6.0 0 0 0 0
31 0.33 1.0 6.0 0 0 0 0
32 0.33 2.0 6.0 0 0 0 0
33 0.33 3.0 6.0 0 0 0 0
34 0.33 4.0 6.0 0 0 0 0
35 0.33 5.0 6.0 0 0 0 0
36 0.33 6.0 6.0 0 0 0 0
37 0.33 7.0 6.0 0 0 0 0
38 0.33 8.0 6.0 0 0 0 0
39 0.33 9.0 6.0 0 0 0 0
40 0.33 0.0 5.0 0 0 0 0
41 0.33 1.0 5.0 0 0 0 0
42 0.33 2.0 5.0 0 0 0 0
43 0.33 3.0 5.0 0 0 0 0
44 0.33 4.0 5.0 0 0 0 0
45 0.33 5.0 5.0 0 0 0 0
46 0.33 6.0 5.0 0 0 0 0
47 0.33 7.0 5.0 0 0 0 0
48 0.33 8.0 5.0 0 0 0 0
49 0.33 9.0 5.0 0 0 0 0
50 0.33 0.0 4.0 0 0 0 0
51 0.33 1.0 4.0 0 0 0 0
52 0.33 2.0 4.0 0 0 0 0
53 0.33 3.0 4.0 0 0 0 0
54 0.33 4.0 4.0 0 0 0 0
55 0.33 5.0 4.0 0 0 0 0
56 0.33 6.0 4.0 0 0 0 0
57 0.33 7.0 4.0 0 0 0 0
58 0.33 8.0 4.0 0 0 0 0
59 0.33 9.0 4.0 0 0 0 0
60 0.33 0.0 3.0 0 0 0 0
61 0.33 1.0 3.0 0 0 0 0
62 0.33 2.0 3.0 0 0 0 0
63 0.33 3.0 3.0 0 0 0 0
64 0.33 4.0 3.0 0 0 0 0
65 0.33 5.0 3.0 0 0 0 0
66 0.33 6.0 3.0 0 0 0 0
67 0.33 7.0 3.0 0 0 0 0
68 0.33 8.0 3.0 0 0 0 0
69 0.33 9.0 3.0 0 0 0 0
70 0.33 0.0 2.0 0 0 0 0
71 0.33 1.0 2.0 0 0 0 0
72 0.33 2.0 2.0 0 0 0 0
73 0.33 3.0 2.0 0 0 0 0
74 0.33 4.0 2.0 0 0 0 0
75 0.33 5.0 2.0 0 0 0 0
76 0.33 6.0 2.0 0 0 0 0
77 0.33 7.0 2.0 0 0 0 0
78 0.33 8.0 2.0 0 0 0 0
79 0.33 9.0 2.0 0 0 0 0
80 0.33 0.0 1.0 0 0 0 0
81 0.33 1.0 1.0 0 0 0 0
82 0.33 2.0 1.0 0 0 0 0
83 0.33 3.0 1.0 0 0 0 0
84 0.33 4.0 1.0 0 0 0 0
85 0.33 5.0 1.0 0 0 0 0
86 0.33 6.0 1.0 0 0 0 0
87 0.33 7.0 1.0 0 0 0 0
88 0.33 8.0 1.0 0 0 0 0
89 0.33 9.0 1.0 0 0 0 0
90 0.33 0.0 0.0 0 0 0 0
91 0.33 1.0 0.0 0 0 0 0
92 0.33 2.0 0.0 0 0 0 0
93 0.33 3.0 0.0 0 0 0 0
94 0.33 4.0 0.0 0 0 0 0
95 0.33 5.0 0.0 0 0 0 0
96 0.33 6.0 0.0 0 0 0 0
97 0.33 7.0 0.0 0 0 0 0
98 0.33 8.0 0.0 0 0 0 0
99 0.33 9.0 0.0 0 0 0 0

View File

@@ -0,0 +1,6 @@
34 0.33 0 0 0 0 0 0
37 0.33 0.74 0 0 0 0 0
25 0.33 0 0.54 0 0 0 0
28 0.33 0.74 0.54 0 0 0 0
32 0.33 2.79 -0.15 1.20 0 0 0
29 0.33 2.46 0.65 1.20 0 0 0

View File

@@ -30,7 +30,6 @@
<depend>rostest</depend> <depend>rostest</depend>
<test_depend>image_publisher</test_depend> <test_depend>image_publisher</test_depend>
<test_depend>ros_pytest</test_depend>
<!-- The export tag contains other, unspecified, tags --> <!-- The export tag contains other, unspecified, tags -->
<export> <export>

View File

@@ -185,13 +185,9 @@ private:
// TODO: check IDs are unique // TODO: check IDs are unique
if (send_tf_) { if (send_tf_) {
transform.child_frame_id = getChildFrameId(ids[i]); transform.child_frame_id = getChildFrameId(ids[i]);
transform.transform.rotation = marker.pose.orientation;
// check if such static transform exists fillTranslation(transform.transform.translation, tvecs[i]);
if (!tf_buffer_.canTransform(transform.header.frame_id, transform.child_frame_id, transform.header.stamp)) { br_.sendTransform(transform);
transform.transform.rotation = marker.pose.orientation;
fillTranslation(transform.transform.translation, tvecs[i]);
br_.sendTransform(transform);
}
} }
} }
array_.markers.push_back(marker); array_.markers.push_back(marker);

View File

@@ -18,7 +18,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <fstream> #include <fstream>
#include <algorithm>
#include <ros/ros.h> #include <ros/ros.h>
#include <nodelet/nodelet.h> #include <nodelet/nodelet.h>
#include <pluginlib/class_list_macros.h> #include <pluginlib/class_list_macros.h>
@@ -28,7 +27,6 @@
#include <tf2_ros/buffer.h> #include <tf2_ros/buffer.h>
#include <tf2_ros/transform_listener.h> #include <tf2_ros/transform_listener.h>
#include <tf2_ros/transform_broadcaster.h> #include <tf2_ros/transform_broadcaster.h>
#include <tf2_ros/static_transform_broadcaster.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.h> #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
#include <message_filters/subscriber.h> #include <message_filters/subscriber.h>
#include <message_filters/synchronizer.h> #include <message_filters/synchronizer.h>
@@ -69,15 +67,13 @@ private:
Mat camera_matrix_, dist_coeffs_; Mat camera_matrix_, dist_coeffs_;
geometry_msgs::TransformStamped transform_; geometry_msgs::TransformStamped transform_;
geometry_msgs::PoseWithCovarianceStamped pose_; geometry_msgs::PoseWithCovarianceStamped pose_;
vector<geometry_msgs::TransformStamped> markers_transforms_;
tf2_ros::TransformBroadcaster br_; tf2_ros::TransformBroadcaster br_;
tf2_ros::StaticTransformBroadcaster static_br_;
tf2_ros::Buffer tf_buffer_; tf2_ros::Buffer tf_buffer_;
tf2_ros::TransformListener tf_listener_{tf_buffer_}; tf2_ros::TransformListener tf_listener_{tf_buffer_};
visualization_msgs::MarkerArray vis_array_; visualization_msgs::MarkerArray vis_array_;
std::string known_tilt_, map_, markers_frame_, markers_parent_frame_; std::string known_tilt_;
int image_width_, image_height_, image_margin_; int image_width_, image_height_, image_margin_;
bool auto_flip_, image_axis_; bool auto_flip_;
public: public:
virtual void onInit() virtual void onInit()
@@ -104,9 +100,6 @@ public:
nh_priv_.param("image_width", image_width_, 2000); nh_priv_.param("image_width", image_width_, 2000);
nh_priv_.param("image_height", image_height_, 2000); nh_priv_.param("image_height", image_height_, 2000);
nh_priv_.param("image_margin", image_margin_, 200); nh_priv_.param("image_margin", image_margin_, 200);
nh_priv_.param("image_axis", image_axis_, true);
nh_priv_.param<std::string>("markers/frame_id", markers_parent_frame_, transform_.child_frame_id);
nh_priv_.param<std::string>("markers/child_frame_id_prefix", markers_frame_, "");
// createStripLine(); // createStripLine();
@@ -131,7 +124,6 @@ public:
sync_.reset(new message_filters::Synchronizer<SyncPolicy>(SyncPolicy(10), image_sub_, info_sub_, markers_sub_)); sync_.reset(new message_filters::Synchronizer<SyncPolicy>(SyncPolicy(10), image_sub_, info_sub_, markers_sub_));
sync_->registerCallback(boost::bind(&ArucoMap::callback, this, _1, _2, _3)); sync_->registerCallback(boost::bind(&ArucoMap::callback, this, _1, _2, _3));
publishMarkersFrames();
publishMapImage(); publishMapImage();
vis_markers_pub_.publish(vis_array_); vis_markers_pub_.publish(vis_array_);
@@ -278,50 +270,10 @@ publish_debug:
std::istringstream s(line); std::istringstream s(line);
// Read first character to see whether it's a comment if (!(s >> id >> length >> x >> y >> z >> yaw >> pitch >> roll)) {
char first = 0; ROS_ERROR("aruco_map: cannot parse line: %s", line.c_str());
if (!(s >> first)) {
// No non-whitespace characters, must be a blank line
continue; continue;
} }
if (first == '#') {
ROS_DEBUG("aruco_map: Skipping line as a comment: %s", line.c_str());
continue;
} else if (isdigit(first)) {
// Put the digit back into the stream
// Note that this is a non-modifying putback, so this should work with istreams
// (see https://en.cppreference.com/w/cpp/io/basic_istream/putback)
s.putback(first);
} else {
// Probably garbage data; inform user and throw an exception, possibly killing nodelet
ROS_FATAL("aruco_map: Malformed input: %s", line.c_str());
ros::shutdown();
throw std::runtime_error("Malformed input");
}
if (!(s >> id >> length >> x >> y)) {
ROS_ERROR("aruco_map: Not enough data in line: %s; "
"Each marker must have at least id, length, x, y fields", line.c_str());
continue;
}
// Be less strict about z, yaw, pitch roll
if (!(s >> z)) {
ROS_DEBUG("aruco_map: No z coordinate provided for marker %d, assuming 0", id);
z = 0;
}
if (!(s >> yaw)) {
ROS_DEBUG("aruco_map: No yaw provided for marker %d, assuming 0", id);
yaw = 0;
}
if (!(s >> pitch)) {
ROS_DEBUG("aruco_map: No pitch provided for marker %d, assuming 0", id);
pitch = 0;
}
if (!(s >> roll)) {
ROS_DEBUG("aruco_map: No roll provided for marker %d, assuming 0", id);
roll = 0;
}
addMarker(id, length, x, y, z, yaw, pitch, roll); addMarker(id, length, x, y, z, yaw, pitch, roll);
} }
@@ -387,19 +339,6 @@ publish_debug:
void addMarker(int id, double length, double x, double y, double z, void addMarker(int id, double length, double x, double y, double z,
double yaw, double pitch, double roll) double yaw, double pitch, double roll)
{ {
// Check whether the id is in range for current dictionary
int num_markers = board_->dictionary->bytesList.rows;
if (num_markers <= id) {
ROS_ERROR("aruco_map: Marker id %d is not in dictionary; current dictionary contains %d markers. "
"Please see https://github.com/CopterExpress/clever/blob/master/aruco_pose/README.md#parameters for details",
id, num_markers);
return;
}
// Check if marker is already in the board
if (std::count(board_->ids.begin(), board_->ids.end(), id) > 0) {
ROS_ERROR("aruco_map: Marker id %d is already in the map", id);
return;
}
// Create transform // Create transform
tf::Quaternion q; tf::Quaternion q;
q.setRPY(roll, pitch, yaw); q.setRPY(roll, pitch, yaw);
@@ -429,15 +368,6 @@ publish_debug:
board_->ids.push_back(id); board_->ids.push_back(id);
board_->objPoints.push_back(obj_points); board_->objPoints.push_back(obj_points);
// Add marker's static transform
if (!markers_frame_.empty()) {
geometry_msgs::TransformStamped marker_transform;
marker_transform.header.frame_id = markers_parent_frame_;
marker_transform.child_frame_id = markers_frame_ + std::to_string(id);
tf::transformTFToMsg(transform, marker_transform.transform);
markers_transforms_.push_back(marker_transform);
}
// Add visualization marker // Add visualization marker
visualization_msgs::Marker marker; visualization_msgs::Marker marker;
marker.header.frame_id = transform_.child_frame_id; marker.header.frame_id = transform_.child_frame_id;
@@ -468,13 +398,6 @@ publish_debug:
// vis_array_.markers.at(0).points.push_back(p); // vis_array_.markers.at(0).points.push_back(p);
} }
void publishMarkersFrames()
{
if (!markers_transforms_.empty()) {
static_br_.sendTransform(markers_transforms_);
}
}
void publishMapImage() void publishMapImage()
{ {
cv::Size size(image_width_, image_height_); cv::Size size(image_width_, image_height_);
@@ -482,15 +405,14 @@ publish_debug:
cv_bridge::CvImage msg; cv_bridge::CvImage msg;
if (!board_->ids.empty()) { if (!board_->ids.empty()) {
_drawPlanarBoard(board_, size, image, image_margin_, 1, image_axis_); _drawPlanarBoard(board_, size, image, image_margin_, 1);
msg.encoding = image_axis_ ? sensor_msgs::image_encodings::RGB8 : sensor_msgs::image_encodings::MONO8;
} else { } else {
// empty map // empty map
image.create(size, CV_8UC1); image.create(size, CV_8UC1);
image.setTo(cv::Scalar::all(255)); image.setTo(cv::Scalar::all(255));
msg.encoding = sensor_msgs::image_encodings::MONO8;
} }
msg.encoding = sensor_msgs::image_encodings::MONO8;
msg.image = image; msg.image = image;
img_pub_.publish(msg.toImageMsg()); img_pub_.publish(msg.toImageMsg());
} }

View File

@@ -23,12 +23,12 @@ static void _projectPoints( InputArray objectPoints,
void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginSize, void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginSize,
int borderBits, bool drawAxis) { int borderBits) {
CV_Assert(outSize.area() > 0); CV_Assert(outSize.area() > 0);
CV_Assert(marginSize >= 0); CV_Assert(marginSize >= 0);
_img.create(outSize, drawAxis ? CV_8UC3 : CV_8UC1); _img.create(outSize, CV_8UC1);
Mat out = _img.getMat(); Mat out = _img.getMat();
out.setTo(Scalar::all(255)); out.setTo(Scalar::all(255));
out.adjustROI(-marginSize, -marginSize, -marginSize, -marginSize); out.adjustROI(-marginSize, -marginSize, -marginSize, -marginSize);
@@ -87,12 +87,8 @@ void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginS
// dst_sz.width = dst_sz.height = std::min(dst_sz.width, dst_sz.height); //marker should be square // dst_sz.width = dst_sz.height = std::min(dst_sz.width, dst_sz.height); //marker should be square
double diag = std::round(std::hypot(dst_sz.width, dst_sz.height)); double diag = std::round(std::hypot(dst_sz.width, dst_sz.height));
int side = std::round(diag / std::sqrt(2)); int side = std::round(diag / std::sqrt(2));
side = std::max(side, 10);
dictionary.drawMarker(_board->ids[m], side, marker, borderBits); dictionary.drawMarker(_board->ids[m], side, marker, borderBits);
if (drawAxis) {
cvtColor(marker, marker, COLOR_GRAY2RGB);
}
// interpolate tiny marker to marker position in markerZone // interpolate tiny marker to marker position in markerZone
inCorners[0] = Point2f(-0.5f, -0.5f); inCorners[0] = Point2f(-0.5f, -0.5f);
@@ -104,81 +100,74 @@ void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginS
warpAffine(marker, out, transformation, out.size(), INTER_LINEAR, warpAffine(marker, out, transformation, out.size(), INTER_LINEAR,
BORDER_TRANSPARENT); BORDER_TRANSPARENT);
} }
// draw axis
if (drawAxis) {
Size wholeSize; Point ofs;
out.locateROI(wholeSize, ofs);
auto out_copy = _img.getMat();
cv::Point center(ofs.x - minX / sizeX * float(out.cols), ofs.y + out.rows + minY / sizeY * float(out.rows));
line(out_copy, center, center + Point(300, 0), Scalar(255, 0, 0), 10); // x axis
line(out_copy, center, center + Point(0, -300), Scalar(0, 255, 0), 10); // y axis
line(out_copy, center, center + Point(-200, 200), Scalar(0, 0, 255), 10); // z axis
}
} }
/* Draw a (potentially partially visible) line. */ /* Draw a (potentially partially visible) line. */
static void linePartial(InputOutputArray image, Point3f p1, Point3f p2, const Scalar& color, static void linePartial(InputOutputArray image, Point3f p1, Point3f p2, const Scalar& color,
int thickness = 1, int lineType = LINE_8, int shift = 0) int thickness = 1, int lineType = LINE_8, int shift = 0)
{ {
// If both points are behind the screen, don't draw anything // If both points are behind the screen, don't draw anything
if (p1.z <= 0 && p2.z <= 0) { if (p1.z <= 0 && p2.z <= 0)
return; {
} return;
Point2f p1p{p1.x, p1.y}; }
Point2f p2p{p2.x, p2.y}; Point2f p1p{p1.x, p1.y};
// If points are on the different sides of the plane, compute intersection point Point2f p2p{p2.x, p2.y};
if (p1.z * p2.z < 0) { // If points are on the different sides of the plane, compute intersection point
// Compute intersection point with the screen if (p1.z * p2.z < 0)
// We denote alpha as such: {
// xi = (1 - alpha) * x1 + alpha * x2 // Compute intersection point with the screen
// yi = (1 - alpha) * y1 + alpha * y2 // We denote alpha as such:
// zi = (1 - alpha) * z1 + alpha * z2 = 0 // xi = (1 - alpha) * x1 + alpha * x2
// Thus, alpha can be expressed as // yi = (1 - alpha) * y1 + alpha * y2
// alpha = z1 / (z1 - z2) // zi = (1 - alpha) * z1 + alpha * z2 = 0
float alpha = p1.z / (p1.z - p2.z); // Thus, alpha can be expressed as
Point2f pi{(1 - alpha) * p1.x + alpha * p2.x, (1 - alpha) * p1.y + alpha * p2.y}; // alpha = z1 / (z1 - z2)
// Now, if z1 is negative, we draw the line from (xi, yi) to (x2, y2), else we draw from (x1, y1) to (xi, yi) float alpha = p1.z / (p1.z - p2.z);
if (p1.z < 0) { Point2f pi{(1 - alpha) * p1.x + alpha * p2.x, (1 - alpha) * p1.y + alpha * p2.y};
p1p = pi; // Now, if z1 is negative, we draw the line from (xi, yi) to (x2, y2), else we draw from (x1, y1) to (xi, yi)
} else { if (p1.z < 0)
p2p = pi; {
} p1p = pi;
} }
line(image, p1p, p2p, color, thickness, lineType, shift); else
{
p2p = pi;
}
}
line(image, p1p, p2p, color, thickness, lineType, shift);
} }
void _drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _distCoeffs, void _drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _distCoeffs,
InputArray _rvec, InputArray _tvec, float length) { InputArray _rvec, InputArray _tvec, float length) {
CV_Assert(_image.getMat().total() != 0 && CV_Assert(_image.getMat().total() != 0 &&
(_image.getMat().channels() == 1 || _image.getMat().channels() == 3)); (_image.getMat().channels() == 1 || _image.getMat().channels() == 3));
CV_Assert(length > 0); CV_Assert(length > 0);
// project axis points // project axis points
std::vector<Point3f> axisPoints; std::vector< Point3f > axisPoints;
axisPoints.push_back(Point3f(0, 0, 0)); axisPoints.push_back(Point3f(0, 0, 0));
axisPoints.push_back(Point3f(length, 0, 0)); axisPoints.push_back(Point3f(length, 0, 0));
axisPoints.push_back(Point3f(0, length, 0)); axisPoints.push_back(Point3f(0, length, 0));
axisPoints.push_back(Point3f(0, 0, length)); axisPoints.push_back(Point3f(0, 0, length));
std::vector<Point3f> imagePointsZ; std::vector< Point3f > imagePointsZ;
_projectPoints(axisPoints, _rvec, _tvec, _cameraMatrix, _distCoeffs, imagePointsZ); _projectPoints(axisPoints, _rvec, _tvec, _cameraMatrix, _distCoeffs, imagePointsZ);
// draw axis lines // draw axis lines
linePartial(_image, imagePointsZ[0], imagePointsZ[1], Scalar(0, 0, 255), 3); linePartial(_image, imagePointsZ[0], imagePointsZ[1], Scalar(0, 0, 255), 3);
linePartial(_image, imagePointsZ[0], imagePointsZ[2], Scalar(0, 255, 0), 3); linePartial(_image, imagePointsZ[0], imagePointsZ[2], Scalar(0, 255, 0), 3);
linePartial(_image, imagePointsZ[0], imagePointsZ[3], Scalar(255, 0, 0), 3); linePartial(_image, imagePointsZ[0], imagePointsZ[3], Scalar(255, 0, 0), 3);
} }
static CvMat _cvMat(const cv::Mat& m) static CvMat _cvMat(const cv::Mat& m)
{ {
CvMat self; CvMat self;
CV_DbgAssert(m.dims <= 2); CV_DbgAssert(m.dims <= 2);
self = cvMat(m.rows, m.dims == 1 ? 1 : m.cols, m.type(), m.data); self = cvMat(m.rows, m.dims == 1 ? 1 : m.cols, m.type(), m.data);
self.step = (int)m.step[0]; self.step = (int)m.step[0];
self.type = (self.type & ~cv::Mat::CONTINUOUS_FLAG) | (m.flags & cv::Mat::CONTINUOUS_FLAG); self.type = (self.type & ~cv::Mat::CONTINUOUS_FLAG) | (m.flags & cv::Mat::CONTINUOUS_FLAG);
return self; return self;
} }
static void _projectPoints( InputArray _opoints, static void _projectPoints( InputArray _opoints,
@@ -190,47 +179,47 @@ static void _projectPoints( InputArray _opoints,
OutputArray _jacobian, OutputArray _jacobian,
double aspectRatio ) double aspectRatio )
{ {
Mat opoints = _opoints.getMat(); Mat opoints = _opoints.getMat();
int npoints = opoints.checkVector(3), depth = opoints.depth(); int npoints = opoints.checkVector(3), depth = opoints.depth();
CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_64F)); CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_64F));
CvMat dpdrot, dpdt, dpdf, dpdc, dpddist; CvMat dpdrot, dpdt, dpdf, dpdc, dpddist;
CvMat *pdpdrot = 0, *pdpdt = 0, *pdpdf = 0, *pdpdc = 0, *pdpddist = 0; CvMat *pdpdrot=0, *pdpdt=0, *pdpdf=0, *pdpdc=0, *pdpddist=0;
CV_Assert(_ipoints.needed()); CV_Assert( _ipoints.needed() );
_ipoints.create(npoints, 1, CV_MAKETYPE(depth, 3), -1, true); _ipoints.create(npoints, 1, CV_MAKETYPE(depth, 3), -1, true);
Mat imagePoints = _ipoints.getMat(); Mat imagePoints = _ipoints.getMat();
CvMat c_imagePoints = _cvMat(imagePoints); CvMat c_imagePoints = _cvMat(imagePoints);
CvMat c_objectPoints = _cvMat(opoints); CvMat c_objectPoints = _cvMat(opoints);
Mat cameraMatrix = _cameraMatrix.getMat(); Mat cameraMatrix = _cameraMatrix.getMat();
Mat rvec = _rvec.getMat(), tvec = _tvec.getMat(); Mat rvec = _rvec.getMat(), tvec = _tvec.getMat();
CvMat c_cameraMatrix = _cvMat(cameraMatrix); CvMat c_cameraMatrix = _cvMat(cameraMatrix);
CvMat c_rvec = _cvMat(rvec), c_tvec = _cvMat(tvec); CvMat c_rvec = _cvMat(rvec), c_tvec = _cvMat(tvec);
double dc0buf[5] = {0}; double dc0buf[5]={0};
Mat dc0(5, 1, CV_64F, dc0buf); Mat dc0(5,1,CV_64F,dc0buf);
Mat distCoeffs = _distCoeffs.getMat(); Mat distCoeffs = _distCoeffs.getMat();
if (distCoeffs.empty()) if( distCoeffs.empty() )
distCoeffs = dc0; distCoeffs = dc0;
CvMat c_distCoeffs = _cvMat(distCoeffs); CvMat c_distCoeffs = _cvMat(distCoeffs);
int ndistCoeffs = distCoeffs.rows + distCoeffs.cols - 1; int ndistCoeffs = distCoeffs.rows + distCoeffs.cols - 1;
Mat jacobian; Mat jacobian;
if (_jacobian.needed()) if( _jacobian.needed() )
{ {
_jacobian.create(npoints * 2, 3 + 3 + 2 + 2 + ndistCoeffs, CV_64F); _jacobian.create(npoints*2, 3+3+2+2+ndistCoeffs, CV_64F);
jacobian = _jacobian.getMat(); jacobian = _jacobian.getMat();
pdpdrot = &(dpdrot = _cvMat(jacobian.colRange(0, 3))); pdpdrot = &(dpdrot = _cvMat(jacobian.colRange(0, 3)));
pdpdt = &(dpdt = _cvMat(jacobian.colRange(3, 6))); pdpdt = &(dpdt = _cvMat(jacobian.colRange(3, 6)));
pdpdf = &(dpdf = _cvMat(jacobian.colRange(6, 8))); pdpdf = &(dpdf = _cvMat(jacobian.colRange(6, 8)));
pdpdc = &(dpdc = _cvMat(jacobian.colRange(8, 10))); pdpdc = &(dpdc = _cvMat(jacobian.colRange(8, 10)));
pdpddist = &(dpddist = _cvMat(jacobian.colRange(10, 10 + ndistCoeffs))); pdpddist = &(dpddist = _cvMat(jacobian.colRange(10, 10+ndistCoeffs)));
} }
_cvProjectPoints2(&c_objectPoints, &c_rvec, &c_tvec, &c_cameraMatrix, &c_distCoeffs, _cvProjectPoints2( &c_objectPoints, &c_rvec, &c_tvec, &c_cameraMatrix, &c_distCoeffs,
&c_imagePoints, pdpdrot, pdpdt, pdpdf, pdpdc, pdpddist, aspectRatio); &c_imagePoints, pdpdrot, pdpdt, pdpdf, pdpdc, pdpddist, aspectRatio );
} }
namespace _detail namespace _detail

View File

@@ -3,7 +3,6 @@
#include <opencv2/opencv.hpp> #include <opencv2/opencv.hpp>
#include <opencv2/aruco.hpp> #include <opencv2/aruco.hpp>
void _drawPlanarBoard(cv::aruco::Board *_board, cv::Size outSize, cv::OutputArray _img, void _drawPlanarBoard(cv::aruco::Board *_board, cv::Size outSize, cv::OutputArray _img, int marginSize, int borderBits);
int marginSize, int borderBits, bool drawAxis); // editorconfig-checker-disable-line
void _drawAxis(cv::InputOutputArray image, cv::InputArray cameraMatrix, cv::InputArray distCoeffs, void _drawAxis(cv::InputOutputArray image, cv::InputArray cameraMatrix, cv::InputArray distCoeffs,
cv::InputArray rvec, cv::InputArray tvec, float length); // editorconfig-checker-disable-line cv::InputArray rvec, cv::InputArray tvec, float length);

View File

@@ -1,13 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright (C) 2018 Copter Express Technologies
#
# Author: Oleg Kalachev <okalachev@gmail.com>
#
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
"""Markers map generator """Markers map generator
Generate map file for aruco_map nodelet. Generate map file for aruco_map nodelet.

View File

@@ -1,14 +1,3 @@
/*
* Utility functions
* Copyright (C) 2018 Copter Express Technologies
*
* Author: Oleg Kalachev <okalachev@gmail.com>
*
* Distributed under MIT License (available at https://opensource.org/licenses/MIT).
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/
#pragma once #pragma once
#include <cmath> #include <cmath>
@@ -30,7 +19,8 @@ static void param(ros::NodeHandle nh, const std::string& param_name, T& param_va
} }
} }
static void parseCameraInfo(const sensor_msgs::CameraInfoConstPtr& cinfo, cv::Mat& matrix, cv::Mat& dist) static void parseCameraInfo(const sensor_msgs::CameraInfoConstPtr& cinfo,
cv::Mat& matrix, cv::Mat& dist)
{ {
for (unsigned int i = 0; i < 3; ++i) for (unsigned int i = 0; i < 3; ++i)
for (unsigned int j = 0; j < 3; ++j) for (unsigned int j = 0; j < 3; ++j)

View File

@@ -1,149 +1,101 @@
#!/usr/bin/env python
import sys
import unittest
import json
import rospy import rospy
import pytest import rostest
import tf2_ros
import tf2_geometry_msgs
from geometry_msgs.msg import PoseWithCovarianceStamped from geometry_msgs.msg import PoseWithCovarianceStamped
from sensor_msgs.msg import Image from sensor_msgs.msg import Image
from aruco_pose.msg import MarkerArray from aruco_pose.msg import MarkerArray
from visualization_msgs.msg import MarkerArray as VisMarkerArray from visualization_msgs.msg import MarkerArray as VisMarkerArray
@pytest.fixture class TestArucoPose(unittest.TestCase):
def node(): def setUp(self):
return rospy.init_node('aruco_pose_test', anonymous=True) rospy.init_node('test_aruco_detect', anonymous=True)
@pytest.fixture def test_markers(self):
def tf_buffer(): markers = rospy.wait_for_message('aruco_detect/markers', MarkerArray, timeout=5)
buf = tf2_ros.Buffer() self.assertEqual(len(markers.markers), 4)
tf2_ros.TransformListener(buf) self.assertEqual(markers.header.frame_id, 'main_camera_optical')
return buf
def approx(expected): self.assertEqual(markers.markers[0].id, 2)
return pytest.approx(expected, abs=1e-4) # compare floats more roughly self.assertAlmostEqual(markers.markers[0].length, 0.33, places=4)
self.assertAlmostEqual(markers.markers[0].pose.position.x, 0.36706567854, places=4)
self.assertAlmostEqual(markers.markers[0].pose.position.y, 0.290484516644, places=4)
self.assertAlmostEqual(markers.markers[0].pose.position.z, 2.18787602301, places=4)
self.assertAlmostEqual(markers.markers[0].pose.orientation.x, 0.993997406299, places=4)
self.assertAlmostEqual(markers.markers[0].pose.orientation.y, -0.00532003481626, places=4)
self.assertAlmostEqual(markers.markers[0].pose.orientation.z, -0.107390951553, places=4)
self.assertAlmostEqual(markers.markers[0].pose.orientation.w, 0.0201999263402, places=4)
self.assertAlmostEqual(markers.markers[0].c1.x, 415.557739258, places=4)
self.assertAlmostEqual(markers.markers[0].c1.y, 335.557739258, places=4)
self.assertAlmostEqual(markers.markers[0].c2.x, 509.442260742, places=4)
self.assertAlmostEqual(markers.markers[0].c2.y, 335.557739258, places=4)
self.assertAlmostEqual(markers.markers[0].c3.x, 509.442260742, places=4)
self.assertAlmostEqual(markers.markers[0].c3.y, 429.442260742, places=4)
self.assertAlmostEqual(markers.markers[0].c4.x, 415.557739258, places=4)
self.assertAlmostEqual(markers.markers[0].c4.y, 429.442260742, places=4)
def test_markers(node): self.assertEqual(markers.markers[3].id, 3)
markers = rospy.wait_for_message('aruco_detect/markers', MarkerArray, timeout=5) self.assertAlmostEqual(markers.markers[3].length, 0.1, places=4)
assert len(markers.markers) == 5 self.assertAlmostEqual(markers.markers[3].pose.position.x, -0.1805169666, places=4)
assert markers.header.frame_id == 'main_camera_optical' self.assertAlmostEqual(markers.markers[3].pose.position.y, -0.200697302327, places=4)
self.assertAlmostEqual(markers.markers[3].pose.position.z, 0.585767514823, places=4)
self.assertAlmostEqual(markers.markers[3].pose.orientation.x, -0.961738074009, places=4)
self.assertAlmostEqual(markers.markers[3].pose.orientation.y, -0.0375180244707, places=4)
self.assertAlmostEqual(markers.markers[3].pose.orientation.z, -0.0115387773672, places=4)
self.assertAlmostEqual(markers.markers[3].pose.orientation.w, 0.271144115664, places=4)
self.assertAlmostEqual(markers.markers[3].c1.x, 129.557723999, places=4)
self.assertAlmostEqual(markers.markers[3].c1.y, 49.557723999, places=4)
self.assertAlmostEqual(markers.markers[3].c2.x, 223.442276001, places=4)
self.assertAlmostEqual(markers.markers[3].c2.y, 49.557723999, places=4)
self.assertAlmostEqual(markers.markers[3].c3.x, 223.442276001, places=4)
self.assertAlmostEqual(markers.markers[3].c3.y, 143.442276001, places=4)
self.assertAlmostEqual(markers.markers[3].c4.x, 129.557723999, places=4)
self.assertAlmostEqual(markers.markers[3].c4.y, 143.442276001, places=4)
assert markers.markers[0].id == 2 self.assertEqual(markers.markers[1].id, 1)
assert markers.markers[0].length == approx(0.33) self.assertAlmostEqual(markers.markers[1].length, 0.33, places=4)
assert markers.markers[0].pose.position.x == approx(0.36706567854) self.assertEqual(markers.markers[2].id, 4)
assert markers.markers[0].pose.position.y == approx(0.290484516644) self.assertAlmostEqual(markers.markers[2].length, 0.33, places=4)
assert markers.markers[0].pose.position.z == approx(2.18787602301)
assert markers.markers[0].pose.orientation.x == approx(0.993997406299)
assert markers.markers[0].pose.orientation.y == approx(-0.00532003481626)
assert markers.markers[0].pose.orientation.z == approx(-0.107390951553)
assert markers.markers[0].pose.orientation.w == approx(0.0201999263402)
assert markers.markers[0].c1.x == approx(415.557739258)
assert markers.markers[0].c1.y == approx(335.557739258)
assert markers.markers[0].c2.x == approx(509.442260742)
assert markers.markers[0].c2.y == approx(335.557739258)
assert markers.markers[0].c3.x == approx(509.442260742)
assert markers.markers[0].c3.y == approx(429.442260742)
assert markers.markers[0].c4.x == approx(415.557739258)
assert markers.markers[0].c4.y == approx(429.442260742)
assert markers.markers[4].id == 3 def test_visualization(self):
assert markers.markers[4].length == approx(0.1) vis = rospy.wait_for_message('aruco_detect/visualization', VisMarkerArray, timeout=5)
assert markers.markers[4].pose.position.x == approx(-0.1805169666) self.assertEqual(len(vis.markers), 9)
assert markers.markers[4].pose.position.y == approx(-0.200697302327)
assert markers.markers[4].pose.position.z == approx(0.585767514823)
assert markers.markers[4].pose.orientation.x == approx(-0.961738074009)
assert markers.markers[4].pose.orientation.y == approx(-0.0375180244707)
assert markers.markers[4].pose.orientation.z == approx(-0.0115387773672)
assert markers.markers[4].pose.orientation.w == approx(0.271144115664)
assert markers.markers[4].c1.x == approx(129.557723999)
assert markers.markers[4].c1.y == approx(49.557723999)
assert markers.markers[4].c2.x == approx(223.442276001)
assert markers.markers[4].c2.y == approx(49.557723999)
assert markers.markers[4].c3.x == approx(223.442276001)
assert markers.markers[4].c3.y == approx(143.442276001)
assert markers.markers[4].c4.x == approx(129.557723999)
assert markers.markers[4].c4.y == approx(143.442276001)
assert markers.markers[1].id == 1 def test_debug(self):
assert markers.markers[1].length == approx(0.33) img = rospy.wait_for_message('aruco_detect/debug', Image, timeout=5)
assert markers.markers[3].id == 4 self.assertEqual(img.width, 640)
assert markers.markers[3].length == approx(0.33) self.assertEqual(img.height, 480)
self.assertEqual(img.header.frame_id, 'main_camera_optical')
assert markers.markers[2].id == 100 def test_map(self):
assert markers.markers[2].length == approx(0.33) pose = rospy.wait_for_message('aruco_map/pose', PoseWithCovarianceStamped, timeout=5)
assert markers.markers[2].pose.position.x == approx(-1.37600105389) self.assertEqual(pose.header.frame_id, 'main_camera_optical')
assert markers.markers[2].pose.position.y == approx(-0.323028530991) self.assertAlmostEqual(pose.pose.pose.position.x, -0.629167753342, places=4)
assert markers.markers[2].pose.position.z == approx(2.94611272668) self.assertAlmostEqual(pose.pose.pose.position.y, 0.293822650809, places=4)
assert markers.markers[2].pose.orientation.x == approx(-0.955543925678) self.assertAlmostEqual(pose.pose.pose.position.z, 2.12641343155, places=4)
assert markers.markers[2].pose.orientation.y == approx(0.0458801909197) self.assertAlmostEqual(pose.pose.pose.orientation.x, -0.998383794799, places=4)
assert markers.markers[2].pose.orientation.z == approx(-0.249604946264) self.assertAlmostEqual(pose.pose.pose.orientation.y, -5.20919098575e-06, places=4)
assert markers.markers[2].pose.orientation.w == approx(-0.150093920537) self.assertAlmostEqual(pose.pose.pose.orientation.z, -0.0300861070302, places=4)
assert markers.markers[2].c1.x == approx(52.557723999) self.assertAlmostEqual(pose.pose.pose.orientation.w, 0.0482143590507, places=4)
assert markers.markers[2].c1.y == approx(205.557723999)
assert markers.markers[2].c2.x == approx(113.442276001)
assert markers.markers[2].c2.y == approx(205.557723999)
assert markers.markers[2].c3.x == approx(113.442276001)
assert markers.markers[2].c3.y == approx(265.442260742)
assert markers.markers[2].c4.x == approx(52.557723999)
assert markers.markers[2].c4.y == approx(265.442260742)
def test_markers_frames(node, tf_buffer): def test_map_image(self):
marker_2 = tf_buffer.lookup_transform('main_camera_optical', 'aruco_2', rospy.Time(), rospy.Duration(5)) img = rospy.wait_for_message('aruco_map/image', Image, timeout=5)
assert marker_2.transform.translation.x == approx(0.36706567854) self.assertEqual(img.width, 2000)
assert marker_2.transform.translation.y == approx(0.290484516644) self.assertEqual(img.height, 2000)
assert marker_2.transform.translation.z == approx(2.18787602301) self.assertEqual(img.encoding, 'mono8')
assert marker_2.transform.rotation.x == approx(0.993997406299)
assert marker_2.transform.rotation.y == approx(-0.00532003481626)
assert marker_2.transform.rotation.z == approx(-0.107390951553)
assert marker_2.transform.rotation.w == approx(0.0201999263402)
def test_map_markers_frames(node, tf_buffer): def test_map_visualization(self):
stamp = rospy.get_rostime() vis = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
timeout = rospy.Duration(5)
marker_1 = tf_buffer.lookup_transform('aruco_map', 'aruco_in_map_1', stamp, timeout) def test_map_debug(self):
assert marker_1.transform.translation.x == approx(0) img = rospy.wait_for_message('aruco_map/debug', Image, timeout=5)
assert marker_1.transform.translation.y == approx(0)
assert marker_1.transform.translation.z == approx(0)
marker_4 = tf_buffer.lookup_transform('aruco_map', 'aruco_in_map_4', stamp, timeout) # def test_transforms(self):
assert marker_4.transform.translation.x == approx(1) # pass
assert marker_4.transform.translation.y == approx(1)
assert marker_4.transform.translation.z == approx(0)
marker_12 = tf_buffer.lookup_transform('aruco_map', 'aruco_in_map_12', stamp, timeout)
assert marker_12.transform.translation.x == approx(0.2)
assert marker_12.transform.translation.y == approx(0.5)
assert marker_12.transform.translation.z == approx(0)
def test_visualization(node): rostest.rosrun('aruco_pose', 'test_aruco_detect', TestArucoPose, sys.argv)
vis = rospy.wait_for_message('aruco_detect/visualization', VisMarkerArray, timeout=5)
assert len(vis.markers) == 11
def test_debug(node):
img = rospy.wait_for_message('aruco_detect/debug', Image, timeout=5)
assert img.width == 640
assert img.height == 480
assert img.header.frame_id == 'main_camera_optical'
def test_map(node):
pose = rospy.wait_for_message('aruco_map/pose', PoseWithCovarianceStamped, timeout=5)
assert pose.header.frame_id == 'main_camera_optical'
assert pose.pose.pose.position.x == approx(-0.629167753342)
assert pose.pose.pose.position.y == approx(0.293822650809)
assert pose.pose.pose.position.z == approx(2.12641343155)
assert pose.pose.pose.orientation.x == approx(-0.998383794799)
assert pose.pose.pose.orientation.y == approx(-5.20919098575e-06)
assert pose.pose.pose.orientation.z == approx(-0.0300861070302)
assert pose.pose.pose.orientation.w == approx(0.0482143590507)
def test_map_image(node):
img = rospy.wait_for_message('aruco_map/image', Image, timeout=5)
assert img.width == 2000
assert img.height == 2000
assert img.encoding == 'mono8'
def test_map_visualization(node):
vis = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
def test_map_debug(node):
img = rospy.wait_for_message('aruco_map/debug', Image, timeout=5)

View File

@@ -5,27 +5,23 @@
<param name="camera_info_url" value="file://$(find aruco_pose)/test/camera_info.yaml" /> <param name="camera_info_url" value="file://$(find aruco_pose)/test/camera_info.yaml" />
</node> </node>
<node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager" required="true"/> <node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager"/>
<node pkg="nodelet" clear_params="true" type="nodelet" name="aruco_detect" args="load aruco_pose/aruco_detect nodelet_manager" required="true"> <node pkg="nodelet" clear_params="true" type="nodelet" name="aruco_detect" args="load aruco_pose/aruco_detect nodelet_manager">
<remap from="image_raw" to="main_camera/image_raw"/> <remap from="image_raw" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/> <remap from="camera_info" to="main_camera/camera_info"/>
<param name="length" value="0.33"/> <param name="length" value="0.33"/>
<param name="length_override/3" value="0.1"/> <param name="length_override/3" value="0.1"/>
<param name="estimate_poses" value="true"/> <param name="estimate_poses" value="true"/>
<param name="send_tf" value="true"/>
</node> </node>
<node name="aruco_map" pkg="nodelet" type="nodelet" args="load aruco_pose/aruco_map nodelet_manager" clear_params="true" required="true"> <node name="aruco_map" pkg="nodelet" type="nodelet" args="load aruco_pose/aruco_map nodelet_manager" clear_params="true">
<remap from="image_raw" to="main_camera/image_raw"/> <remap from="image_raw" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/> <remap from="camera_info" to="main_camera/camera_info"/>
<remap from="markers" to="aruco_detect/markers"/> <remap from="markers" to="aruco_detect/markers"/>
<param name="type" value="map"/> <param name="type" value="map"/>
<param name="map" value="$(find aruco_pose)/test/basic.txt"/> <param name="map" value="$(find aruco_pose)/test/basic.txt"/>
<param name="markers/frame_id" value="aruco_map"/>
<param name="markers/child_frame_id_prefix" value="aruco_in_map_"/>
</node> </node>
<param name="test_module" value="$(find aruco_pose)/test/basic.py"/> <test test-name="test_aruco_pose" pkg="aruco_pose" type="basic.py"/>
<test test-name="aruco_pose_test" pkg="ros_pytest" type="ros_pytest_runner"/>
</launch> </launch>

View File

@@ -1,11 +1,7 @@
# Default markers
1 0.33 0 0 0 0 0 0 1 0.33 0 0 0 0 0 0
2 0.33 1 0 0 0 0 0 2 0.33 1 0 0 0 0 0
3 0.33 0 1 0 0 0 0 3 0.33 0 1 0 0 0 0
4 0.33 1 1 0 0 0 0 4 0.33 1 1 0 0 0 0
# Marker with non-zero yaw rotation
10 0.5 0.5 2 0 1.2 0 0 10 0.5 0.5 2 0 1.2 0 0
# Marker with non-zero pitch and roll rotation
11 0.2 0.5 0.5 0 0.0 -1 1 11 0.2 0.5 0.5 0 0.0 -1 1
# Marker with yaw, pitch and roll rotation
12 0.4 0.2 0.5 0 0.1 -1.2 -0.5 12 0.4 0.2 0.5 0 0.1 -1.2 -0.5

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env python
import sys
import unittest
import json
import rospy
import rostest
from sensor_msgs.msg import Image
from visualization_msgs.msg import MarkerArray as VisMarkerArray
class TestArucoPose(unittest.TestCase):
def setUp(self):
rospy.init_node('test_aruco_largemap', anonymous=True)
def test_map_image(self):
img = rospy.wait_for_message('aruco_map/image', Image, timeout=5)
self.assertEqual(img.width, 2000)
self.assertEqual(img.height, 2000)
self.assertEqual(img.encoding, 'mono8')
def test_map_visualization(self):
vis = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
rostest.rosrun('aruco_pose', 'test_aruco_largemap', TestArucoPose, sys.argv)

View File

@@ -1,13 +0,0 @@
<launch>
<node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager" required="true"/>
<node name="aruco_map" pkg="nodelet" type="nodelet" args="load aruco_pose/aruco_map nodelet_manager" clear_params="true" required="true">
<remap from="image_raw" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/>
<remap from="markers" to="aruco_detect/markers"/>
<param name="type" value="map"/>
<param name="map" value="$(find aruco_pose)/test/largemap.txt"/>
</node>
<test test-name="test_aruco_pose_largemap" pkg="aruco_pose" type="largemap.py"/>
</launch>

View File

@@ -1,11 +0,0 @@
0 0.2 0 0 0 0 0 0
1 0.2 10 0 0 0 0 0
2 0.2 20 0 0 0 0 0
3 0.2 30 0 0 0 0 0
4 0.2 40 0 0 0 0 0
5 0.2 50 0 0 0 0 0
6 0.2 60 0 0 0 0 0
7 0.2 70 0 0 0 0 0
8 0.2 80 0 0 0 0 0
9 0.2 90 0 0 0 0 0
10 0.2 100 0 0 0 0 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -1,13 +0,0 @@
import rospy
import pytest
from visualization_msgs.msg import MarkerArray as VisMarkerArray
@pytest.fixture
def node():
return rospy.init_node('aruco_pose_test', anonymous=True)
def test_node_failure(node):
with pytest.raises(rospy.exceptions.ROSException):
rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)

View File

@@ -1,14 +0,0 @@
<launch>
<node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager"/>
<node name="aruco_map" pkg="nodelet" type="nodelet" args="load aruco_pose/aruco_map nodelet_manager" clear_params="true">
<remap from="image_raw" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/>
<remap from="markers" to="aruco_detect/markers"/>
<param name="type" value="map"/>
<param name="map" value="$(find aruco_pose)/test/test_node_failure.txt"/>
</node>
<param name="test_module" value="$(find aruco_pose)/test/test_node_failure.py"/>
<test test-name="test_node_failure" pkg="ros_pytest" type="ros_pytest_runner"/>
</launch>

View File

@@ -1,4 +0,0 @@
# Any garbage data (pretty much anything apart from a comment starting with a hash starting
# with a hash sign or a number) will be interpreted as garbage data; the node should fail
# after reading it.
// Don't try to put your comments this way, it will kill your node!

View File

@@ -1,13 +0,0 @@
import rospy
import pytest
from visualization_msgs.msg import MarkerArray as VisMarkerArray
@pytest.fixture
def node():
return rospy.init_node('aruco_pose_test_empty_map', anonymous=True)
def test_empty_map(node):
markers = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
assert len(markers.markers) == 0

View File

@@ -1,14 +0,0 @@
<launch>
<node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager"/>
<node name="aruco_map" pkg="nodelet" type="nodelet" args="load aruco_pose/aruco_map nodelet_manager" clear_params="true">
<remap from="image_raw" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/>
<remap from="markers" to="aruco_detect/markers"/>
<param name="type" value="map"/>
<param name="map" value="$(find aruco_pose)/test/test_parser_empty_map.txt"/>
</node>
<param name="test_module" value="$(find aruco_pose)/test/test_parser_empty_map.py"/>
<test test-name="test_node_empty_map" pkg="ros_pytest" type="ros_pytest_runner"/>
</launch>

View File

@@ -1,6 +0,0 @@
# Failing markers: Not enough parameters to add a marker
1
2 1
3 0.5 1
# Failing markers: Marker IDs outside of dictionary range
1001 1 1 0

View File

@@ -1,61 +0,0 @@
import rospy
import pytest
from sensor_msgs.msg import Image
from aruco_pose.msg import MarkerArray
from visualization_msgs.msg import MarkerArray as VisMarkerArray
@pytest.fixture
def node():
return rospy.init_node('aruco_pose_test', anonymous=True)
def approx(expected):
return pytest.approx(expected, abs=1e-4) # compare floats more roughly
def test_markers(node):
markers = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
assert len(markers.markers) == 6
assert markers.markers[0].pose.position.x == approx(0)
assert markers.markers[0].pose.position.y == approx(0)
assert markers.markers[0].pose.position.z == approx(0)
assert markers.markers[1].pose.position.x == approx(1)
assert markers.markers[1].pose.position.y == approx(1)
assert markers.markers[1].pose.position.z == approx(1)
assert markers.markers[2].pose.position.x == approx(1)
assert markers.markers[2].pose.position.y == approx(0)
assert markers.markers[2].pose.position.z == approx(0.5)
assert markers.markers[3].pose.position.x == approx(0)
assert markers.markers[3].pose.position.y == approx(1)
assert markers.markers[3].pose.position.z == approx(0)
assert markers.markers[4].pose.position.x == approx(1)
assert markers.markers[4].pose.position.y == approx(0.5)
assert markers.markers[4].pose.position.z == approx(0)
assert markers.markers[5].pose.position.x == approx(2.2)
assert markers.markers[5].pose.position.y == approx(0.2)
assert markers.markers[5].pose.position.z == approx(0)
assert markers.markers[0].scale.x == approx(0.33)
assert markers.markers[0].scale.y == approx(0.33)
assert markers.markers[1].scale.x == approx(0.225)
assert markers.markers[1].scale.y == approx(0.225)
assert markers.markers[2].scale.x == approx(0.45)
assert markers.markers[2].scale.y == approx(0.45)
assert markers.markers[3].scale.x == approx(0.15)
assert markers.markers[3].scale.y == approx(0.15)
assert markers.markers[4].scale.x == approx(0.25)
assert markers.markers[4].scale.y == approx(0.25)
assert markers.markers[5].scale.x == approx(0.35)
assert markers.markers[5].scale.y == approx(0.35)
def test_map_image(node):
img = rospy.wait_for_message('aruco_map/image', Image, timeout=5)
assert img.width == 2000
assert img.height == 2000
assert img.encoding == 'mono8'

View File

@@ -1,14 +0,0 @@
<launch>
<node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager" required="true"/>
<node name="aruco_map" pkg="nodelet" type="nodelet" args="load aruco_pose/aruco_map nodelet_manager" clear_params="true" required="true">
<remap from="image_raw" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/>
<remap from="markers" to="aruco_detect/markers"/>
<param name="type" value="map"/>
<param name="map" value="$(find aruco_pose)/test/test_parser_pass.txt"/>
</node>
<param name="test_module" value="$(find aruco_pose)/test/test_parser_pass.py"/>
<test test-name="test_node_pass" pkg="ros_pytest" type="ros_pytest_runner"/>
</launch>

View File

@@ -1,23 +0,0 @@
# Parser test #1 - correct file
# 1. Commentary test
#Commentary text without space after pound sign
# Commentary text with space after pound sign
# Commentary text with spaces before pound sign
# Commentary text with tab before pound sign
# Text with tabs before pound sign
# Empty line test:
# All-whitespace line test:
# 2. Default coordinates test
# Fully filled marker description, tab-delimited:
1 0.33 0 0 0 0 0 0
# Fully filled marker description, space-delimited:
2 0.225 1 1 1 0 0 0
# Default roll, pitch, yaw angles
3 0.45 1 0 0.5
# Default roll, pitch, yaw, z
4 0.15 0 1
# Inline commentary
5 0.25 1 0.5# Comment straight after digit
6 0.35 2.2 0.2 # Comment with a space after digit

View File

@@ -4,7 +4,6 @@
"author": "Copter Express", "author": "Copter Express",
"language": "ru", "language": "ru",
"root": "docs/", "root": "docs/",
"gitbook": "^3.2.2",
"plugins": [ "plugins": [
"youtube", "youtube",
"richquotes@https://github.com/okalachev/gitbook-plugin-richquotes.git", "richquotes@https://github.com/okalachev/gitbook-plugin-richquotes.git",

View File

@@ -1,12 +1,12 @@
[Unit] [Unit]
Description=Clever ROS package Description=Clever ROS package
Requires=roscore.service Requires=roscore.service
After=network.target After=roscore.service
[Service] [Service]
User=pi User=pi
ExecStart=/bin/sh -c ". /home/pi/catkin_ws/devel/setup.sh; \ EnvironmentFile=/lib/systemd/system/roscore.env
ROS_HOSTNAME=`hostname`.local exec roslaunch clever clever.launch --wait --screen --skip-log-check" ExecStart=/opt/ros/kinetic/bin/roslaunch clever clever.launch --wait --screen
Restart=on-failure Restart=on-failure
RestartSec=3 RestartSec=3

35
builder/assets/clever_rename Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Set Clever hostname to the specified value
set -e
NEW_NAME_OPT=$1
if [[ -z ${NEW_NAME_OPT} ]]; then
echo "Please specify new name for this Clever"
exit 1
fi
NEW_NAME=$(echo ${NEW_NAME_OPT} | tr '[:upper:]' '[:lower:]')
echo "Setting name to ${NEW_NAME}"
echo "Backing up /etc/hostname"
cp /etc/hostname /etc/hostname.bak
echo "Writing new /etc/hostname"
echo ${NEW_NAME} > /etc/hostname
echo "Backing up /etc/hosts"
cp /etc/hosts /etc/hosts.bak
echo "Rewriting /etc/hosts with new values"
sed -i 's/127\.0\.1\.1.*/127.0.1.1\t'${NEW_NAME}'/g' /etc/hosts
echo "Changing hostname in /lib/systemd/system/roscore.env"
sed -i 's/ROS_HOSTNAME=.*/ROS_HOSTNAME='${NEW_NAME}'.local/g' /lib/systemd/system/roscore.env
echo "Changing hostname in .bashrc"
sed -i 's/export ROS_HOSTNAME=.*/export ROS_HOSTNAME='${NEW_NAME}'.local/g' /home/pi/.bashrc
echo "Done, reboot your Clever to see the results"

View File

@@ -8,10 +8,6 @@
# #
# Author: Artem Smirnov <urpylka@gmail.com> # Author: Artem Smirnov <urpylka@gmail.com>
# #
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
set -e # Exit immidiately on non-zero result set -e # Exit immidiately on non-zero result

View File

@@ -8,10 +8,6 @@
# #
# Author: Artem Smirnov <urpylka@gmail.com> # Author: Artem Smirnov <urpylka@gmail.com>
# #
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
set -e # Exit immidiately on non-zero result set -e # Exit immidiately on non-zero result
@@ -38,11 +34,7 @@ echo_stamp() {
echo_stamp "Rename SSID" echo_stamp "Rename SSID"
NEW_SSID='CLEVER-'$(head -c 100 /dev/urandom | xxd -ps -c 100 | sed -e "s/[^0-9]//g" | cut -c 1-4) NEW_SSID='CLEVER-'$(head -c 100 /dev/urandom | xxd -ps -c 100 | sed -e "s/[^0-9]//g" | cut -c 1-4)
sudo sed -i.OLD "s/CLEVER/${NEW_SSID}/" /etc/wpa_supplicant/wpa_supplicant.conf sudo sed -i.OLD "s/CLEVER/${NEW_SSID}/" /etc/wpa_supplicant/wpa_supplicant.conf
clever_rename ${NEW_SSID}
echo_stamp "Rename hostname to $NEW_SSID"
hostnamectl set-hostname $NEW_SSID
sed -i 's/127\.0\.1\.1.*/127.0.1.1\t'${NEW_SSID}' '${NEW_SSID}'.local/g' /etc/hosts
# .local (mdns) hostname added to make it accesable when wlan and ethernet interfaces down
echo_stamp "Harware setup" echo_stamp "Harware setup"
/root/hardware_setup.sh /root/hardware_setup.sh

View File

@@ -541,15 +541,3 @@ tf2_web_republisher:
image_publisher: image_publisher:
debian: debian:
stretch: [ros-kinetic-image-publisher] stretch: [ros-kinetic-image-publisher]
raspberry-kernel-headers:
debian:
stretch: [raspberry-kernel-headers]
ddynamic_reconfigure:
debian:
stretch: [ros-kinetic-ddynamic-reconfigure]
realsense2_camera:
debian:
stretch: [ros-kinetic-realsense2-camera]
ros_pytest:
debian:
stretch: [ros-kinetic-ros-pytest]

View File

@@ -1,8 +0,0 @@
[Unit]
Description=Daemon required to control GPIO pins via pigpio
[Service]
ExecStart=/usr/bin/pigpiod -l -t 0 -x 0x0FFF3FF0
ExecStop=/bin/systemctl kill pigpiod
Type=forking
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,10 @@
ROS_ROOT=/opt/ros/kinetic/share/ros
ROS_DISTRO=kinetic
ROS_PACKAGE_PATH=/home/pi/catkin_ws/src:/opt/ros/kinetic/share
ROS_PORT=11311
ROS_MASTER_URI=http://localhost:11311
CMAKE_PREFIX_PATH=/home/pi/catkin_ws/devel:/opt/ros/kinetic
PATH=/opt/ros/kinetic/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
LD_LIBRARY_PATH=/opt/ros/kinetic/lib
PYTHONPATH=/home/pi/catkin_ws/devel/lib/python2.7/dist-packages:/opt/ros/kinetic/lib/python2.7/dist-packages
ROS_HOSTNAME=raspberrypi.local

View File

@@ -4,7 +4,8 @@ After=network.target
[Service] [Service]
User=pi User=pi
ExecStart=/bin/sh -c ". /opt/ros/kinetic/setup.sh; ROS_HOSTNAME=`hostname`.local exec roscore" EnvironmentFile=/lib/systemd/system/roscore.env
ExecStart=/opt/ros/kinetic/bin/roscore
Restart=on-failure Restart=on-failure
RestartSec=3 RestartSec=3

View File

@@ -0,0 +1,14 @@
[Unit]
Description=ROS ws281x support
Requires=roscore.service
After=roscore.service
[Service]
EnvironmentFile=/lib/systemd/system/roscore.env
ExecStart=/opt/ros/kinetic/bin/roslaunch ros_ws281x clever4.launch --wait --screen
Restart=on-failure
RestartSec=3
TimeoutSec=infinity
[Install]
WantedBy=multi-user.target

View File

@@ -1,21 +1,17 @@
#! /usr/bin/env bash #! /usr/bin/env bash
# #
# Script for build the image. Used builder script of the target repo. # Script for build the image. Used builder script of the target repo
# For build: docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/builder/repo smirart/builder # For build: docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/builder/repo smirart/builder
# #
# Copyright (C) 2018 Copter Express Technologies # Copyright (C) 2018 Copter Express Technologies
# #
# Author: Artem Smirnov <urpylka@gmail.com> # Author: Artem Smirnov <urpylka@gmail.com>
# #
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
set -e # Exit immidiately on non-zero result set -e # Exit immidiately on non-zero result
SOURCE_IMAGE="https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-04-09/2019-04-08-raspbian-stretch-lite.zip" SOURCE_IMAGE="https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2018-11-15/2018-11-13-raspbian-stretch-lite.zip"
export DEBIAN_FRONTEND=${DEBIAN_FRONTEND:='noninteractive'} export DEBIAN_FRONTEND=${DEBIAN_FRONTEND:='noninteractive'}
export LANG=${LANG:='C.UTF-8'} export LANG=${LANG:='C.UTF-8'}
@@ -109,14 +105,16 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-network.
[[ $(arch) == 'armv7l' ]] && NUMBER_THREADS=1 || NUMBER_THREADS=$(nproc --all) [[ $(arch) == 'armv7l' ]] && NUMBER_THREADS=1 || NUMBER_THREADS=$(nproc --all)
# Clever # Clever
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clever.service' '/lib/systemd/system/' ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clever.service' '/lib/systemd/system/'
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/roscore.env' '/lib/systemd/system/'
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/roscore.service' '/lib/systemd/system/' ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/roscore.service' '/lib/systemd/system/'
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/kinetic-rosdep-clever.yaml' '/etc/ros/rosdep/' ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/kinetic-rosdep-clever.yaml' '/etc/ros/rosdep/'
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/ros_python_paths' '/etc/sudoers.d/' ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/ros_python_paths' '/etc/sudoers.d/'
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/pigpiod.service' '/lib/systemd/system/'
# ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/kinetic-ros-clever.rosinstall' '/home/pi/ros_catkin_ws/' # ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/kinetic-ros-clever.rosinstall' '/home/pi/ros_catkin_ws/'
# Add PX4 udev rules # Add PX4 udev rules
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${REPO_DIR}'/clever/config/99-px4fmu.rules' '/lib/udev/rules.d/' ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/99-px4fmu.rules' '/lib/udev/rules.d/'
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/rosled.service' '/lib/systemd/system/'
# Add rename script # Add rename script
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clever_rename' '/usr/local/bin/clever_rename'
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-ros.sh' ${REPO_URL} ${IMAGE_VERSION} false false ${NUMBER_THREADS} ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-ros.sh' ${REPO_URL} ${IMAGE_VERSION} false false ${NUMBER_THREADS}
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-validate.sh' ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-validate.sh'

View File

@@ -1,16 +1,12 @@
#! /usr/bin/env bash #! /usr/bin/env bash
# #
# Script for image initialisation # Script for initialisation image
# #
# Copyright (C) 2018 Copter Express Technologies # Copyright (C) 2018 Copter Express Technologies
# #
# Author: Artem Smirnov <urpylka@gmail.com> # Author: Artem Smirnov <urpylka@gmail.com>
# #
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
set -e # Exit immidiately on non-zero result set -e # Exit immidiately on non-zero result

View File

@@ -1,16 +1,12 @@
#! /usr/bin/env bash #! /usr/bin/env bash
# #
# Script for network configuration # Script for network configure
# #
# Copyright (C) 2018 Copter Express Technologies # Copyright (C) 2018 Copter Express Technologies
# #
# Author: Artem Smirnov <urpylka@gmail.com> # Author: Artem Smirnov <urpylka@gmail.com>
# #
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
set -e # Exit immidiately on non-zero result set -e # Exit immidiately on non-zero result

View File

@@ -8,10 +8,6 @@
# #
# Author: Artem Smirnov <urpylka@gmail.com> # Author: Artem Smirnov <urpylka@gmail.com>
# #
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
set -e # Exit immidiately on non-zero result set -e # Exit immidiately on non-zero result
@@ -46,10 +42,9 @@ echo_stamp() {
my_travis_retry() { my_travis_retry() {
local result=0 local result=0
local count=1 local count=1
local max_count=50 while [ $count -le 3 ]; do
while [ $count -le $max_count ]; do
[ $result -ne 0 ] && { [ $result -ne 0 ] && {
echo -e "\nThe command \"$@\" failed. Retrying, $count of $max_count.\n" >&2 echo -e "\n${ANSI_RED}The command \"$@\" failed. Retrying, $count of 3.${ANSI_RESET}\n" >&2
} }
# ! { } ignores set -e, see https://stackoverflow.com/a/4073372 # ! { } ignores set -e, see https://stackoverflow.com/a/4073372
! { "$@"; result=$?; } ! { "$@"; result=$?; }
@@ -58,21 +53,21 @@ my_travis_retry() {
sleep 1 sleep 1
done done
[ $count -gt $max_count ] && { [ $count -gt 3 ] && {
echo -e "\nThe command \"$@\" failed $max_count times.\n" >&2 echo -e "\n${ANSI_RED}The command \"$@\" failed 3 times.${ANSI_RESET}\n" >&2
} }
return $result return $result
} }
# TODO: 'kinetic-rosdep-clever.yaml' should add only if we use our repo? # TODO: 'kinetic-rosdep-clever.yaml' should add only if we use our repo?
echo_stamp "Init rosdep" echo_stamp "Init rosdep" \
my_travis_retry rosdep init && rosdep init \
echo "yaml file:///etc/ros/rosdep/kinetic-rosdep-clever.yaml" >> /etc/ros/rosdep/sources.list.d/20-default.list && echo "yaml file:///etc/ros/rosdep/kinetic-rosdep-clever.yaml" >> /etc/ros/rosdep/sources.list.d/20-default.list \
my_travis_retry rosdep update && rosdep update
echo_stamp "Populate rosdep for ROS user" echo_stamp "Populate rosdep for ROS user"
my_travis_retry sudo -u pi rosdep update sudo -u pi rosdep update
resolve_rosdep() { resolve_rosdep() {
# TEMPLATE: resolve_rosdep <CATKIN_PATH> <ROS_DISTRO> <OS_DISTRO> <OS_VERSION> # TEMPLATE: resolve_rosdep <CATKIN_PATH> <ROS_DISTRO> <OS_DISTRO> <OS_VERSION>
@@ -142,9 +137,9 @@ fi
export ROS_IP='127.0.0.1' # needed for running tests export ROS_IP='127.0.0.1' # needed for running tests
echo_stamp "Reconfiguring Clever repository for simplier unshallowing" echo_stamp "Adding ros_ws281x ROS package"
cd /home/pi/catkin_ws/src/clever cd /home/pi/catkin_ws/src
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" git clone https://github.com/sfalexrog/ros_ws281x
echo_stamp "Installing CLEVER" \ echo_stamp "Installing CLEVER" \
&& cd /home/pi/catkin_ws/src/clever \ && cd /home/pi/catkin_ws/src/clever \
@@ -154,12 +149,17 @@ echo_stamp "Installing CLEVER" \
&& my_travis_retry pip install wheel \ && my_travis_retry pip install wheel \
&& my_travis_retry pip install -r /home/pi/catkin_ws/src/clever/clever/requirements.txt \ && my_travis_retry pip install -r /home/pi/catkin_ws/src/clever/clever/requirements.txt \
&& source /opt/ros/kinetic/setup.bash \ && source /opt/ros/kinetic/setup.bash \
&& catkin_make -j2 -DCMAKE_BUILD_TYPE=Release \ && catkin_make -j2 -DCMAKE_BUILD_TYPE=Release -DROS_WS2811_REAL_LIB=ON \
&& catkin_make run_tests \
&& catkin_test_results \
&& systemctl enable roscore \ && systemctl enable roscore \
&& systemctl enable clever \ && systemctl enable clever \
&& echo_stamp "All CLEVER was installed!" "SUCCESS" \ && echo_stamp "All CLEVER was installed!" "SUCCESS" \
|| (echo_stamp "CLEVER installation was failed!" "ERROR"; exit 1) || (echo_stamp "CLEVER installation was failed!" "ERROR"; exit 1)
echo_stamp "Enabling ROS LED service"
systemctl enable rosled
echo_stamp "Build CLEVER documentation" echo_stamp "Build CLEVER documentation"
cd /home/pi/catkin_ws/src/clever cd /home/pi/catkin_ws/src/clever
NPM_CONFIG_UNSAFE_PERM=true npm install gitbook-cli -g NPM_CONFIG_UNSAFE_PERM=true npm install gitbook-cli -g
@@ -169,21 +169,18 @@ gitbook build
echo_stamp "Installing additional ROS packages" echo_stamp "Installing additional ROS packages"
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
ros-kinetic-dynamic-reconfigure \ ros-kinetic-dynamic-reconfigure \
ros-kinetic-tf2-web-republisher \
ros-kinetic-compressed-image-transport \ ros-kinetic-compressed-image-transport \
ros-kinetic-rosbridge-suite \ ros-kinetic-rosbridge-suite \
ros-kinetic-rosserial \ ros-kinetic-rosserial \
ros-kinetic-usb-cam \ ros-kinetic-usb-cam \
ros-kinetic-vl53l1x \ ros-kinetic-vl53l1x \
ros-kinetic-opencv3=3.3.19-0stretch \ ros-kinetic-opencv3=3.3.19-0stretch
ros-kinetic-rosshow
# TODO move GeographicLib datasets to Mavros debian package # TODO move GeographicLib datasets to Mavros debian package
echo_stamp "Install GeographicLib datasets (needed for mavros)" \ echo_stamp "Install GeographicLib datasets (needs for mavros)" \
&& wget -qO- https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | bash && wget -qO- https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | bash
echo_stamp "Running tests"
catkin_make run_tests && catkin_test_results
echo_stamp "Change permissions for catkin_ws" echo_stamp "Change permissions for catkin_ws"
chown -Rf pi:pi /home/pi/catkin_ws chown -Rf pi:pi /home/pi/catkin_ws
@@ -192,7 +189,7 @@ cat << EOF >> /home/pi/.bashrc
LANG='C.UTF-8' LANG='C.UTF-8'
LC_ALL='C.UTF-8' LC_ALL='C.UTF-8'
ROS_DISTRO='kinetic' ROS_DISTRO='kinetic'
export ROS_HOSTNAME=\`hostname\`.local export ROS_HOSTNAME='raspberrypi.local'
source /opt/ros/kinetic/setup.bash source /opt/ros/kinetic/setup.bash
source /home/pi/catkin_ws/devel/setup.bash source /home/pi/catkin_ws/devel/setup.bash
EOF EOF

View File

@@ -1,16 +1,12 @@
#! /usr/bin/env bash #! /usr/bin/env bash
# #
# Script for installing software to the image. # Script for install software to the image.
# #
# Copyright (C) 2018 Copter Express Technologies # Copyright (C) 2018 Copter Express Technologies
# #
# Author: Artem Smirnov <urpylka@gmail.com> # Author: Artem Smirnov <urpylka@gmail.com>
# #
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
set -e # Exit immidiately on non-zero result set -e # Exit immidiately on non-zero result
@@ -63,7 +59,7 @@ echo_stamp "Install apt keys & repos"
curl http://repo.coex.space/aptly_repo_signing.key 2> /dev/null | apt-key add - curl http://repo.coex.space/aptly_repo_signing.key 2> /dev/null | apt-key add -
apt-get update \ apt-get update \
&& apt-get install --no-install-recommends -y -qq dirmngr=2.1.18-8~deb9u4 > /dev/null \ && apt-get install --no-install-recommends -y -qq dirmngr=2.1.18-8~deb9u4 > /dev/null \
&& apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 && apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
echo "deb http://packages.ros.org/ros/ubuntu stretch main" > /etc/apt/sources.list.d/ros-latest.list echo "deb http://packages.ros.org/ros/ubuntu stretch main" > /etc/apt/sources.list.d/ros-latest.list
echo "deb http://repo.coex.space/rpi-ros-kinetic stretch main" > /etc/apt/sources.list.d/rpi-ros-kinetic.list echo "deb http://repo.coex.space/rpi-ros-kinetic stretch main" > /etc/apt/sources.list.d/rpi-ros-kinetic.list
@@ -88,9 +84,9 @@ lsof=4.89+dfsg-0.1 \
git \ git \
dnsmasq=2.76-5+rpt1+deb9u1 \ dnsmasq=2.76-5+rpt1+deb9u1 \
tmux=2.3-4 \ tmux=2.3-4 \
vim \ vim=2:8.0.0197-4+deb9u1 \
cmake=3.7.2-1 \ cmake=3.7.2-1 \
libjpeg8=8d1-2 \ libjpeg8-dev=8d1-2 \
tcpdump \ tcpdump \
ltrace \ ltrace \
libpoco-dev=1.7.6+dfsg1-5+deb9u1 \ libpoco-dev=1.7.6+dfsg1-5+deb9u1 \
@@ -103,24 +99,14 @@ libffi-dev \
monkey=1.6.9-1 \ monkey=1.6.9-1 \
pigpio python-pigpio python3-pigpio \ pigpio python-pigpio python3-pigpio \
i2c-tools \ i2c-tools \
espeak espeak-data python-espeak \
ntpdate \ ntpdate \
python-dev \ python-dev \
python3-dev \ python3-dev \
python-systemd \
mjpg-streamer=2.0 \
&& echo_stamp "Everything was installed!" "SUCCESS" \ && echo_stamp "Everything was installed!" "SUCCESS" \
|| (echo_stamp "Some packages wasn't installed!" "ERROR"; exit 1) || (echo_stamp "Some packages wasn't installed!" "ERROR"; exit 1)
echo_stamp "Updating kernel to fix camera bug" echo_stamp "Updating kernel to fix camera bug"
apt-get install --no-install-recommends -y \ apt-get install --no-install-recommends -y raspberrypi-kernel=1.20190215-1
raspberrypi-kernel=1.20190709~stretch-1 \
raspberrypi-bootloader=1.20190709~stretch-1 \
libraspberrypi-bin=1.20190709~stretch-1 \
libraspberrypi-dev=1.20190709~stretch-1 \
libraspberrypi0=1.20190709~stretch-1 \
wireless-regdb=2018.05.09-0~rpt1 \
wpasupplicant=2:2.6-21~bpo9~rpt1
# Deny byobu to check available updates # Deny byobu to check available updates
sed -i "s/updates_available//" /usr/share/byobu/status/status sed -i "s/updates_available//" /usr/share/byobu/status/status
@@ -153,6 +139,9 @@ mv /etc/monkey/sites/default /etc/monkey/sites/default.orig
mv /root/monkey /etc/monkey/sites/default mv /root/monkey /etc/monkey/sites/default
systemctl enable monkey.service systemctl enable monkey.service
echo_stamp "Install paho-mqtt"
my_travis_retry pip install paho-mqtt
echo_stamp "Install Node.js" echo_stamp "Install Node.js"
cd /home/pi cd /home/pi
wget https://nodejs.org/dist/v10.15.0/node-v10.15.0-linux-armv6l.tar.gz wget https://nodejs.org/dist/v10.15.0/node-v10.15.0-linux-armv6l.tar.gz
@@ -168,9 +157,6 @@ syntax on
autocmd BufNewFile,BufRead *.launch set syntax=xml autocmd BufNewFile,BufRead *.launch set syntax=xml
EOF EOF
echo_stamp "Change default keyboard layout to US"
sed -i 's/XKBLAYOUT="gb"/XKBLAYOUT="us"/g' /etc/default/keyboard
echo_stamp "Attempting to kill dirmngr" echo_stamp "Attempting to kill dirmngr"
gpgconf --kill dirmngr gpgconf --kill dirmngr
# dirmngr is only used by apt-key, so we can safely kill it. # dirmngr is only used by apt-key, so we can safely kill it.

View File

@@ -7,10 +7,6 @@
# #
# Author: Oleg Kalachev <okalachev@gmail.com> # Author: Oleg Kalachev <okalachev@gmail.com>
# #
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
set -ex set -ex

View File

@@ -25,6 +25,6 @@ import pymavlink
from pymavlink import mavutil from pymavlink import mavutil
import rpi_ws281x import rpi_ws281x
import pigpio import pigpio
from espeak import espeak
print cv2.getBuildInformation() print cv2.getBuildInformation()

View File

@@ -28,8 +28,6 @@ monkey --version
pigpiod -v pigpiod -v
i2cdetect -V i2cdetect -V
butterfly -h butterfly -h
espeak --version
mjpg_streamer --version
# ros stuff # ros stuff
@@ -48,4 +46,4 @@ rosversion rosserial
rosversion usb_cam rosversion usb_cam
rosversion cv_camera rosversion cv_camera
rosversion web_video_server rosversion web_video_server
rosversion rosshow rosversion ros_ws281x

View File

@@ -1,31 +0,0 @@
#!/usr/bin/env python3
import os
import sys
def human_size(num, suffix='B'):
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
if abs(num) < 1024.0:
return "%3.1f %s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f %s%s" % (num, 'Yi', suffix)
SIZE_LIMIT = 600 * 1024
EXCLUDE = 'rviz.png', 'ssid.png', 'sitl_docker_demo.png', 'qgc-params.png', 'butterfly.png', \
'Clever main.png', 'fpv_3.png', '1_4.png', 'fpv_4.png', 'detal1.png', 'lockradio.png', \
'qground.png', 'allElements.png', 'download-log.png', 'explosion.png', 'rqt.png', \
'cl3_mountBEC.JPG', 'cl3_mountRpiCamera.JPG'
code = 0
for root, dirs, files in os.walk('docs/'):
for f in files:
if f not in EXCLUDE:
path = os.path.join(root, f)
size = os.path.getsize(path)
if size > SIZE_LIMIT:
print('\x1b[1;31mFile too large ({}): {}\x1b[0m'.format(human_size(size), path), \
file=sys.stderr)
code = 1
sys.exit(code)

View File

@@ -162,6 +162,8 @@ add_executable(rc src/rc.cpp)
add_executable(camera_markers src/camera_markers.cpp) add_executable(camera_markers src/camera_markers.cpp)
add_executable(frames src/frames.cpp)
add_executable(vpe_publisher src/vpe_publisher.cpp) add_executable(vpe_publisher src/vpe_publisher.cpp)
target_link_libraries(simple_offboard target_link_libraries(simple_offboard
@@ -173,6 +175,8 @@ target_link_libraries(rc ${catkin_LIBRARIES})
target_link_libraries(camera_markers ${catkin_LIBRARIES}) target_link_libraries(camera_markers ${catkin_LIBRARIES})
target_link_libraries(frames ${catkin_LIBRARIES})
target_link_libraries(vpe_publisher ${catkin_LIBRARIES}) target_link_libraries(vpe_publisher ${catkin_LIBRARIES})
add_dependencies(simple_offboard clever_generate_messages_cpp) add_dependencies(simple_offboard clever_generate_messages_cpp)
@@ -227,19 +231,6 @@ target_link_libraries(clever
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# ) # )
# Only install udev rules when building a Debian package
# FIXME: Other operating systems may have other prefixes
string(FIND ${CMAKE_INSTALL_PREFIX} "/opt/ros" _PREFIX_INDEX)
if (${_PREFIX_INDEX} EQUAL 0)
message(STATUS "Building as a Debian package - adding udev rules as installable files")
install(FILES
config/99-px4fmu.rules
DESTINATION /lib/udev/rules.d
)
else()
message(STATUS "Building in a user workspace - not adding udev rules")
endif()
############# #############
## Testing ## ## Testing ##
############# #############
@@ -252,8 +243,3 @@ endif()
## Add folders to be run by python nosetests ## Add folders to be run by python nosetests
# catkin_add_nosetests(test) # catkin_add_nosetests(test)
if (CATKIN_ENABLE_TESTING)
find_package(rostest REQUIRED)
add_rostest(test/basic.test)
endif()

View File

@@ -1,7 +1,7 @@
<launch> <launch>
<arg name="aruco_detect" default="true"/> <arg name="aruco_detect" default="true"/>
<arg name="aruco_map" default="false"/> <arg name="aruco_map" default="true"/>
<arg name="aruco_vpe" default="false"/> <arg name="aruco_vpe" default="true"/>
<!-- For additional help go to https://clever.copterexpress.com/aruco.html --> <!-- For additional help go to https://clever.copterexpress.com/aruco.html -->
@@ -22,11 +22,8 @@
<remap from="markers" to="aruco_detect/markers"/> <remap from="markers" to="aruco_detect/markers"/>
<param name="map" value="$(find aruco_pose)/map/map.txt"/> <param name="map" value="$(find aruco_pose)/map/map.txt"/>
<param name="known_tilt" value="map"/> <param name="known_tilt" value="map"/>
<param name="image_axis" value="true"/>
<param name="frame_id" value="aruco_map_detected" if="$(arg aruco_vpe)"/> <param name="frame_id" value="aruco_map_detected" if="$(arg aruco_vpe)"/>
<param name="frame_id" value="aruco_map" unless="$(arg aruco_vpe)"/> <param name="frame_id" value="aruco_map" unless="$(arg aruco_vpe)"/>
<param name="markers/frame_id" value="aruco_map"/>
<param name="markers/child_frame_id_prefix" value="aruco_"/>
</node> </node>
<!-- vpe publisher from aruco markers --> <!-- vpe publisher from aruco markers -->

View File

@@ -5,10 +5,11 @@
<arg name="web_video_server" default="true"/> <arg name="web_video_server" default="true"/>
<arg name="rosbridge" default="true"/> <arg name="rosbridge" default="true"/>
<arg name="main_camera" default="true"/> <arg name="main_camera" default="true"/>
<arg name="optical_flow" default="false"/> <arg name="optical_flow" default="true"/>
<arg name="aruco" default="false"/> <arg name="aruco" default="true"/>
<arg name="rc" default="true"/> <arg name="rc" default="false"/>
<arg name="rangefinder_vl53l1x" default="false"/> <arg name="rangefinder_vl53l1x" default="true"/>
<arg name="arduino" default="false"/>
<!-- mavros --> <!-- mavros -->
<include file="$(find clever)/launch/mavros.launch"> <include file="$(find clever)/launch/mavros.launch">
@@ -20,7 +21,6 @@
<!-- web video server --> <!-- web video server -->
<node name="web_video_server" pkg="web_video_server" type="web_video_server" if="$(arg web_video_server)" required="false" respawn="true" respawn_delay="5"> <node name="web_video_server" pkg="web_video_server" type="web_video_server" if="$(arg web_video_server)" required="false" respawn="true" respawn_delay="5">
<param name="default_stream_type" value="ros_compressed"/> <param name="default_stream_type" value="ros_compressed"/>
<param name="publish_rate" value="1.0"/>
</node> </node>
<!-- aruco markers --> <!-- aruco markers -->
@@ -46,6 +46,11 @@
<param name="reference_frames/base_link" value="map"/> <param name="reference_frames/base_link" value="map"/>
</node> </node>
<!-- Auxiliary frames -->
<node name="frames" pkg="clever" type="frames" output="screen">
<param name="body/frame_id" value="body"/>
</node>
<!-- main camera --> <!-- main camera -->
<include file="$(find clever)/launch/main_camera.launch" if="$(arg main_camera)"/> <include file="$(find clever)/launch/main_camera.launch" if="$(arg main_camera)"/>
@@ -58,9 +63,15 @@
<!-- vl53l1x ToF rangefinder --> <!-- vl53l1x ToF rangefinder -->
<node name="vl53l1x" pkg="vl53l1x" type="vl53l1x_node" output="screen" if="$(arg rangefinder_vl53l1x)"> <node name="vl53l1x" pkg="vl53l1x" type="vl53l1x_node" output="screen" if="$(arg rangefinder_vl53l1x)">
<param name="frame_id" value="rangefinder"/> <param name="frame_id" value="rangefinder"/>
<param name="offset" value="-0.05"/>
<remap from="~range" to="mavros/distance_sensor/rangefinder_sub"/> <!-- redirect data to FCU --> <remap from="~range" to="mavros/distance_sensor/rangefinder_sub"/> <!-- redirect data to FCU -->
</node> </node>
<!-- rc backend --> <!-- rc backend -->
<node name="rc" pkg="clever" type="rc" output="screen" if="$(arg rc)"/> <node name="rc" pkg="clever" type="rc" output="screen" if="$(arg rc)"/>
<!-- Arduino bridge -->
<node pkg="rosserial_python" type="serial_node.py" name="serial_node" output="screen" if="$(arg arduino)">
<param name="port" value="/dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0"/>
</node>
</launch> </launch>

View File

@@ -5,10 +5,10 @@
<!-- article about camera setup: https://clever.copterexpress.com/camera_frame.html --> <!-- article about camera setup: https://clever.copterexpress.com/camera_frame.html -->
<!-- camera is oriented downward, camera cable goes backward [option 1] --> <!-- camera is oriented downward, camera cable goes backward [option 1] -->
<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/> <!-- <node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/> -->
<!-- camera is oriented downward, camera cable goes forward [option 2] --> <!-- camera is oriented downward, camera cable goes forward [option 2] -->
<!--<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 1.5707963 0 3.1415926 base_link main_camera_optical"/>--> <node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="-0.04 0 -0.08 1.5707963 0 3.1415926 base_link main_camera_optical"/>
<!-- camera is oriented upward, camera cable goes backward [option 3] --> <!-- camera is oriented upward, camera cable goes backward [option 3] -->
<!--<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 0.07 1.5707963 0 0 base_link main_camera_optical"/>--> <!--<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 0.07 1.5707963 0 0 base_link main_camera_optical"/>-->
@@ -24,7 +24,6 @@
<param name="rate" value="100"/> <!-- poll rate --> <param name="rate" value="100"/> <!-- poll rate -->
<param name="cv_cap_prop_fps" value="40"/> <!-- camera FPS --> <param name="cv_cap_prop_fps" value="40"/> <!-- camera FPS -->
<param name="capture_delay" value="0.02"/> <!-- approximate delay on frame retrieving --> <param name="capture_delay" value="0.02"/> <!-- approximate delay on frame retrieving -->
<param name="rescale_camera_info" value="true"/> <!-- automatically rescale camera calibration info -->
<!-- camera resolution, NOTE: camera_info file should match it --> <!-- camera resolution, NOTE: camera_info file should match it -->
<param name="image_width" value="320"/> <param name="image_width" value="320"/>

View File

@@ -56,7 +56,7 @@
<node pkg="tf2_ros" type="static_transform_publisher" name="rangefinder_frame" args="0 0 -0.05 0 1.5707963268 0 base_link rangefinder"/> <node pkg="tf2_ros" type="static_transform_publisher" name="rangefinder_frame" args="0 0 -0.05 0 1.5707963268 0 base_link rangefinder"/>
<!-- Copter visualization --> <!-- Copter visualization -->
<node name="visualization" pkg="mavros_extras" type="visualization" if="$(arg viz)"> <node name="copter_visualization" pkg="mavros_extras" type="copter_visualization" if="$(arg viz)">
<remap to="mavros/local_position/pose" from="local_position"/> <remap to="mavros/local_position/pose" from="local_position"/>
<remap to="mavros/setpoint_position/local" from="local_setpoint"/> <remap to="mavros/setpoint_position/local" from="local_setpoint"/>
<param name="fixed_frame_id" value="map"/> <param name="fixed_frame_id" value="map"/>

View File

@@ -30,14 +30,13 @@
<depend>nodelet</depend> <depend>nodelet</depend>
<depend>mavros</depend> <depend>mavros</depend>
<depend>mavros_extras</depend> <depend>mavros_extras</depend>
<depend>lxml</depend>
<depend>cv_camera</depend> <depend>cv_camera</depend>
<depend>cv_bridge</depend> <depend>cv_bridge</depend>
<depend>opencv3</depend> <depend>opencv3</depend>
<depend>mjpg-streamer</depend>
<depend>rosbridge_server</depend> <depend>rosbridge_server</depend>
<depend>web_video_server</depend> <depend>web_video_server</depend>
<depend>tf2_web_republisher</depend>
<depend>python-lxml</depend>
<exec_depend>python-pymavlink</exec_depend>
<!-- Use test_depend for packages you need only for testing: --> <!-- Use test_depend for packages you need only for testing: -->
<!-- <test_depend>gtest</test_depend> --> <!-- <test_depend>gtest</test_depend> -->

View File

@@ -1,5 +1,6 @@
flask==1.1.1 flask==0.12.3
docopt==0.6.2 docopt==0.6.2
geopy==1.11.0 geopy==1.11.0
pymavlink==2.2.10
smbus2==0.2.1 smbus2==0.2.1
VL53L1X==0.0.2 VL53L1X==0.0.2

63
clever/src/frames.cpp Normal file
View File

@@ -0,0 +1,63 @@
/*
* Auxiliary TF frames for CLEVER drone kit:
* - Body frame (drone body with zero pitch and roll).
* - TODO: REP-0105 `odom` frame emulation: continuous frame without discrete jumps.
* - TODO: Terrain frame (base on ALTITUDE message).
* - TODO: map_upside_down frame
* - TODO: home frame?
*
* Copyright (C) 2018 Copter Express Technologies
*
* Author: Oleg Kalachev <okalachev@gmail.com>
*
* Distributed under MIT License (available at https://opensource.org/licenses/MIT).
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/
// TODO: consider implementing as a mavros plugin
#include <string>
#include <memory>
#include <ros/ros.h>
#include <tf/transform_datatypes.h>
#include <tf2_ros/transform_broadcaster.h>
#include <geometry_msgs/TransformStamped.h>
#include <geometry_msgs/PoseStamped.h>
using std::string;
static std::shared_ptr<tf2_ros::TransformBroadcaster> br;
static geometry_msgs::TransformStamped body;
inline void publishBody(const geometry_msgs::PoseStamped& pose)
{
// Get only yaw from pose
tf::Quaternion q;
q.setRPY(0, 0, tf::getYaw(pose.pose.orientation));
tf::quaternionTFToMsg(q, body.transform.rotation);
body.transform.translation.x = pose.pose.position.x;
body.transform.translation.y = pose.pose.position.y;
body.transform.translation.z = pose.pose.position.z;
body.header.frame_id = pose.header.frame_id;
body.header.stamp = pose.header.stamp;
br->sendTransform(body);
}
void poseCallback(const geometry_msgs::PoseStamped& pose)
{
publishBody(pose);
}
int main(int argc, char **argv) {
ros::init(argc, argv, "frames");
ros::NodeHandle nh, nh_priv("~");
nh_priv.param<string>("body/frame_id", body.child_frame_id, "body");
br = std::make_shared<tf2_ros::TransformBroadcaster>();
ros::Subscriber pose_sub = nh.subscribe("mavros/local_position/pose", 1, &poseCallback);
ROS_INFO("frames: ready");
ros::spin();
}

View File

@@ -1,36 +1,21 @@
#!/usr/bin/env python #!/usr/bin/env python
# coding=utf-8
# Copyright (C) 2018 Copter Express Technologies
#
# Author: Oleg Kalachev <okalachev@gmail.com>
#
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
import math import math
import subprocess from subprocess import Popen, PIPE
import re import re
import traceback import traceback
from threading import Event
import numpy
import rospy import rospy
from systemd import journal
import tf2_ros
import tf2_geometry_msgs
from pymavlink import mavutil
from std_srvs.srv import Trigger from std_srvs.srv import Trigger
from sensor_msgs.msg import Image, CameraInfo, NavSatFix, Imu, Range from sensor_msgs.msg import Image, CameraInfo, NavSatFix, Imu, Range
from mavros_msgs.msg import State, OpticalFlowRad, Mavlink from mavros_msgs.msg import State, OpticalFlowRad
from mavros_msgs.srv import ParamGet from mavros_msgs.srv import ParamGet
from geometry_msgs.msg import PoseStamped, TwistStamped, PoseWithCovarianceStamped, Vector3Stamped from geometry_msgs.msg import PoseStamped, TwistStamped, PoseWithCovarianceStamped
from visualization_msgs.msg import MarkerArray as VisualizationMarkerArray
import tf.transformations as t import tf.transformations as t
from aruco_pose.msg import MarkerArray from aruco_pose.msg import MarkerArray
from mavros import mavlink
# TODO: roscore is running
# TODO: clever.service is running
# TODO: check attitude is present # TODO: check attitude is present
# TODO: disk free space # TODO: disk free space
# TODO: map, base_link, body # TODO: map, base_link, body
@@ -43,41 +28,28 @@ from mavros import mavlink
rospy.init_node('selfcheck') rospy.init_node('selfcheck')
tf_buffer = tf2_ros.Buffer()
tf_listener = tf2_ros.TransformListener(tf_buffer)
failures = [] failures = []
infos = []
current_check = None
def failure(text, *args): def failure(text, *args):
msg = text % args failures.append(text % args)
rospy.logwarn('%s: %s', current_check, msg)
failures.append(msg)
def info(text, *args):
msg = text % args
rospy.loginfo('%s: %s', current_check, msg)
infos.append(msg)
def check(name): def check(name):
def inner(fn): def inner(fn):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
failures[:] = [] failures[:] = []
infos[:] = []
global current_check
current_check = name
try: try:
fn(*args, **kwargs) fn(*args, **kwargs)
for f in failures:
rospy.logwarn('%s: %s', name, f)
except Exception as e: except Exception as e:
for f in failures:
rospy.logwarn('%s: %s', name, f)
traceback.print_exc() traceback.print_exc()
rospy.logerr('%s: exception occurred', name) rospy.logwarn('%s: exception occurred', name)
return return
if not failures and not infos: if not failures:
rospy.loginfo('%s: OK', name) rospy.loginfo('%s: OK', name)
return wrapper return wrapper
return inner return inner
@@ -87,12 +59,7 @@ param_get = rospy.ServiceProxy('mavros/param/get', ParamGet)
def get_param(name): def get_param(name):
try: res = param_get(param_id=name)
res = param_get(param_id=name)
except rospy.ServiceException as e:
failure('%s: %s', name, str(e))
return None
if not res.success: if not res.success:
failure('Unable to retrieve PX4 parameter %s', name) failure('Unable to retrieve PX4 parameter %s', name)
else: else:
@@ -101,162 +68,36 @@ def get_param(name):
return res.value.real return res.value.real
recv_event = Event()
link = mavutil.mavlink.MAVLink('', 255, 1)
mavlink_pub = rospy.Publisher('mavlink/to', Mavlink, queue_size=1)
mavlink_recv = ''
def mavlink_message_handler(msg):
global mavlink_recv
if msg.msgid == 126:
mav_bytes_msg = mavlink.convert_to_bytes(msg)
mav_msg = link.decode(mav_bytes_msg)
mavlink_recv += ''.join(chr(x) for x in mav_msg.data[:mav_msg.count])
if 'nsh>' in mavlink_recv:
# Remove the last line, including newline before prompt
mavlink_recv = mavlink_recv[:mavlink_recv.find('nsh>') - 1]
recv_event.set()
mavlink_sub = rospy.Subscriber('mavlink/from', Mavlink, mavlink_message_handler)
# FIXME: not sleeping here still breaks things
rospy.sleep(0.5)
def mavlink_exec(cmd, timeout=3.0):
global mavlink_recv
mavlink_recv = ''
recv_event.clear()
if not cmd.endswith('\n'):
cmd += '\n'
msg = mavutil.mavlink.MAVLink_serial_control_message(
device=mavutil.mavlink.SERIAL_CONTROL_DEV_SHELL,
flags=mavutil.mavlink.SERIAL_CONTROL_FLAG_RESPOND | mavutil.mavlink.SERIAL_CONTROL_FLAG_EXCLUSIVE |
mavutil.mavlink.SERIAL_CONTROL_FLAG_MULTI,
timeout=3,
baudrate=0,
count=len(cmd),
data=map(ord, cmd.ljust(70, '\0')))
msg.pack(link)
ros_msg = mavlink.convert_to_rosmsg(msg)
mavlink_pub.publish(ros_msg)
recv_event.wait(timeout)
return mavlink_recv
BOARD_ROTATIONS = {
0: 'no rotation',
1: 'yaw 45°',
2: 'yaw 90°',
3: 'yaw 135°',
4: 'yaw 180°',
5: 'yaw 225°',
6: 'yaw 270°',
7: 'yaw 315°',
8: 'roll 180°',
9: 'roll 180°, yaw 45°',
10: 'roll 180°, yaw 90°',
11: 'roll 180°, yaw 135°',
12: 'pitch 180°',
13: 'roll 180°, yaw 225°',
14: 'roll 180°, yaw 270°',
15: 'roll 180°, yaw 315°',
16: 'roll 90°',
17: 'roll 90°, yaw 45°',
18: 'roll 90°, yaw 90°',
19: 'roll 90°, yaw 135°',
20: 'roll 270°',
21: 'roll 270°, yaw 45°',
22: 'roll 270°, yaw 90°',
23: 'roll 270°, yaw 135°',
24: 'pitch 90°',
25: 'pitch 270°',
26: 'roll 270°, yaw 270°',
27: 'roll 180°, pitch 270°',
28: 'pitch 90°, yaw 180',
29: 'pitch 90°, roll 90°',
30: 'yaw 293°, pitch 68°, roll 90°',
31: 'pitch 90°, roll 270°',
32: 'pitch 9°, yaw 180°',
33: 'pitch 45°',
34: 'pitch 315°',
}
@check('FCU') @check('FCU')
def check_fcu(): def check_fcu():
try: try:
state = rospy.wait_for_message('mavros/state', State, timeout=3) state = rospy.wait_for_message('mavros/state', State, timeout=3)
if not state.connected: if not state.connected:
failure('no connection to the FCU (check wiring)') failure('no connection to the FCU (check wiring)')
return
# Make sure the console is available to us
mavlink_exec('\n')
version_str = mavlink_exec('ver all')
if version_str == '':
info('no version data available from SITL')
r = re.compile(r'^FW (git tag|version): (v?\d\.\d\.\d.*)$')
is_clever_firmware = False
for ver_line in version_str.split('\n'):
match = r.search(ver_line)
if match is not None:
field, version = match.groups()
info('firmware %s: %s' % (field, version))
if 'clever' in version:
is_clever_firmware = True
if not is_clever_firmware:
failure('not running Clever PX4 firmware, check http://clever.copterexpress.com/firmware.html')
est = get_param('SYS_MC_EST_GROUP') est = get_param('SYS_MC_EST_GROUP')
if est == 1: if est == 1:
info('selected estimator: LPE') rospy.loginfo('Selected estimator: LPE')
fuse = get_param('LPE_FUSION') fuse = get_param('LPE_FUSION')
if fuse & (1 << 4): if fuse & (1 << 4):
info('LPE_FUSION: land detector fusion is enabled') rospy.loginfo('LPE_FUSION: land detector fusion is enabled')
else: else:
info('LPE_FUSION: land detector fusion is disabled') rospy.loginfo('LPE_FUSION: land detector fusion is disabled')
if fuse & (1 << 7): if fuse & (1 << 7):
info('LPE_FUSION: barometer fusion is enabled') rospy.loginfo('LPE_FUSION: barometer fusion is enabled')
else: else:
info('LPE_FUSION: barometer fusion is disabled') rospy.loginfo('LPE_FUSION: barometer fusion is disabled')
elif est == 2: elif est == 2:
info('selected estimator: EKF2') rospy.loginfo('Selected estimator: EKF2')
else: else:
failure('unknown selected estimator: %s', est) failure('Unknown selected estimator: %s', est)
rot = get_param('SENS_BOARD_ROT')
if rot is not None:
try:
info('board rotation: %s', BOARD_ROTATIONS[rot])
except KeyError:
failure('unknown board rotation %s', rot)
except rospy.ROSException: except rospy.ROSException:
failure('no MAVROS state (check wiring)') failure('no MAVROS state (check wiring)')
def describe_direction(v): @check('Camera')
if v.x > 0.9:
return 'forward'
elif v.x < - 0.9:
return 'backward'
elif v.y > 0.9:
return 'left'
elif v.y < -0.9:
return 'right'
elif v.z > 0.9:
return 'upward'
elif v.z < -0.9:
return 'downward'
else:
return None
def check_camera(name): def check_camera(name):
try: try:
img = rospy.wait_for_message(name + '/image_raw', Image, timeout=1) img = rospy.wait_for_message(name + '/image_raw', Image, timeout=1)
@@ -264,98 +105,32 @@ def check_camera(name):
failure('%s: no images (is the camera connected properly?)', name) failure('%s: no images (is the camera connected properly?)', name)
return return
try: try:
camera_info = rospy.wait_for_message(name + '/camera_info', CameraInfo, timeout=1) info = rospy.wait_for_message(name + '/camera_info', CameraInfo, timeout=1)
except rospy.ROSException: except rospy.ROSException:
failure('%s: no calibration info', name) failure('%s: no calibration info', name)
return return
if img.width != camera_info.width: if img.width != info.width:
failure('%s: calibration width doesn\'t match image width (%d != %d)', name, camera_info.width, img.width) failure('%s: calibration width doesn\'t match image width (%d != %d)', name, info.width, img.width)
if img.height != camera_info.height: if img.height != info.height:
failure('%s: calibration height doesn\'t match image height (%d != %d))', name, camera_info.height, img.height) failure('%s: calibration height doesn\'t match image height (%d != %d))', name, info.height, img.height)
try:
optical = Vector3Stamped()
optical.header.frame_id = img.header.frame_id
optical.vector.z = 1
cable = Vector3Stamped()
cable.header.frame_id = img.header.frame_id
cable.vector.y = 1
optical = describe_direction(tf_buffer.transform(optical, 'base_link').vector)
cable = describe_direction(tf_buffer.transform(cable, 'base_link').vector)
if not optical or not cable:
info('%s: custom camera orientation detected', name)
else:
info('camera is oriented %s, camera cable goes %s', optical, cable)
except tf2_ros.TransformException:
failure('cannot transform from base_link to camera frame')
@check('Main camera') @check('ArUco detector')
def check_main_camera():
check_camera('main_camera')
def is_process_running(binary, exact=False, full=False):
try:
args = ['pgrep']
if exact:
args.append('-x') # match exactly with the command name
if full:
args.append('-f') # use full process name to match
args.append(binary)
subprocess.check_output(args)
return True
except subprocess.CalledProcessError:
return False
@check('ArUco markers')
def check_aruco(): def check_aruco():
if is_process_running('aruco_detect', full=True): try:
info('aruco_detect/length = %g m', rospy.get_param('aruco_detect/length')) rospy.wait_for_message('aruco_detect/markers', MarkerArray, timeout=1)
known_tilt = rospy.get_param('aruco_detect/known_tilt') except rospy.ROSException:
if known_tilt == 'map': failure('no markers detection')
known_tilt += ' (ALL markers are on the floor)'
elif known_tilt == 'map_flipped':
known_tilt += ' (ALL markers are on the ceiling)'
info('aruco_detector/known_tilt = %s', known_tilt)
try:
rospy.wait_for_message('aruco_detect/markers', MarkerArray, timeout=1)
except rospy.ROSException:
failure('no markers detection')
return
else:
info('aruco_detect is not running')
return return
try:
if is_process_running('aruco_map', full=True): rospy.wait_for_message('aruco_map/pose', PoseWithCovarianceStamped, timeout=1)
known_tilt = rospy.get_param('aruco_map/known_tilt') except rospy.ROSException:
if known_tilt == 'map': failure('no map detection')
known_tilt += ' (marker\'s map is on the floor)'
elif known_tilt == 'map_flipped':
known_tilt += ' (marker\'s map is on the ceiling)'
info('aruco_map/known_tilt = %s', known_tilt)
try:
visualization = rospy.wait_for_message('aruco_map/visualization', VisualizationMarkerArray, timeout=1)
info('map has %s markers', len(visualization.markers))
except:
failure('cannot read aruco_map/visualization topic')
try:
rospy.wait_for_message('aruco_map/pose', PoseWithCovarianceStamped, timeout=1)
except rospy.ROSException:
failure('no map detection')
else:
info('aruco_map is not running')
@check('Vision position estimate') @check('Vision position estimate')
def check_vpe(): def check_vpe():
vis = None
try: try:
vis = rospy.wait_for_message('mavros/vision_pose/pose', PoseStamped, timeout=1) vis = rospy.wait_for_message('mavros/vision_pose/pose', PoseStamped, timeout=1)
except rospy.ROSException: except rospy.ROSException:
@@ -363,11 +138,7 @@ def check_vpe():
vis = rospy.wait_for_message('mavros/mocap/pose', PoseStamped, timeout=1) vis = rospy.wait_for_message('mavros/mocap/pose', PoseStamped, timeout=1)
except rospy.ROSException: except rospy.ROSException:
failure('no VPE or MoCap messages') failure('no VPE or MoCap messages')
# check if vpe_publisher is running return
try:
subprocess.check_output(['pgrep', '-x', 'vpe_publisher'])
except subprocess.CalledProcessError:
return # it's not running, skip following checks
# check PX4 settings # check PX4 settings
est = get_param('SYS_MC_EST_GROUP') est = get_param('SYS_MC_EST_GROUP')
@@ -379,30 +150,27 @@ def check_vpe():
if vision_yaw_w == 0: if vision_yaw_w == 0:
failure('vision yaw weight is zero, change ATT_W_EXT_HDG parameter') failure('vision yaw weight is zero, change ATT_W_EXT_HDG parameter')
else: else:
info('Vision yaw weight: %.2f', vision_yaw_w) rospy.loginfo('Vision yaw weight: %.2f', vision_yaw_w)
fuse = get_param('LPE_FUSION') fuse = get_param('LPE_FUSION')
if not fuse & (1 << 2): if not fuse & (1 << 2):
failure('vision position fusion is disabled, change LPE_FUSION parameter') failure('vision position fusing is disabled, change LPE_FUSION parameter')
delay = get_param('LPE_VIS_DELAY') delay = get_param('LPE_VIS_DELAY')
if delay != 0: if delay != 0:
failure('LPE_VIS_DELAY parameter is %s, but it should be zero', delay) failure('LPE_VIS_DELAY parameter is %s, but it should be zero', delay)
info('LPE_VIS_XY is %.2f m, LPE_VIS_Z is %.2f m', get_param('LPE_VIS_XY'), get_param('LPE_VIS_Z')) rospy.loginfo('LPE_VIS_XY is %.2f m, LPE_VIS_Z is %.2f m', get_param('LPE_VIS_XY'), get_param('LPE_VIS_Z'))
elif est == 2: elif est == 2:
fuse = get_param('EKF2_AID_MASK') fuse = get_param('EKF2_AID_MASK')
if not fuse & (1 << 3): if not fuse & (1 << 3):
failure('vision position fusion is disabled, change EKF2_AID_MASK parameter') failure('vision position fusing is disabled, change EKF2_AID_MASK parameter')
if not fuse & (1 << 4): if not fuse & (1 << 4):
failure('vision yaw fusion is disabled, change EKF2_AID_MASK parameter') failure('vision yaw fusing is disabled, change EKF2_AID_MASK parameter')
delay = get_param('EKF2_EV_DELAY') delay = get_param('EKF2_EV_DELAY')
if delay != 0: if delay != 0:
failure('EKF2_EV_DELAY is %.2f, but it should be zero', delay) failure('EKF2_EV_DELAY is %.2f, but it should be zero', delay)
info('EKF2_EVA_NOISE is %.3f, EKF2_EVP_NOISE is %.3f', rospy.loginfo('EKF2_EVA_NOISE is %.3f, EKF2_EVP_NOISE is %.3f',
get_param('EKF2_EVA_NOISE'), get_param('EKF2_EVA_NOISE'),
get_param('EKF2_EVP_NOISE')) get_param('EKF2_EVP_NOISE'))
if not vis:
return
# check vision pose and estimated pose inconsistency # check vision pose and estimated pose inconsistency
try: try:
pose = rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=1) pose = rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=1)
@@ -472,7 +240,7 @@ def check_velocity():
failure('vertical velocity estimation is %.2f m/s; is copter staying still?' % vert) failure('vertical velocity estimation is %.2f m/s; is copter staying still?' % vert)
angular = velocity.twist.angular angular = velocity.twist.angular
ANGULAR_VELOCITY_LIMIT = 0.1 ANGULAR_VELOCITY_LIMIT = 0.01
if abs(angular.x) > ANGULAR_VELOCITY_LIMIT: if abs(angular.x) > ANGULAR_VELOCITY_LIMIT:
failure('pitch rate estimation is %.2f rad/s (%.2f deg/s); is copter staying still?', failure('pitch rate estimation is %.2f rad/s (%.2f deg/s); is copter staying still?',
angular.x, math.degrees(angular.x)) angular.x, math.degrees(angular.x))
@@ -508,32 +276,32 @@ def check_optical_flow():
if est == 1: if est == 1:
fuse = get_param('LPE_FUSION') fuse = get_param('LPE_FUSION')
if not fuse & (1 << 1): if not fuse & (1 << 1):
failure('optical flow fusion is disabled, change LPE_FUSION parameter') failure('optical flow fusing is disabled, change LPE_FUSION parameter')
if not fuse & (1 << 1): if not fuse & (1 << 1):
failure('flow gyro compensation is disabled, change LPE_FUSION parameter') failure('flow gyro compensation is disabled, change LPE_FUSION parameter')
scale = get_param('LPE_FLW_SCALE') scale = get_param('LPE_FLW_SCALE')
if not numpy.isclose(scale, 1.0): if scale != 0:
failure('LPE_FLW_SCALE parameter is %.2f, but it should be 1.0', scale) failure('LPE_FLW_SCALE parameter is %.2f, but it should be 1.0', scale)
info('LPE_FLW_QMIN is %s, LPE_FLW_R is %.4f, LPE_FLW_RR is %.4f, SENS_FLOW_MINHGT is %.3f, SENS_FLOW_MAXHGT is %.3f', rospy.loginfo('LPE_FLW_QMIN is %s, LPE_FLW_R is %.4f, LPE_FLW_RR is %.4f, SENS_FLOW_MINHGT is %.3f, SENS_FLOW_MAXHGT is %.3f',
get_param('LPE_FLW_QMIN'), get_param('LPE_FLW_QMIN'),
get_param('LPE_FLW_R'), get_param('LPE_FLW_R'),
get_param('LPE_FLW_RR'), get_param('LPE_FLW_RR'),
get_param('SENS_FLOW_MINHGT'), get_param('SENS_FLOW_MINHGT'),
get_param('SENS_FLOW_MAXHGT')) get_param('SENS_FLOW_MAXHGT'))
elif est == 2: elif est == 2:
fuse = get_param('EKF2_AID_MASK') fuse = get_param('EKF2_AID_MASK')
if not fuse & (1 << 1): if not fuse & (1 << 1):
failure('optical flow fusion is disabled, change EKF2_AID_MASK parameter') failure('optical flow fusing is disabled, change EKF2_AID_MASK parameter')
delay = get_param('EKF2_OF_DELAY') delay = get_param('EKF2_OF_DELAY')
if delay != 0: if delay != 0:
failure('EKF2_OF_DELAY is %.2f, but it should be zero', delay) failure('EKF2_OF_DELAY is %.2f, but it should be zero', delay)
info('EKF2_OF_QMIN is %s, EKF2_OF_N_MIN is %.4f, EKF2_OF_N_MAX is %.4f, SENS_FLOW_MINHGT is %.3f, SENS_FLOW_MAXHGT is %.3f', rospy.loginfo('EKF2_OF_QMIN is %s, EKF2_OF_N_MIN is %.4f, EKF2_OF_N_MAX is %.4f, SENS_FLOW_MINHGT is %.3f, SENS_FLOW_MAXHGT is %.3f',
get_param('EKF2_OF_QMIN'), get_param('EKF2_OF_QMIN'),
get_param('EKF2_OF_N_MIN'), get_param('EKF2_OF_N_MIN'),
get_param('EKF2_OF_N_MAX'), get_param('EKF2_OF_N_MAX'),
get_param('SENS_FLOW_MINHGT'), get_param('SENS_FLOW_MINHGT'),
get_param('SENS_FLOW_MAXHGT')) get_param('SENS_FLOW_MAXHGT'))
except rospy.ROSException: except rospy.ROSException:
failure('no optical flow data (from Raspberry)') failure('no optical flow data (from Raspberry)')
@@ -544,13 +312,13 @@ def check_rangefinder():
# TODO: check FPS! # TODO: check FPS!
rng = False rng = False
try: try:
rospy.wait_for_message('mavros/distance_sensor/rangefinder_sub', Range, timeout=4) rospy.wait_for_message('mavros/distance_sensor/rangefinder_sub', Range, timeout=0.5)
rng = True rng = True
except rospy.ROSException: except rospy.ROSException:
failure('no rangefinder data from Raspberry') failure('no rangefinder data from Raspberry')
try: try:
rospy.wait_for_message('mavros/distance_sensor/rangefinder', Range, timeout=4) rospy.wait_for_message('mavros/distance_sensor/rangefinder', Range, timeout=0.5)
rng = True rng = True
except rospy.ROSException: except rospy.ROSException:
failure('no rangefinder data from PX4') failure('no rangefinder data from PX4')
@@ -562,26 +330,28 @@ def check_rangefinder():
if est == 1: if est == 1:
fuse = get_param('LPE_FUSION') fuse = get_param('LPE_FUSION')
if not fuse & (1 << 5): if not fuse & (1 << 5):
info('"pub agl as lpos down" in LPE_FUSION is disabled, NOT operating over flat surface') rospy.loginfo('"pub agl as lpos down" in LPE_FUSION is disabled, NOT operating over flat surface')
else: else:
info('"pub agl as lpos down" in LPE_FUSION is enabled, operating over flat surface') rospy.loginfo('"pub agl as lpos down" in LPE_FUSION is enabled, operating over flat surface')
elif est == 2: elif est == 2:
hgt = get_param('EKF2_HGT_MODE') hgt = get_param('EKF2_HGT_MODE')
if hgt != 2: if hgt != 2:
info('EKF2_HGT_MODE != Range sensor, NOT operating over flat surface') rospy.loginfo('EKF2_HGT_MODE != Range sensor, NOT operating over flat surface')
else: else:
info('EKF2_HGT_MODE = Range sensor, operating over flat surface') rospy.loginfo('EKF2_HGT_MODE = Range sensor, operating over flat surface')
aid = get_param('EKF2_RNG_AID') aid = get_param('EKF2_RNG_AID')
if aid != 1: if aid != 1:
info('EKF2_RNG_AID != 1, range sensor aiding disabled') rospy.loginfo('EKF2_RNG_AID != 1, range sensor aiding disabled')
else: else:
info('EKF2_RNG_AID = 1, range sensor aiding enabled') rospy.loginfo('EKF2_RNG_AID = 1, range sensor aiding enabled')
@check('Boot duration') @check('Boot duration')
def check_boot_duration(): def check_boot_duration():
output = subprocess.check_output('systemd-analyze') proc = Popen('systemd-analyze', stdout=PIPE)
proc.wait()
output = proc.communicate()[0]
r = re.compile(r'([\d\.]+)s$') r = re.compile(r'([\d\.]+)s$')
duration = float(r.search(output).groups()[0]) duration = float(r.search(output).groups()[0])
if duration > 15: if duration > 15:
@@ -592,7 +362,9 @@ def check_boot_duration():
def check_cpu_usage(): def check_cpu_usage():
WHITELIST = 'nodelet', WHITELIST = 'nodelet',
CMD = "top -n 1 -b -i | tail -n +8 | awk '{ printf(\"%-8s\\t%-8s\\t%-8s\\n\", $1, $9, $12); }'" CMD = "top -n 1 -b -i | tail -n +8 | awk '{ printf(\"%-8s\\t%-8s\\t%-8s\\n\", $1, $9, $12); }'"
output = subprocess.check_output(CMD, shell=True) proc = Popen(CMD, stdout=PIPE, shell=True)
proc.wait()
output = proc.communicate()[0]
processes = output.split('\n') processes = output.split('\n')
for process in processes: for process in processes:
if not process: if not process:
@@ -604,77 +376,13 @@ def check_cpu_usage():
cpu.strip(), cmd.strip(), pid.strip()) cpu.strip(), cmd.strip(), pid.strip())
@check('clever.service')
def check_clever_service():
try:
output = subprocess.check_output('systemctl show -p ActiveState --value clever.service'.split(),
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
failure('systemctl returned %s: %s', e.returncode, e.output)
return
if 'inactive' in output:
failure('clever.service is not running, try sudo systemctl restart clever')
return
j = journal.Reader()
j.this_boot()
j.add_match(_SYSTEMD_UNIT='clever.service')
j.add_disjunction()
j.add_match(UNIT='clever.service')
node_errors = []
r = re.compile(r'^(.*)\[(FATAL|ERROR)\] \[\d+.\d+\]: (.*)$')
for event in j:
msg = event['MESSAGE']
if ('Stopped Clever ROS package' in msg) or ('Started Clever ROS package' in msg):
node_errors = []
elif ('[ERROR]' in msg) or ('[FATAL]' in msg):
msg = r.search(msg).groups()[2]
if msg in node_errors:
continue
node_errors.append(msg)
for error in node_errors:
failure(error)
@check('Image')
def check_image():
try:
info('version: %s', open('/etc/clever_version').read().strip())
except IOError:
info('no /etc/clever_version file, not the Clever image?')
@check('Preflight status')
def check_preflight_status():
# Make sure the console is available to us
mavlink_exec('\n')
cmdr_output = mavlink_exec('commander check')
if cmdr_output == '':
failure('no data from FCU')
return
cmdr_lines = cmdr_output.split('\n')
r = re.compile(r'^(.*)(Preflight|Prearm) check: (.*)')
for line in cmdr_lines:
if 'WARN' in line:
failure(line[line.find(']') + 2:])
continue
match = r.search(line)
if match is not None:
check_status = match.groups()[2]
if check_status != 'OK':
failure(' '.join([match.groups()[1], 'check:', check_status]))
def selfcheck(): def selfcheck():
check_image()
check_clever_service()
check_fcu() check_fcu()
check_imu() check_imu()
check_local_position() check_local_position()
check_velocity() check_velocity()
check_global_position() check_global_position()
check_preflight_status() check_camera('main_camera')
check_main_camera()
check_aruco() check_aruco()
check_simpleoffboard() check_simpleoffboard()
check_optical_flow() check_optical_flow()

View File

@@ -54,7 +54,6 @@ using mavros_msgs::Thrust;
// tf2 // tf2
tf2_ros::Buffer tf_buffer; tf2_ros::Buffer tf_buffer;
std::shared_ptr<tf2_ros::TransformBroadcaster> transform_broadcaster;
// Parameters // Parameters
string local_frame; string local_frame;
@@ -71,7 +70,6 @@ ros::Duration global_position_timeout;
ros::Duration battery_timeout; ros::Duration battery_timeout;
float default_speed; float default_speed;
bool auto_release; bool auto_release;
bool land_only_in_offboard;
std::map<string, string> reference_frames; std::map<string, string> reference_frames;
// Publishers // Publishers
@@ -89,7 +87,6 @@ AttitudeTarget att_raw_msg;
Thrust thrust_msg; Thrust thrust_msg;
TwistStamped rates_msg; TwistStamped rates_msg;
TransformStamped target; TransformStamped target;
geometry_msgs::TransformStamped body;
// State // State
PoseStamped nav_start; PoseStamped nav_start;
@@ -123,41 +120,18 @@ TwistStamped velocity;
NavSatFix global_position; NavSatFix global_position;
BatteryState battery; BatteryState battery;
// Common subscriber callback template that stores message to the variable // Common subcriber callback template that stores message to the variable
template<typename T, T& STORAGE> template<typename T, T& STORAGE>
void handleMessage(const T& msg) void handleMessage(const T& msg)
{ {
STORAGE = msg; STORAGE = msg;
} }
inline void publishBodyFrame()
{
if (body.child_frame_id.empty()) return;
tf::Quaternion q;
q.setRPY(0, 0, tf::getYaw(local_position.pose.orientation));
tf::quaternionTFToMsg(q, body.transform.rotation);
body.transform.translation.x = local_position.pose.position.x;
body.transform.translation.y = local_position.pose.position.y;
body.transform.translation.z = local_position.pose.position.z;
body.header.frame_id = local_position.header.frame_id;
body.header.stamp = local_position.header.stamp;
transform_broadcaster->sendTransform(body);
}
void handleLocalPosition(const PoseStamped& pose)
{
local_position = pose;
publishBodyFrame();
// TODO: terrain?, home?
}
// wait for transform without interrupting publishing setpoints // wait for transform without interrupting publishing setpoints
inline bool waitTransform(const string& target, const string& source, inline bool waitTransform(const string& target, const string& source,
const ros::Time& stamp, const ros::Duration& timeout) // editorconfig-checker-disable-line const ros::Time& stamp, const ros::Duration& timeout)
{ {
ros::Rate r(100); ros::Rate r(10);
auto start = ros::Time::now(); auto start = ros::Time::now();
while (ros::ok()) { while (ros::ok()) {
if (ros::Time::now() - start > timeout) return false; if (ros::Time::now() - start > timeout) return false;
@@ -201,29 +175,31 @@ bool getTelemetry(GetTelemetry::Request& req, GetTelemetry::Response& res)
res.mode = state.mode; res.mode = state.mode;
} }
try { waitTransform(local_frame, req.frame_id, stamp, telemetry_transform_timeout);
waitTransform(req.frame_id, fcu_frame, stamp, telemetry_transform_timeout);
auto transform = tf_buffer.lookupTransform(req.frame_id, fcu_frame, stamp);
res.x = transform.transform.translation.x;
res.y = transform.transform.translation.y;
res.z = transform.transform.translation.z;
double yaw, pitch, roll; if (!TIMEOUT(local_position, local_position_timeout)) {
tf2::getEulerYPR(transform.transform.rotation, yaw, pitch, roll); try {
res.yaw = yaw; // transform pose
res.pitch = pitch; PoseStamped pose;
res.roll = roll; tf_buffer.transform(local_position, pose, req.frame_id);
} catch (const tf2::TransformException& e) { res.x = pose.pose.position.x;
ROS_DEBUG("simple_offboard: %s", e.what()); res.y = pose.pose.position.y;
res.z = pose.pose.position.z;
// Tait-Bryan angles, order z-y-x
double yaw, pitch, roll;
tf2::getEulerYPR(pose.pose.orientation, yaw, pitch, roll);
res.yaw = yaw;
res.pitch = pitch;
res.roll = roll;
} catch (const tf2::TransformException& e) {}
} }
if (!TIMEOUT(velocity, velocity_timeout)) { if (!TIMEOUT(velocity, velocity_timeout)) {
try { try {
// transform velocity // transform velocity
waitTransform(req.frame_id, fcu_frame, velocity.header.stamp, telemetry_transform_timeout);
Vector3Stamped vec, vec_out; Vector3Stamped vec, vec_out;
vec.header.stamp = velocity.header.stamp; vec.header = velocity.header;
vec.header.frame_id = velocity.header.frame_id;
vec.vector = velocity.twist.linear; vec.vector = velocity.twist.linear;
tf_buffer.transform(vec, vec_out, req.frame_id); tf_buffer.transform(vec, vec_out, req.frame_id);
@@ -349,10 +325,6 @@ PoseStamped globalToLocal(double lat, double lon)
x_offset = distance * sin(azimuth_radians); x_offset = distance * sin(azimuth_radians);
y_offset = distance * cos(azimuth_radians); y_offset = distance * cos(azimuth_radians);
if (!waitTransform(local_frame, fcu_frame, global_position.header.stamp, ros::Duration(0.2))) {
throw std::runtime_error("No local position");
}
auto local = tf_buffer.lookupTransform(local_frame, fcu_frame, global_position.header.stamp); auto local = tf_buffer.lookupTransform(local_frame, fcu_frame, global_position.header.stamp);
PoseStamped pose; PoseStamped pose;
@@ -391,12 +363,13 @@ void publish(const ros::Time stamp)
if (!target.child_frame_id.empty()) { if (!target.child_frame_id.empty()) {
if (setpoint_type == NAVIGATE || setpoint_type == NAVIGATE_GLOBAL || setpoint_type == POSITION) { if (setpoint_type == NAVIGATE || setpoint_type == NAVIGATE_GLOBAL || setpoint_type == POSITION) {
static tf2_ros::TransformBroadcaster tf_broadcaster;
target.header = setpoint_position_transformed.header; target.header = setpoint_position_transformed.header;
target.transform.translation.x = setpoint_position_transformed.pose.position.x; target.transform.translation.x = setpoint_position_transformed.pose.position.x;
target.transform.translation.y = setpoint_position_transformed.pose.position.y; target.transform.translation.y = setpoint_position_transformed.pose.position.y;
target.transform.translation.z = setpoint_position_transformed.pose.position.z; target.transform.translation.z = setpoint_position_transformed.pose.position.z;
target.transform.rotation = setpoint_position_transformed.pose.orientation; target.transform.rotation = setpoint_position_transformed.pose.orientation;
transform_broadcaster->sendTransform(target); tf_broadcaster.sendTransform(target);
} }
} }
@@ -481,12 +454,10 @@ inline void checkState()
throw std::runtime_error("No connection to FCU, https://clever.copterexpress.com/connection.html"); throw std::runtime_error("No connection to FCU, https://clever.copterexpress.com/connection.html");
} }
#define ENSURE_FINITE(var) { if (!std::isfinite(var)) throw std::runtime_error(#var " argument cannot be NaN or Inf"); }
bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, float vy, float vz, bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, float vy, float vz,
float pitch, float roll, float yaw, float pitch_rate, float roll_rate, float yaw_rate, // editorconfig-checker-disable-line float pitch, float roll, float yaw, float pitch_rate, float roll_rate, float yaw_rate,
float lat, float lon, float thrust, float speed, string frame_id, bool auto_arm, // editorconfig-checker-disable-line float lat, float lon, float thrust, float speed, string frame_id, bool auto_arm,
uint8_t& success, string& message) // editorconfig-checker-disable-line uint8_t& success, string& message)
{ {
auto stamp = ros::Time::now(); auto stamp = ros::Time::now();
@@ -494,20 +465,6 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
if (busy) if (busy)
throw std::runtime_error("Busy"); throw std::runtime_error("Busy");
ENSURE_FINITE(x);
ENSURE_FINITE(y);
ENSURE_FINITE(z);
ENSURE_FINITE(vx);
ENSURE_FINITE(vy);
ENSURE_FINITE(vz);
ENSURE_FINITE(pitch);
ENSURE_FINITE(roll);
ENSURE_FINITE(pitch_rate);
ENSURE_FINITE(roll_rate);
ENSURE_FINITE(lat);
ENSURE_FINITE(lon);
ENSURE_FINITE(thrust);
busy = true; busy = true;
// Checks // Checks
@@ -557,9 +514,7 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
if (sp_type == NAVIGATE_GLOBAL) { if (sp_type == NAVIGATE_GLOBAL) {
// Calculate x and from lat and lot in request's frame // Calculate x and from lat and lot in request's frame
auto pose_local = globalToLocal(lat, lon); auto xy_in_req_frame = tf_buffer.transform(globalToLocal(lat, lon), frame_id);
pose_local.header.stamp = stamp; // TODO: fix
auto xy_in_req_frame = tf_buffer.transform(pose_local, frame_id);
x = xy_in_req_frame.pose.position.x; x = xy_in_req_frame.pose.position.x;
y = xy_in_req_frame.pose.position.y; y = xy_in_req_frame.pose.position.y;
} }
@@ -689,12 +644,6 @@ bool land(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res)
checkState(); checkState();
if (land_only_in_offboard) {
if (state.mode != "OFFBOARD") {
throw std::runtime_error("Copter is not in OFFBOARD mode");
}
}
static mavros_msgs::SetMode sm; static mavros_msgs::SetMode sm;
sm.request.custom_mode = "AUTO.LAND"; sm.request.custom_mode = "AUTO.LAND";
@@ -733,16 +682,13 @@ int main(int argc, char **argv)
ros::NodeHandle nh, nh_priv("~"); ros::NodeHandle nh, nh_priv("~");
tf2_ros::TransformListener tf_listener(tf_buffer); tf2_ros::TransformListener tf_listener(tf_buffer);
transform_broadcaster = std::make_shared<tf2_ros::TransformBroadcaster>();
// Params // Params
nh.param<string>("mavros/local_position/tf/frame_id", local_frame, "map"); nh.param<string>("mavros/local_position/tf/frame_id", local_frame, "map");
nh.param<string>("mavros/local_position/tf/child_frame_id", fcu_frame, "base_link"); nh.param<string>("mavros/local_position/tf/child_frame_id", fcu_frame, "base_link");
nh_priv.param("target_frame", target.child_frame_id, string("navigate_target")); nh_priv.param("target_frame", target.child_frame_id, string("navigate_target"));
nh_priv.param("auto_release", auto_release, true); nh_priv.param("auto_release", auto_release, true);
nh_priv.param("land_only_in_offboard", land_only_in_offboard, true);
nh_priv.param("default_speed", default_speed, 0.5f); nh_priv.param("default_speed", default_speed, 0.5f);
nh_priv.param<string>("body_frame", body.child_frame_id, "body");
nh_priv.getParam("reference_frames", reference_frames); nh_priv.getParam("reference_frames", reference_frames);
state_timeout = ros::Duration(nh_priv.param("state_timeout", 3.0)); state_timeout = ros::Duration(nh_priv.param("state_timeout", 3.0));
@@ -763,11 +709,11 @@ int main(int argc, char **argv)
// Telemetry subscribers // Telemetry subscribers
auto state_sub = nh.subscribe("mavros/state", 1, &handleMessage<mavros_msgs::State, state>); auto state_sub = nh.subscribe("mavros/state", 1, &handleMessage<mavros_msgs::State, state>);
auto velocity_sub = nh.subscribe("mavros/local_position/velocity_body", 1, &handleMessage<TwistStamped, velocity>); auto local_position_sub = nh.subscribe("mavros/local_position/pose", 1, &handleMessage<PoseStamped, local_position>);
auto velocity_sub = nh.subscribe("mavros/local_position/velocity", 1, &handleMessage<TwistStamped, velocity>);
auto global_position_sub = nh.subscribe("mavros/global_position/global", 1, &handleMessage<NavSatFix, global_position>); auto global_position_sub = nh.subscribe("mavros/global_position/global", 1, &handleMessage<NavSatFix, global_position>);
auto battery_sub = nh.subscribe("mavros/battery", 1, &handleMessage<BatteryState, battery>); auto battery_sub = nh.subscribe("mavros/battery", 1, &handleMessage<BatteryState, battery>);
auto statustext_sub = nh.subscribe("mavros/statustext/recv", 1, &handleMessage<mavros_msgs::StatusText, statustext>); auto statustext_sub = nh.subscribe("mavros/statustext/recv", 1, &handleMessage<mavros_msgs::StatusText, statustext>);
auto local_position_sub = nh.subscribe("mavros/local_position/pose", 1, &handleLocalPosition);
// Setpoint publishers // Setpoint publishers
position_pub = nh.advertise<PoseStamped>("mavros/setpoint_position/local", 1); position_pub = nh.advertise<PoseStamped>("mavros/setpoint_position/local", 1);

View File

@@ -1,29 +0,0 @@
#!/usr/bin/env python
import rospy
import pytest
from mavros_msgs.msg import State
@pytest.fixture()
def node():
return rospy.init_node('clever_test', anonymous=True)
def test_state(node):
state = rospy.wait_for_message('mavros/state', State, timeout=10)
assert state.connected == False
assert state.armed == False
assert state.guided == False
assert state.mode == ''
def test_simple_offboard_services_available():
rospy.wait_for_service('get_telemetry', timeout=5)
rospy.wait_for_service('navigate', timeout=5)
rospy.wait_for_service('navigate_global', timeout=5)
rospy.wait_for_service('set_position', timeout=5)
rospy.wait_for_service('set_velocity', timeout=5)
rospy.wait_for_service('set_attitude', timeout=5)
rospy.wait_for_service('set_rates', timeout=5)
rospy.wait_for_service('land', timeout=5)
def test_web_video_server(node):
import urllib2
urllib2.urlopen("http://localhost:8080").read()

View File

@@ -1,37 +0,0 @@
<launch>
<!-- Verify all the required nodes basically work -->
<node pkg="mavros" type="mavros_node" name="mavros" required="true" output="screen">
<param name="fcu_url" value="udp://@127.0.1:14557"/>
<rosparam command="load" file="$(find clever)/launch/mavros_config.yaml"/>
</node>
<node name="visualization" pkg="mavros_extras" type="visualization" required="true">
<remap to="mavros/local_position/pose" from="local_position"/>
<remap to="mavros/setpoint_position/local" from="local_setpoint"/>
<param name="fixed_frame_id" value="map"/>
<param name="child_frame_id" value="base_link"/>
<param name="marker_scale" value="1"/>
<param name="max_track_size" value="20"/>
<param name="num_rotors" value="4"/>
</node>
<node name="web_video_server" pkg="web_video_server" type="web_video_server" required="true" output="screen">
<param name="default_stream_type" value="ros_compressed"/>
<param name="publish_rate" value="1.0"/>
</node>
<node pkg="tf2_ros" type="static_transform_publisher" name="map_flipped_frame" args="0 0 0 3.1415926 3.1415926 0 map map_flipped" required="true"/>
<node name="simple_offboard" pkg="clever" type="simple_offboard" required="true" output="screen">
<param name="reference_frames/body" value="map"/>
<param name="reference_frames/base_link" value="map"/>
</node>
<node name="tf2_web_republisher" pkg="tf2_web_republisher" type="tf2_web_republisher" required="true"/>
<node name="rc" pkg="clever" type="rc" required="true" output="screen"/>
<param name="test_module" value="$(find clever)/test/basic.py"/>
<test test-name="basic_test" pkg="ros_pytest" type="ros_pytest_runner"/>
</launch>

View File

@@ -1,197 +0,0 @@
#!/usr/bin/env python
import math
import rospy
import pytest
from pytest import approx
from numpy import isfinite
from geometry_msgs.msg import PoseStamped
from mavros_msgs.msg import State
from sensor_msgs.msg import NavSatFix
from clever import srv
from std_srvs.srv import Trigger
import tf2_ros
import tf2_geometry_msgs
def roughly(expected):
return approx(expected, abs=1e-1)
def very_roughly(expected):
return approx(expected, abs=1)
@pytest.fixture()
def node():
return rospy.init_node('clever_test', anonymous=True)
def wait_service(name, service_class):
res = rospy.ServiceProxy(name, service_class)
res.wait_for_service(5)
return res
@pytest.fixture
def get_telemetry():
return wait_service('get_telemetry', srv.GetTelemetry)
@pytest.fixture
def navigate():
return wait_service('navigate', srv.Navigate)
@pytest.fixture
def navigate():
res = rospy.ServiceProxy('navigate', srv.Navigate)
res.wait_for_service(5)
return res
@pytest.fixture
def land():
return wait_service('land', Trigger)
@pytest.fixture
def tf_buffer():
buf = tf2_ros.Buffer()
tf2_ros.TransformListener(buf)
return buf
def wait_connection():
start = rospy.get_rostime()
while rospy.get_rostime() - start <= rospy.Duration(15):
state = rospy.wait_for_message('mavros/state', State, timeout=10)
if state.connected:
return True
assert False, "no connection to SITL"
def minimal_rate(func, rate):
start = rospy.get_rostime()
i = 0
while rospy.get_rostime() - start <= rospy.Duration(2):
func()
i += 1
result_rate = i / 2
assert result_rate >= rate, 'Rate too low: %s Hz' % result_rate
def test_state_initial(node):
wait_connection()
state = rospy.wait_for_message('mavros/state', State, timeout=10)
assert state.connected == True
assert state.armed == False
def test_telem_initial(node, get_telemetry):
# wait for local position
rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=15)
rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=30)
telem = get_telemetry()
assert telem.frame_id == 'map'
assert telem.connected == True
assert telem.armed == False
assert telem.mode != ''
assert telem.x == roughly(0.0)
assert telem.y == roughly(0.0)
assert telem.z == roughly(0.0)
assert telem.lat == approx(47.397742)
assert telem.lon == approx(8.545594)
assert telem.vx == roughly(0.0)
assert telem.vy == roughly(0.0)
assert telem.vz == roughly(0.0)
assert telem.pitch == roughly(0.0)
assert telem.roll == roughly(0.0)
assert telem.yaw == roughly(1.56)
assert isfinite(telem.voltage)
assert isfinite(telem.cell_voltage)
def test_telem_rate(node, get_telemetry):
minimal_rate(lambda: get_telemetry(), 20)
minimal_rate(lambda: get_telemetry(frame_id='body'), 20)
minimal_rate(lambda: get_telemetry(frame_id='base_link'), 200)
def test_takeoff_without_auto_arm(node, navigate):
res = navigate(z=2, frame_id='body')
assert res.success == False
assert res.message == 'Copter is not in OFFBOARD mode, use auto_arm?'
def test_takeoff(node, navigate, get_telemetry, tf_buffer):
res = navigate(z=2, speed=1, frame_id='body', auto_arm=True)
assert res.success == True, res.message
rospy.sleep(5)
telem = get_telemetry()
assert telem.z == very_roughly(2.0)
assert telem.x == very_roughly(0.0)
assert telem.y == very_roughly(0.0)
assert telem.pitch == roughly(0.0)
assert telem.roll == roughly(0.0)
assert telem.yaw == roughly(1.56)
def test_navigate_nans(node, navigate):
res = navigate(x=float('nan'))
assert res.success == False
assert res.message == 'x argument cannot be NaN or Inf'
res = navigate(y=float('nan'))
assert res.success == False
assert res.message == 'y argument cannot be NaN or Inf'
res = navigate(z=float('nan'))
assert res.success == False
assert res.message == 'z argument cannot be NaN or Inf'
res = navigate(x=float('inf'))
assert res.success == False
assert res.message == 'x argument cannot be NaN or Inf'
res = navigate(y=float('inf'))
assert res.success == False
assert res.message == 'y argument cannot be NaN or Inf'
res = navigate(z=float('inf'))
assert res.success == False
assert res.message == 'z argument cannot be NaN or Inf'
res = navigate(x=float('-inf'))
assert res.success == False
assert res.message == 'x argument cannot be NaN or Inf'
res = navigate(y=float('-inf'))
assert res.success == False
assert res.message == 'y argument cannot be NaN or Inf'
res = navigate(z=float('-inf'))
assert res.success == False
assert res.message == 'z argument cannot be NaN or Inf'
def test_navigate(node, navigate, get_telemetry, tf_buffer):
res = navigate(x=1, y=2, z=3, speed=1)
assert res.success == True, res.message
nav_target = tf_buffer.lookup_transform('map', 'navigate_target', rospy.get_rostime(), rospy.Duration(0.2))
assert nav_target.transform.translation.x == approx(1)
assert nav_target.transform.translation.y == approx(2)
assert nav_target.transform.translation.z == approx(3)
rospy.sleep(10)
telem = get_telemetry()
assert telem.x == very_roughly(1.0)
assert telem.y == very_roughly(2.0)
assert telem.z == very_roughly(3.0)
assert telem.pitch == roughly(0.0)
assert telem.roll == roughly(0.0)
assert telem.yaw == roughly(0.0)
res = navigate(x=-1, y=-2, z=-1, frame_id='body', speed=1)
assert res.success == True, res.message
nav_target = tf_buffer.lookup_transform('map', 'navigate_target', rospy.get_rostime(), rospy.Duration(0.2))
assert nav_target.transform.translation.x == very_roughly(0)
assert nav_target.transform.translation.y == very_roughly(0)
assert nav_target.transform.translation.z == very_roughly(2)
rospy.sleep(10)
telem = get_telemetry()
assert telem.x == very_roughly(0)
assert telem.y == very_roughly(0)
assert telem.z == very_roughly(2)
assert telem.pitch == roughly(0)
assert telem.roll == roughly(0)
assert telem.yaw == roughly(0)
# TODO
# test navigate_global, set_velocity, set_attitude, set_rates
def test_land(node, get_telemetry, land):
res = land()
assert res.success, res.message
telem = get_telemetry()
assert telem.mode == 'AUTO.LAND'
assert telem.armed == True, 'Drone unexpectedly disarmed while landing'
rospy.sleep(12)
telem = get_telemetry()
assert telem.mode == 'AUTO.LAND'
assert telem.armed == False, 'Drone is not disarmed after landing'

View File

@@ -1,20 +0,0 @@
<launch>
<arg name="ip" default="127.0.0.1"/>
<!-- mavros -->
<include file="$(find clever)/launch/mavros.launch">
<arg name="fcu_conn" value="udp"/>
<arg name="fcu_ip" value="$(arg ip)"/>
<arg name="gcs_bridge" value="false"/>
<arg name="viz" value="false"/>
<arg name="respawn" default="false"/>
</include>
<node name="simple_offboard" pkg="clever" type="simple_offboard" required="true" output="screen">
<param name="reference_frames/body" value="map"/>
<param name="reference_frames/base_link" value="map"/>
</node>
<param name="test_module" value="$(find clever)/test/sitl.py"/>
<test test-name="basic_test" pkg="ros_pytest" type="ros_pytest_runner" time-limit="120.0"/>
</launch>

View File

@@ -3,7 +3,7 @@ var titleEl = document.querySelector('title');
var modeEl = document.querySelector('.mode'); var modeEl = document.querySelector('.mode');
var batteryEl = document.querySelector('.battery'); var batteryEl = document.querySelector('.battery');
var url = 'ws://' + location.hostname + ':9090'; var url = 'ws://' + location.host + ':9090';
var ros = new ROSLIB.Ros({ url: url }); var ros = new ROSLIB.Ros({ url: url });
function speak(txt) { function speak(txt) {

View File

@@ -1,5 +1,5 @@
var ros = new ROSLIB.Ros({ var ros = new ROSLIB.Ros({
url : 'ws://' + location.hostname + ':9090' url : 'ws://' + location.host + ':9090'
}); });
var titleEl = document.querySelector('title'); var titleEl = document.querySelector('title');

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

BIN
docs/assets/Clever main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 MiB

View File

@@ -0,0 +1,735 @@
# Onboard parameters for Vehicle 1
#
# Stack: PX4 Pro
# Vehicle: Multi-Rotor
# Version: 1.7.0
# Git Revision: cbdb08bb6109c1ea
#
# Vehicle-Id Component-Id Name Value Type
1 1 ATT_ACC_COMP 1 6
1 1 ATT_BIAS_MAX 0.050000000745058060 9
1 1 ATT_EXT_HDG_M 0 6
1 1 ATT_MAG_DECL 0.000000000000000000 9
1 1 ATT_MAG_DECL_A 1 6
1 1 ATT_W_ACC 0.200000002980232239 9
1 1 ATT_W_EXT_HDG 0.100000001490116119 9
1 1 ATT_W_GYRO_BIAS 0.100000001490116119 9
1 1 ATT_W_MAG 0.100000001490116119 9
1 1 BAT_A_PER_V 15.391030311584472656 9
1 1 BAT_CAPACITY -1.000000000000000000 9
1 1 BAT_CNT_V_CURR 0.000805664050858468 9
1 1 BAT_CNT_V_VOLT 0.000805664050858468 9
1 1 BAT_CRIT_THR 0.070000000298023224 9
1 1 BAT_EMERGEN_THR 0.050000000745058060 9
1 1 BAT_LOW_THR 0.150000005960464478 9
1 1 BAT_N_CELLS 4 6
1 1 BAT_R_INTERNAL -1.000000000000000000 9
1 1 BAT_SOURCE 0 6
1 1 BAT_V_CHARGED 4.199999809265136719 9
1 1 BAT_V_DIV 10.887768745422363281 9
1 1 BAT_V_EMPTY 3.400000095367431641 9
1 1 BAT_V_LOAD_DROP 0.300000011920928955 9
1 1 BAT_V_OFFS_CURR 0.000000000000000000 9
1 1 CAL_ACC0_EN 1 6
1 1 CAL_ACC0_ID 1246218 6
1 1 CAL_ACC0_XOFF 0.081070423126220703 9
1 1 CAL_ACC0_XSCALE 0.996176421642303467 9
1 1 CAL_ACC0_YOFF -0.182177066802978516 9
1 1 CAL_ACC0_YSCALE 1.000774979591369629 9
1 1 CAL_ACC0_ZOFF 0.506614208221435547 9
1 1 CAL_ACC0_ZSCALE 0.991645038127899170 9
1 1 CAL_ACC1_EN 1 6
1 1 CAL_ACC1_ID 1114634 6
1 1 CAL_ACC1_XOFF 0.864228248596191406 9
1 1 CAL_ACC1_XSCALE 1.004844427108764648 9
1 1 CAL_ACC1_YOFF 0.980560302734375000 9
1 1 CAL_ACC1_YSCALE 0.980703771114349365 9
1 1 CAL_ACC1_ZOFF 0.873121738433837891 9
1 1 CAL_ACC1_ZSCALE 0.989114820957183838 9
1 1 CAL_ACC2_XOFF 0.000000000000000000 9
1 1 CAL_ACC2_XSCALE 1.000000000000000000 9
1 1 CAL_ACC2_YOFF 0.000000000000000000 9
1 1 CAL_ACC2_YSCALE 1.000000000000000000 9
1 1 CAL_ACC2_ZOFF 0.000000000000000000 9
1 1 CAL_ACC2_ZSCALE 1.000000000000000000 9
1 1 CAL_AIR_CMODEL 0 6
1 1 CAL_AIR_TUBED_MM 1.500000000000000000 9
1 1 CAL_AIR_TUBELEN 0.200000002980232239 9
1 1 CAL_GYRO0_EN 1 6
1 1 CAL_GYRO0_ID 2163722 6
1 1 CAL_GYRO0_XOFF 0.013700588606297970 9
1 1 CAL_GYRO0_XSCALE 1.000000000000000000 9
1 1 CAL_GYRO0_YOFF 0.049494847655296326 9
1 1 CAL_GYRO0_YSCALE 1.000000000000000000 9
1 1 CAL_GYRO0_ZOFF -0.032555881887674332 9
1 1 CAL_GYRO0_ZSCALE 1.000000000000000000 9
1 1 CAL_GYRO1_EN 1 6
1 1 CAL_GYRO1_ID 2228490 6
1 1 CAL_GYRO1_XOFF -0.007464688271284103 9
1 1 CAL_GYRO1_XSCALE 1.000000000000000000 9
1 1 CAL_GYRO1_YOFF 0.008172192610800266 9
1 1 CAL_GYRO1_YSCALE 1.000000000000000000 9
1 1 CAL_GYRO1_ZOFF -0.010663406923413277 9
1 1 CAL_GYRO1_ZSCALE 1.000000000000000000 9
1 1 CAL_GYRO2_XOFF 0.000000000000000000 9
1 1 CAL_GYRO2_XSCALE 1.000000000000000000 9
1 1 CAL_GYRO2_YOFF 0.000000000000000000 9
1 1 CAL_GYRO2_YSCALE 1.000000000000000000 9
1 1 CAL_GYRO2_ZOFF 0.000000000000000000 9
1 1 CAL_GYRO2_ZSCALE 1.000000000000000000 9
1 1 CAL_MAG0_EN 1 6
1 1 CAL_MAG0_ID 131594 6
1 1 CAL_MAG0_ROT -1 6
1 1 CAL_MAG0_XOFF -0.020210459828376770 9
1 1 CAL_MAG0_XSCALE 1.033145427703857422 9
1 1 CAL_MAG0_YOFF 0.100117556750774384 9
1 1 CAL_MAG0_YSCALE 1.017574071884155273 9
1 1 CAL_MAG0_ZOFF -0.113783776760101318 9
1 1 CAL_MAG0_ZSCALE 0.933741152286529541 9
1 1 CAL_MAG1_ID 0 6
1 1 CAL_MAG1_ROT -1 6
1 1 CAL_MAG1_XOFF 0.000000000000000000 9
1 1 CAL_MAG1_XSCALE 1.000000000000000000 9
1 1 CAL_MAG1_YOFF 0.000000000000000000 9
1 1 CAL_MAG1_YSCALE 1.000000000000000000 9
1 1 CAL_MAG1_ZOFF 0.000000000000000000 9
1 1 CAL_MAG1_ZSCALE 1.000000000000000000 9
1 1 CAL_MAG2_ID 0 6
1 1 CAL_MAG2_ROT -1 6
1 1 CAL_MAG2_XOFF 0.000000000000000000 9
1 1 CAL_MAG2_XSCALE 1.000000000000000000 9
1 1 CAL_MAG2_YOFF 0.000000000000000000 9
1 1 CAL_MAG2_YSCALE 1.000000000000000000 9
1 1 CAL_MAG2_ZOFF 0.000000000000000000 9
1 1 CAL_MAG2_ZSCALE 1.000000000000000000 9
1 1 CAL_MAG3_ID 0 6
1 1 CAL_MAG3_ROT -1 6
1 1 CAL_MAG3_XOFF 0.000000000000000000 9
1 1 CAL_MAG3_XSCALE 1.000000000000000000 9
1 1 CAL_MAG3_YOFF 0.000000000000000000 9
1 1 CAL_MAG3_YSCALE 1.000000000000000000 9
1 1 CAL_MAG3_ZOFF 0.000000000000000000 9
1 1 CAL_MAG3_ZSCALE 1.000000000000000000 9
1 1 CAL_MAG_SIDES 63 6
1 1 CBRK_AIRSPD_CHK 0 6
1 1 CBRK_ENGINEFAIL 284953 6
1 1 CBRK_FLIGHTTERM 121212 6
1 1 CBRK_GPSFAIL 240024 6
1 1 CBRK_IO_SAFETY 22027 6
1 1 CBRK_RATE_CTRL 0 6
1 1 CBRK_SUPPLY_CHK 894281 6
1 1 CBRK_USB_CHK 197848 6
1 1 CBRK_VELPOSERR 0 6
1 1 COM_ARM_AUTH 256010 6
1 1 COM_ARM_EKF_AB 0.004999999888241291 9
1 1 COM_ARM_EKF_GB 0.000869999988935888 9
1 1 COM_ARM_EKF_HGT 1.000000000000000000 9
1 1 COM_ARM_EKF_POS 0.500000000000000000 9
1 1 COM_ARM_EKF_VEL 0.500000000000000000 9
1 1 COM_ARM_EKF_YAW 0.500000000000000000 9
1 1 COM_ARM_IMU_ACC 0.699999988079071045 9
1 1 COM_ARM_IMU_GYR 0.200000002980232239 9
1 1 COM_ARM_MIS_REQ 0 6
1 1 COM_ARM_SWISBTN 0 6
1 1 COM_ARM_WO_GPS 1 6
1 1 COM_DISARM_LAND 1 6
1 1 COM_DL_LOSS_T 10 6
1 1 COM_DL_REG_T 0 6
1 1 COM_EF_C2T 5.000000000000000000 9
1 1 COM_EF_THROT 0.500000000000000000 9
1 1 COM_EF_TIME 10.000000000000000000 9
1 1 COM_FLIGHT_UUID 34 6
1 1 COM_FLTMODE1 8 6
1 1 COM_FLTMODE2 -1 6
1 1 COM_FLTMODE3 -1 6
1 1 COM_FLTMODE4 1 6
1 1 COM_FLTMODE5 -1 6
1 1 COM_FLTMODE6 2 6
1 1 COM_HOME_H_T 5.000000000000000000 9
1 1 COM_HOME_V_T 10.000000000000000000 9
1 1 COM_LOW_BAT_ACT 2 6
1 1 COM_OBL_ACT 0 6
1 1 COM_OBL_RC_ACT 0 6
1 1 COM_OF_LOSS_T 0.000000000000000000 9
1 1 COM_POSCTL_NAVL 0 6
1 1 COM_POS_FS_DELAY 1 6
1 1 COM_POS_FS_GAIN 10 6
1 1 COM_POS_FS_PROB 30 6
1 1 COM_RC_ARM_HYST 1000 6
1 1 COM_RC_IN_MODE 0 6
1 1 COM_RC_LOSS_T 0.500000000000000000 9
1 1 COM_RC_OVERRIDE 0 6
1 1 COM_RC_STICK_OV 12.000000000000000000 9
1 1 FW_CLMBOUT_DIFF 10.000000000000000000 9
1 1 FW_MAN_P_SC 1.000000000000000000 9
1 1 FW_MAN_R_SC 1.000000000000000000 9
1 1 FW_MAN_Y_SC 1.000000000000000000 9
1 1 GF_ACTION 1 6
1 1 GF_ALTMODE 0 6
1 1 GF_COUNT -1 6
1 1 GF_MAX_HOR_DIST 0.000000000000000000 9
1 1 GF_MAX_VER_DIST 0.000000000000000000 9
1 1 GF_SOURCE 0 6
1 1 GPS_DUMP_COMM 0 6
1 1 GPS_UBX_DYNMODEL 7 6
1 1 IMU_ACCEL_CUTOFF 30.000000000000000000 9
1 1 IMU_GYRO_CUTOFF 30.000000000000000000 9
1 1 LED_RGB_MAXBRT 15 6
1 1 LNDMC_ALT_MAX 10000.000000000000000000 9
1 1 LNDMC_FFALL_THR 2.000000000000000000 9
1 1 LNDMC_FFALL_TTRI 0.300000011920928955 9
1 1 LNDMC_ROT_MAX 20.000000000000000000 9
1 1 LNDMC_THR_RANGE 0.100000001490116119 9
1 1 LNDMC_XY_VEL_MAX 1.500000000000000000 9
1 1 LNDMC_Z_VEL_MAX 0.500000000000000000 9
1 1 LND_FLIGHT_T_HI 0 6
1 1 LND_FLIGHT_T_LO 959960540 6
1 1 LPE_ACC_XY 0.012000000104308128 9
1 1 LPE_ACC_Z 0.019999999552965164 9
1 1 LPE_BAR_Z 3.000000000000000000 9
1 1 LPE_EPH_MAX 3.000000000000000000 9
1 1 LPE_EPV_MAX 5.000000000000000000 9
1 1 LPE_FAKE_ORIGIN 1 6
1 1 LPE_FGYRO_HP 0.001000000047497451 9
1 1 LPE_FLW_OFF_Z 0.000000000000000000 9
1 1 LPE_FLW_QMIN 150 6
1 1 LPE_FLW_R 7.000000000000000000 9
1 1 LPE_FLW_RR 7.000000000000000000 9
1 1 LPE_FLW_SCALE 1.299999952316284180 9
1 1 LPE_FUSION 28 6
1 1 LPE_GPS_DELAY 0.289999991655349731 9
1 1 LPE_GPS_VXY 0.250000000000000000 9
1 1 LPE_GPS_VZ 0.250000000000000000 9
1 1 LPE_GPS_XY 1.000000000000000000 9
1 1 LPE_GPS_Z 3.000000000000000000 9
1 1 LPE_LAND_VXY 0.050000000745058060 9
1 1 LPE_LAND_Z 0.029999999329447746 9
1 1 LPE_LAT 47.397743225097656250 9
1 1 LPE_LDR_OFF_Z 0.000000000000000000 9
1 1 LPE_LDR_Z 0.029999999329447746 9
1 1 LPE_LON 8.545594215393066406 9
1 1 LPE_PN_B 0.001000000047497451 9
1 1 LPE_PN_P 0.100000001490116119 9
1 1 LPE_PN_T 0.001000000047497451 9
1 1 LPE_PN_V 0.100000001490116119 9
1 1 LPE_SNR_OFF_Z 0.000000000000000000 9
1 1 LPE_SNR_Z 0.050000000745058060 9
1 1 LPE_T_MAX_GRADE 1.000000000000000000 9
1 1 LPE_VIC_P 0.001000000047497451 9
1 1 LPE_VIS_DELAY 0.000000000000000000 9
1 1 LPE_VIS_XY 0.100000001490116119 9
1 1 LPE_VIS_Z 0.100000001490116119 9
1 1 LPE_VXY_PUB 0.300000011920928955 9
1 1 LPE_X_LP 5.000000000000000000 9
1 1 LPE_Z_PUB 1.000000000000000000 9
1 1 MAV_BROADCAST 0 6
1 1 MAV_COMP_ID 1 6
1 1 MAV_FWDEXTSP 1 6
1 1 MAV_PROTO_VER 0 6
1 1 MAV_RADIO_ID 0 6
1 1 MAV_SYS_ID 1 6
1 1 MAV_TEST_PAR 1 6
1 1 MAV_TYPE 2 6
1 1 MAV_USEHILGPS 0 6
1 1 MC_ACRO_EXPO 0.689999997615814209 9
1 1 MC_ACRO_P_MAX 360.000000000000000000 9
1 1 MC_ACRO_R_MAX 360.000000000000000000 9
1 1 MC_ACRO_SUPEXPO 0.699999988079071045 9
1 1 MC_ACRO_Y_MAX 360.000000000000000000 9
1 1 MC_BAT_SCALE_EN 0 6
1 1 MC_PITCHRATE_D 0.003000000026077032 9
1 1 MC_PITCHRATE_FF 0.000000000000000000 9
1 1 MC_PITCHRATE_I 0.045000001788139343 9
1 1 MC_PITCHRATE_MAX 220.000000000000000000 9
1 1 MC_PITCHRATE_P 0.144999995827674866 9
1 1 MC_PITCH_P 6.500000000000000000 9
1 1 MC_PITCH_TC 0.200000002980232239 9
1 1 MC_PR_INT_LIM 0.300000011920928955 9
1 1 MC_RATT_TH 0.800000011920928955 9
1 1 MC_ROLLRATE_D 0.003000000026077032 9
1 1 MC_ROLLRATE_FF 0.000000000000000000 9
1 1 MC_ROLLRATE_I 0.045000001788139343 9
1 1 MC_ROLLRATE_MAX 220.000000000000000000 9
1 1 MC_ROLLRATE_P 0.144999995827674866 9
1 1 MC_ROLL_P 6.500000000000000000 9
1 1 MC_ROLL_TC 0.200000002980232239 9
1 1 MC_RR_INT_LIM 0.300000011920928955 9
1 1 MC_TPA_BREAK_D 1.000000000000000000 9
1 1 MC_TPA_BREAK_I 1.000000000000000000 9
1 1 MC_TPA_BREAK_P 1.000000000000000000 9
1 1 MC_TPA_RATE_D 0.000000000000000000 9
1 1 MC_TPA_RATE_I 0.000000000000000000 9
1 1 MC_TPA_RATE_P 0.000000000000000000 9
1 1 MC_YAWRATE_D 0.000000000000000000 9
1 1 MC_YAWRATE_FF 0.000000000000000000 9
1 1 MC_YAWRATE_I 0.100000001490116119 9
1 1 MC_YAWRATE_MAX 200.000000000000000000 9
1 1 MC_YAWRATE_P 0.200000002980232239 9
1 1 MC_YAWRAUTO_MAX 45.000000000000000000 9
1 1 MC_YAW_FF 0.500000000000000000 9
1 1 MC_YAW_P 2.799999952316284180 9
1 1 MC_YR_INT_LIM 0.300000011920928955 9
1 1 MIS_ALTMODE 1 6
1 1 MIS_DIST_1WP 900.000000000000000000 9
1 1 MIS_DIST_WPS 900.000000000000000000 9
1 1 MIS_LTRMIN_ALT -1.000000000000000000 9
1 1 MIS_ONBOARD_EN 1 6
1 1 MIS_TAKEOFF_ALT 2.500000000000000000 9
1 1 MIS_YAWMODE 1 6
1 1 MIS_YAW_ERR 12.000000000000000000 9
1 1 MIS_YAW_TMT -1.000000000000000000 9
1 1 MNT_MODE_IN -1 6
1 1 MOT_SLEW_MAX 0.000000000000000000 9
1 1 MPC_ACC_DOWN_MAX 5.000000000000000000 9
1 1 MPC_ACC_HOR 5.000000000000000000 9
1 1 MPC_ACC_HOR_MAX 5.000000000000000000 9
1 1 MPC_ACC_UP_MAX 5.000000000000000000 9
1 1 MPC_ALT_MODE 0 6
1 1 MPC_CRUISE_90 3.000000000000000000 9
1 1 MPC_DEC_HOR_SLOW 5.000000000000000000 9
1 1 MPC_HOLD_DZ 0.100000001490116119 9
1 1 MPC_HOLD_MAX_XY 0.800000011920928955 9
1 1 MPC_HOLD_MAX_Z 0.600000023841857910 9
1 1 MPC_JERK_MAX 0.000000000000000000 9
1 1 MPC_JERK_MIN 1.000000000000000000 9
1 1 MPC_LAND_ALT1 10.000000000000000000 9
1 1 MPC_LAND_ALT2 5.000000000000000000 9
1 1 MPC_LAND_SPEED 0.500000000000000000 9
1 1 MPC_MANTHR_MAX 0.899999976158142090 9
1 1 MPC_MANTHR_MIN 0.079999998211860657 9
1 1 MPC_MAN_TILT_MAX 35.000000000000000000 9
1 1 MPC_MAN_Y_MAX 200.000000000000000000 9
1 1 MPC_THR_HOVER 0.500000000000000000 9
1 1 MPC_THR_MAX 0.899999976158142090 9
1 1 MPC_THR_MIN 0.119999997317790985 9
1 1 MPC_TILTMAX_AIR 45.000000000000000000 9
1 1 MPC_TILTMAX_LND 12.000000000000000000 9
1 1 MPC_TKO_RAMP_T 0.400000005960464478 9
1 1 MPC_TKO_SPEED 1.500000000000000000 9
1 1 MPC_VELD_LP 5.000000000000000000 9
1 1 MPC_VEL_MANUAL 10.000000000000000000 9
1 1 MPC_XY_CRUISE 5.000000000000000000 9
1 1 MPC_XY_MAN_EXPO 0.000000000000000000 9
1 1 MPC_XY_P 0.949999988079071045 9
1 1 MPC_XY_VEL_D 0.009999999776482582 9
1 1 MPC_XY_VEL_I 0.019999999552965164 9
1 1 MPC_XY_VEL_MAX 8.000000000000000000 9
1 1 MPC_XY_VEL_P 0.090000003576278687 9
1 1 MPC_Z_MAN_EXPO 0.000000000000000000 9
1 1 MPC_Z_P 1.000000000000000000 9
1 1 MPC_Z_VEL_D 0.000000000000000000 9
1 1 MPC_Z_VEL_I 0.019999999552965164 9
1 1 MPC_Z_VEL_MAX_DN 1.000000000000000000 9
1 1 MPC_Z_VEL_MAX_UP 3.000000000000000000 9
1 1 MPC_Z_VEL_P 0.200000002980232239 9
1 1 NAV_ACC_RAD 2.000000000000000000 9
1 1 NAV_AH_ALT 600.000000000000000000 9
1 1 NAV_AH_LAT -265847810 6
1 1 NAV_AH_LON 1518423250 6
1 1 NAV_DLL_ACT 0 6
1 1 NAV_DLL_AH_T 120.000000000000000000 9
1 1 NAV_DLL_CHSK 0 6
1 1 NAV_DLL_CH_ALT 600.000000000000000000 9
1 1 NAV_DLL_CH_LAT -266072120 6
1 1 NAV_DLL_CH_LON 1518453890 6
1 1 NAV_DLL_CH_T 120.000000000000000000 9
1 1 NAV_DLL_N 2 6
1 1 NAV_FORCE_VT 1 6
1 1 NAV_FT_DST 8.000000000000000000 9
1 1 NAV_FT_FS 1 6
1 1 NAV_FT_RS 0.500000000000000000 9
1 1 NAV_FW_ALT_RAD 10.000000000000000000 9
1 1 NAV_GPSF_LT 30.000000000000000000 9
1 1 NAV_GPSF_P 0.000000000000000000 9
1 1 NAV_GPSF_R 15.000000000000000000 9
1 1 NAV_GPSF_TR 0.699999988079071045 9
1 1 NAV_LOITER_RAD 50.000000000000000000 9
1 1 NAV_MC_ALT_RAD 0.800000011920928955 9
1 1 NAV_MIN_FT_HT 8.000000000000000000 9
1 1 NAV_RCL_ACT 3 6
1 1 NAV_RCL_LT 120.000000000000000000 9
1 1 NAV_TRAFF_AVOID 1 6
1 1 PWM_AUX_DIS1 -1 6
1 1 PWM_AUX_DIS2 -1 6
1 1 PWM_AUX_DIS3 -1 6
1 1 PWM_AUX_DIS4 -1 6
1 1 PWM_AUX_DIS5 -1 6
1 1 PWM_AUX_DIS6 -1 6
1 1 PWM_AUX_DISARMED 1500 6
1 1 PWM_AUX_MAX 2000 6
1 1 PWM_AUX_MIN 1000 6
1 1 PWM_AUX_REV1 0 6
1 1 PWM_AUX_REV2 0 6
1 1 PWM_AUX_REV3 0 6
1 1 PWM_AUX_REV4 0 6
1 1 PWM_AUX_REV5 0 6
1 1 PWM_AUX_REV6 0 6
1 1 PWM_AUX_TRIM1 0.000000000000000000 9
1 1 PWM_AUX_TRIM2 0.000000000000000000 9
1 1 PWM_AUX_TRIM3 0.000000000000000000 9
1 1 PWM_AUX_TRIM4 0.000000000000000000 9
1 1 PWM_AUX_TRIM5 0.000000000000000000 9
1 1 PWM_AUX_TRIM6 0.000000000000000000 9
1 1 PWM_DISARMED 900 6
1 1 PWM_MAIN_DIS1 -1 6
1 1 PWM_MAIN_DIS2 -1 6
1 1 PWM_MAIN_DIS3 -1 6
1 1 PWM_MAIN_DIS4 -1 6
1 1 PWM_MAIN_DIS5 -1 6
1 1 PWM_MAIN_DIS6 -1 6
1 1 PWM_MAIN_DIS7 -1 6
1 1 PWM_MAIN_DIS8 -1 6
1 1 PWM_MAIN_REV1 0 6
1 1 PWM_MAIN_REV2 0 6
1 1 PWM_MAIN_REV3 0 6
1 1 PWM_MAIN_REV4 0 6
1 1 PWM_MAIN_REV5 0 6
1 1 PWM_MAIN_REV6 0 6
1 1 PWM_MAIN_REV7 0 6
1 1 PWM_MAIN_REV8 0 6
1 1 PWM_MAIN_TRIM1 0.000000000000000000 9
1 1 PWM_MAIN_TRIM2 0.000000000000000000 9
1 1 PWM_MAIN_TRIM3 0.000000000000000000 9
1 1 PWM_MAIN_TRIM4 0.000000000000000000 9
1 1 PWM_MAIN_TRIM5 0.000000000000000000 9
1 1 PWM_MAIN_TRIM6 0.000000000000000000 9
1 1 PWM_MAIN_TRIM7 0.000000000000000000 9
1 1 PWM_MAIN_TRIM8 0.000000000000000000 9
1 1 PWM_MAX 1950 6
1 1 PWM_MIN 1075 6
1 1 PWM_RATE 400 6
1 1 PWM_SBUS_MODE 0 6
1 1 RC10_DZ 0.000000000000000000 9
1 1 RC10_MAX 2000.000000000000000000 9
1 1 RC10_MIN 1000.000000000000000000 9
1 1 RC10_REV 1.000000000000000000 9
1 1 RC10_TRIM 1500.000000000000000000 9
1 1 RC11_DZ 0.000000000000000000 9
1 1 RC11_MAX 2000.000000000000000000 9
1 1 RC11_MIN 1000.000000000000000000 9
1 1 RC11_REV 1.000000000000000000 9
1 1 RC11_TRIM 1500.000000000000000000 9
1 1 RC12_DZ 0.000000000000000000 9
1 1 RC12_MAX 2000.000000000000000000 9
1 1 RC12_MIN 1000.000000000000000000 9
1 1 RC12_REV 1.000000000000000000 9
1 1 RC12_TRIM 1500.000000000000000000 9
1 1 RC13_DZ 0.000000000000000000 9
1 1 RC13_MAX 2000.000000000000000000 9
1 1 RC13_MIN 1000.000000000000000000 9
1 1 RC13_REV 1.000000000000000000 9
1 1 RC13_TRIM 1500.000000000000000000 9
1 1 RC14_DZ 0.000000000000000000 9
1 1 RC14_MAX 2000.000000000000000000 9
1 1 RC14_MIN 1000.000000000000000000 9
1 1 RC14_REV 1.000000000000000000 9
1 1 RC14_TRIM 1500.000000000000000000 9
1 1 RC15_DZ 0.000000000000000000 9
1 1 RC15_MAX 2000.000000000000000000 9
1 1 RC15_MIN 1000.000000000000000000 9
1 1 RC15_REV 1.000000000000000000 9
1 1 RC15_TRIM 1500.000000000000000000 9
1 1 RC16_DZ 0.000000000000000000 9
1 1 RC16_MAX 2000.000000000000000000 9
1 1 RC16_MIN 1000.000000000000000000 9
1 1 RC16_REV 1.000000000000000000 9
1 1 RC16_TRIM 1500.000000000000000000 9
1 1 RC17_DZ 0.000000000000000000 9
1 1 RC17_MAX 2000.000000000000000000 9
1 1 RC17_MIN 1000.000000000000000000 9
1 1 RC17_REV 1.000000000000000000 9
1 1 RC17_TRIM 1500.000000000000000000 9
1 1 RC18_DZ 0.000000000000000000 9
1 1 RC18_MAX 2000.000000000000000000 9
1 1 RC18_MIN 1000.000000000000000000 9
1 1 RC18_REV 1.000000000000000000 9
1 1 RC18_TRIM 1500.000000000000000000 9
1 1 RC1_DZ 10.000000000000000000 9
1 1 RC1_MAX 1999.000000000000000000 9
1 1 RC1_MIN 1000.000000000000000000 9
1 1 RC1_REV 1.000000000000000000 9
1 1 RC1_TRIM 1499.000000000000000000 9
1 1 RC2_DZ 10.000000000000000000 9
1 1 RC2_MAX 2000.000000000000000000 9
1 1 RC2_MIN 1001.000000000000000000 9
1 1 RC2_REV 1.000000000000000000 9
1 1 RC2_TRIM 1499.000000000000000000 9
1 1 RC3_DZ 10.000000000000000000 9
1 1 RC3_MAX 1989.000000000000000000 9
1 1 RC3_MIN 1000.000000000000000000 9
1 1 RC3_REV 1.000000000000000000 9
1 1 RC3_TRIM 1000.000000000000000000 9
1 1 RC4_DZ 10.000000000000000000 9
1 1 RC4_MAX 1999.000000000000000000 9
1 1 RC4_MIN 1018.000000000000000000 9
1 1 RC4_REV 1.000000000000000000 9
1 1 RC4_TRIM 1501.000000000000000000 9
1 1 RC5_DZ 10.000000000000000000 9
1 1 RC5_MAX 2000.000000000000000000 9
1 1 RC5_MIN 1000.000000000000000000 9
1 1 RC5_REV 1.000000000000000000 9
1 1 RC5_TRIM 1500.000000000000000000 9
1 1 RC6_DZ 10.000000000000000000 9
1 1 RC6_MAX 2000.000000000000000000 9
1 1 RC6_MIN 1000.000000000000000000 9
1 1 RC6_REV 1.000000000000000000 9
1 1 RC6_TRIM 1500.000000000000000000 9
1 1 RC7_DZ 10.000000000000000000 9
1 1 RC7_MAX 2000.000000000000000000 9
1 1 RC7_MIN 1000.000000000000000000 9
1 1 RC7_REV 1.000000000000000000 9
1 1 RC7_TRIM 1500.000000000000000000 9
1 1 RC8_DZ 10.000000000000000000 9
1 1 RC8_MAX 2000.000000000000000000 9
1 1 RC8_MIN 1000.000000000000000000 9
1 1 RC8_REV 1.000000000000000000 9
1 1 RC8_TRIM 1500.000000000000000000 9
1 1 RC9_DZ 0.000000000000000000 9
1 1 RC9_MAX 2000.000000000000000000 9
1 1 RC9_MIN 1000.000000000000000000 9
1 1 RC9_REV 1.000000000000000000 9
1 1 RC9_TRIM 1500.000000000000000000 9
1 1 RC_ACRO_TH 0.500000000000000000 9
1 1 RC_ARMSWITCH_TH 0.250000000000000000 9
1 1 RC_ASSIST_TH 0.250000000000000000 9
1 1 RC_AUTO_TH 0.750000000000000000 9
1 1 RC_CHAN_CNT 8 6
1 1 RC_FAILS_THR 0 6
1 1 RC_FLT_CUTOFF 10.000000000000000000 9
1 1 RC_FLT_SMP_RATE 50.000000000000000000 9
1 1 RC_GEAR_TH 0.250000000000000000 9
1 1 RC_KILLSWITCH_TH 0.250000000000000000 9
1 1 RC_LOITER_TH 0.500000000000000000 9
1 1 RC_MAN_TH 0.500000000000000000 9
1 1 RC_MAP_ACRO_SW 0 6
1 1 RC_MAP_ARM_SW 0 6
1 1 RC_MAP_AUX1 0 6
1 1 RC_MAP_AUX2 0 6
1 1 RC_MAP_AUX3 0 6
1 1 RC_MAP_AUX4 0 6
1 1 RC_MAP_AUX5 0 6
1 1 RC_MAP_FAILSAFE 0 6
1 1 RC_MAP_FLAPS 0 6
1 1 RC_MAP_FLTMODE 5 6
1 1 RC_MAP_GEAR_SW 0 6
1 1 RC_MAP_KILL_SW 6 6
1 1 RC_MAP_LOITER_SW 0 6
1 1 RC_MAP_MAN_SW 0 6
1 1 RC_MAP_MODE_SW 0 6
1 1 RC_MAP_OFFB_SW 0 6
1 1 RC_MAP_PARAM1 0 6
1 1 RC_MAP_PARAM2 0 6
1 1 RC_MAP_PARAM3 0 6
1 1 RC_MAP_PITCH 2 6
1 1 RC_MAP_POSCTL_SW 0 6
1 1 RC_MAP_RATT_SW 0 6
1 1 RC_MAP_RETURN_SW 0 6
1 1 RC_MAP_ROLL 1 6
1 1 RC_MAP_STAB_SW 0 6
1 1 RC_MAP_THROTTLE 3 6
1 1 RC_MAP_TRANS_SW 0 6
1 1 RC_MAP_YAW 4 6
1 1 RC_OFFB_TH 0.500000000000000000 9
1 1 RC_POSCTL_TH 0.500000000000000000 9
1 1 RC_RATT_TH 0.500000000000000000 9
1 1 RC_RETURN_TH 0.500000000000000000 9
1 1 RC_RSSI_PWM_CHAN 0 6
1 1 RC_RSSI_PWM_MAX 1000 6
1 1 RC_RSSI_PWM_MIN 2000 6
1 1 RC_STAB_TH 0.500000000000000000 9
1 1 RC_TRANS_TH 0.250000000000000000 9
1 1 RTL_DESCEND_ALT 10.000000000000000000 9
1 1 RTL_LAND_DELAY 0.000000000000000000 9
1 1 RTL_MIN_DIST 5.000000000000000000 9
1 1 RTL_RETURN_ALT 30.000000000000000000 9
1 1 SDLOG_DIRS_MAX 0 6
1 1 SDLOG_MODE 0 6
1 1 SDLOG_PROFILE 3 6
1 1 SDLOG_UTC_OFFSET 0 6
1 1 SENS_BARO_QNH 1013.250000000000000000 9
1 1 SENS_BOARD_ROT 0 6
1 1 SENS_BOARD_X_OFF 0.576516091823577881 9
1 1 SENS_BOARD_Y_OFF 2.084044218063354492 9
1 1 SENS_BOARD_Z_OFF 0.000000000000000000 9
1 1 SENS_DPRES_ANSC 0.000000000000000000 9
1 1 SENS_DPRES_OFF 0.000000000000000000 9
1 1 SENS_EN_LL40LS 0 6
1 1 SENS_EN_MB12XX 0 6
1 1 SENS_EN_SF0X 0 6
1 1 SENS_EN_SF1XX 0 6
1 1 SENS_EN_THERMAL -1 6
1 1 SENS_EN_TRANGER 0 6
1 1 SYS_AUTOCONFIG 0 6
1 1 SYS_AUTOSTART 4001 6
1 1 SYS_CAL_ACCEL 0 6
1 1 SYS_CAL_BARO 0 6
1 1 SYS_CAL_GYRO 0 6
1 1 SYS_CAL_TDEL 24 6
1 1 SYS_CAL_TMAX 10 6
1 1 SYS_CAL_TMIN 5 6
1 1 SYS_COMPANION 921600 6
1 1 SYS_FMU_TASK 0 6
1 1 SYS_HITL 0 6
1 1 SYS_LOGGER 1 6
1 1 SYS_MC_EST_GROUP 1 6
1 1 SYS_PARAM_VER 1 6
1 1 SYS_RESTART_TYPE 0 6
1 1 SYS_STCK_EN 1 6
1 1 SYS_USE_IO 1 6
1 1 TC_A0_ID 0 6
1 1 TC_A0_SCL_0 1.000000000000000000 9
1 1 TC_A0_SCL_1 1.000000000000000000 9
1 1 TC_A0_SCL_2 1.000000000000000000 9
1 1 TC_A0_TMAX 100.000000000000000000 9
1 1 TC_A0_TMIN 0.000000000000000000 9
1 1 TC_A0_TREF 25.000000000000000000 9
1 1 TC_A0_X0_0 0.000000000000000000 9
1 1 TC_A0_X0_1 0.000000000000000000 9
1 1 TC_A0_X0_2 0.000000000000000000 9
1 1 TC_A0_X1_0 0.000000000000000000 9
1 1 TC_A0_X1_1 0.000000000000000000 9
1 1 TC_A0_X1_2 0.000000000000000000 9
1 1 TC_A0_X2_0 0.000000000000000000 9
1 1 TC_A0_X2_1 0.000000000000000000 9
1 1 TC_A0_X2_2 0.000000000000000000 9
1 1 TC_A0_X3_0 0.000000000000000000 9
1 1 TC_A0_X3_1 0.000000000000000000 9
1 1 TC_A0_X3_2 0.000000000000000000 9
1 1 TC_A1_ID 0 6
1 1 TC_A1_SCL_0 1.000000000000000000 9
1 1 TC_A1_SCL_1 1.000000000000000000 9
1 1 TC_A1_SCL_2 1.000000000000000000 9
1 1 TC_A1_TMAX 100.000000000000000000 9
1 1 TC_A1_TMIN 0.000000000000000000 9
1 1 TC_A1_TREF 25.000000000000000000 9
1 1 TC_A1_X0_0 0.000000000000000000 9
1 1 TC_A1_X0_1 0.000000000000000000 9
1 1 TC_A1_X0_2 0.000000000000000000 9
1 1 TC_A1_X1_0 0.000000000000000000 9
1 1 TC_A1_X1_1 0.000000000000000000 9
1 1 TC_A1_X1_2 0.000000000000000000 9
1 1 TC_A1_X2_0 0.000000000000000000 9
1 1 TC_A1_X2_1 0.000000000000000000 9
1 1 TC_A1_X2_2 0.000000000000000000 9
1 1 TC_A1_X3_0 0.000000000000000000 9
1 1 TC_A1_X3_1 0.000000000000000000 9
1 1 TC_A1_X3_2 0.000000000000000000 9
1 1 TC_A2_ID 0 6
1 1 TC_A2_SCL_0 1.000000000000000000 9
1 1 TC_A2_SCL_1 1.000000000000000000 9
1 1 TC_A2_SCL_2 1.000000000000000000 9
1 1 TC_A2_TMAX 100.000000000000000000 9
1 1 TC_A2_TMIN 0.000000000000000000 9
1 1 TC_A2_TREF 25.000000000000000000 9
1 1 TC_A2_X0_0 0.000000000000000000 9
1 1 TC_A2_X0_1 0.000000000000000000 9
1 1 TC_A2_X0_2 0.000000000000000000 9
1 1 TC_A2_X1_0 0.000000000000000000 9
1 1 TC_A2_X1_1 0.000000000000000000 9
1 1 TC_A2_X1_2 0.000000000000000000 9
1 1 TC_A2_X2_0 0.000000000000000000 9
1 1 TC_A2_X2_1 0.000000000000000000 9
1 1 TC_A2_X2_2 0.000000000000000000 9
1 1 TC_A2_X3_0 0.000000000000000000 9
1 1 TC_A2_X3_1 0.000000000000000000 9
1 1 TC_A2_X3_2 0.000000000000000000 9
1 1 TC_A_ENABLE 0 6
1 1 TC_B0_ID 0 6
1 1 TC_B0_SCL 1.000000000000000000 9
1 1 TC_B0_TMAX 75.000000000000000000 9
1 1 TC_B0_TMIN 5.000000000000000000 9
1 1 TC_B0_TREF 40.000000000000000000 9
1 1 TC_B0_X0 0.000000000000000000 9
1 1 TC_B0_X1 0.000000000000000000 9
1 1 TC_B0_X2 0.000000000000000000 9
1 1 TC_B0_X3 0.000000000000000000 9
1 1 TC_B0_X4 0.000000000000000000 9
1 1 TC_B0_X5 0.000000000000000000 9
1 1 TC_B1_ID 0 6
1 1 TC_B1_SCL 1.000000000000000000 9
1 1 TC_B1_TMAX 75.000000000000000000 9
1 1 TC_B1_TMIN 5.000000000000000000 9
1 1 TC_B1_TREF 40.000000000000000000 9
1 1 TC_B1_X0 0.000000000000000000 9
1 1 TC_B1_X1 0.000000000000000000 9
1 1 TC_B1_X2 0.000000000000000000 9
1 1 TC_B1_X3 0.000000000000000000 9
1 1 TC_B1_X4 0.000000000000000000 9
1 1 TC_B1_X5 0.000000000000000000 9
1 1 TC_B2_ID 0 6
1 1 TC_B2_SCL 1.000000000000000000 9
1 1 TC_B2_TMAX 75.000000000000000000 9
1 1 TC_B2_TMIN 5.000000000000000000 9
1 1 TC_B2_TREF 40.000000000000000000 9
1 1 TC_B2_X0 0.000000000000000000 9
1 1 TC_B2_X1 0.000000000000000000 9
1 1 TC_B2_X2 0.000000000000000000 9
1 1 TC_B2_X3 0.000000000000000000 9
1 1 TC_B2_X4 0.000000000000000000 9
1 1 TC_B2_X5 0.000000000000000000 9
1 1 TC_B_ENABLE 0 6
1 1 TC_G0_ID 0 6
1 1 TC_G0_SCL_0 1.000000000000000000 9
1 1 TC_G0_SCL_1 1.000000000000000000 9
1 1 TC_G0_SCL_2 1.000000000000000000 9
1 1 TC_G0_TMAX 100.000000000000000000 9
1 1 TC_G0_TMIN 0.000000000000000000 9
1 1 TC_G0_TREF 25.000000000000000000 9
1 1 TC_G0_X0_0 0.000000000000000000 9
1 1 TC_G0_X0_1 0.000000000000000000 9
1 1 TC_G0_X0_2 0.000000000000000000 9
1 1 TC_G0_X1_0 0.000000000000000000 9
1 1 TC_G0_X1_1 0.000000000000000000 9
1 1 TC_G0_X1_2 0.000000000000000000 9
1 1 TC_G0_X2_0 0.000000000000000000 9
1 1 TC_G0_X2_1 0.000000000000000000 9
1 1 TC_G0_X2_2 0.000000000000000000 9
1 1 TC_G0_X3_0 0.000000000000000000 9
1 1 TC_G0_X3_1 0.000000000000000000 9
1 1 TC_G0_X3_2 0.000000000000000000 9
1 1 TC_G1_ID 0 6
1 1 TC_G1_SCL_0 1.000000000000000000 9
1 1 TC_G1_SCL_1 1.000000000000000000 9
1 1 TC_G1_SCL_2 1.000000000000000000 9
1 1 TC_G1_TMAX 100.000000000000000000 9
1 1 TC_G1_TMIN 0.000000000000000000 9
1 1 TC_G1_TREF 25.000000000000000000 9
1 1 TC_G1_X0_0 0.000000000000000000 9
1 1 TC_G1_X0_1 0.000000000000000000 9
1 1 TC_G1_X0_2 0.000000000000000000 9
1 1 TC_G1_X1_0 0.000000000000000000 9
1 1 TC_G1_X1_1 0.000000000000000000 9
1 1 TC_G1_X1_2 0.000000000000000000 9
1 1 TC_G1_X2_0 0.000000000000000000 9
1 1 TC_G1_X2_1 0.000000000000000000 9
1 1 TC_G1_X2_2 0.000000000000000000 9
1 1 TC_G1_X3_0 0.000000000000000000 9
1 1 TC_G1_X3_1 0.000000000000000000 9
1 1 TC_G1_X3_2 0.000000000000000000 9
1 1 TC_G2_ID 0 6
1 1 TC_G2_SCL_0 1.000000000000000000 9
1 1 TC_G2_SCL_1 1.000000000000000000 9
1 1 TC_G2_SCL_2 1.000000000000000000 9
1 1 TC_G2_TMAX 100.000000000000000000 9
1 1 TC_G2_TMIN 0.000000000000000000 9
1 1 TC_G2_TREF 25.000000000000000000 9
1 1 TC_G2_X0_0 0.000000000000000000 9
1 1 TC_G2_X0_1 0.000000000000000000 9
1 1 TC_G2_X0_2 0.000000000000000000 9
1 1 TC_G2_X1_0 0.000000000000000000 9
1 1 TC_G2_X1_1 0.000000000000000000 9
1 1 TC_G2_X1_2 0.000000000000000000 9
1 1 TC_G2_X2_0 0.000000000000000000 9
1 1 TC_G2_X2_1 0.000000000000000000 9
1 1 TC_G2_X2_2 0.000000000000000000 9
1 1 TC_G2_X3_0 0.000000000000000000 9
1 1 TC_G2_X3_1 0.000000000000000000 9
1 1 TC_G2_X3_2 0.000000000000000000 9
1 1 TC_G_ENABLE 0 6
1 1 THR_MDL_FAC 0.000000000000000000 9
1 1 TRIG_MODE 0 6
1 1 TRIM_PITCH 0.000000000000000000 9
1 1 TRIM_ROLL 0.000000000000000000 9
1 1 TRIM_YAW 0.000000000000000000 9
1 1 VT_B_DEC_MSS 2.000000000000000000 9
1 1 VT_B_REV_DEL 0.000000000000000000 9

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 683 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 627 KiB

Some files were not shown because too many files have changed in this diff Show More