Compare commits
76 Commits
v0.20-alph
...
new-readme
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34560c0b34 | ||
|
|
4bf9f728b1 | ||
|
|
0172d6e892 | ||
|
|
bcb7351a90 | ||
|
|
c71a46ce9d | ||
|
|
91dd7799ef | ||
|
|
3682e253a7 | ||
|
|
66ecbb4d09 | ||
|
|
f041b6125b | ||
|
|
a4f2bab3d7 | ||
|
|
56bcfa5c87 | ||
|
|
998796045c | ||
|
|
c5e954b56a | ||
|
|
2814fea9cd | ||
|
|
b85326c02a | ||
|
|
98d5d50607 | ||
|
|
69c46786de | ||
|
|
abb495275b | ||
|
|
044d6c6d33 | ||
|
|
22d5a356b6 | ||
|
|
c7828557ca | ||
|
|
514c0f1b65 | ||
|
|
6a79b8292a | ||
|
|
10b6661266 | ||
|
|
7f2cb1c63e | ||
|
|
1d48c79c52 | ||
|
|
ad46a0918c | ||
|
|
9487522992 | ||
|
|
80b35d3b90 | ||
|
|
12e292c9d7 | ||
|
|
9b28e9cad2 | ||
|
|
d57ab82f38 | ||
|
|
c8da639eab | ||
|
|
c7e7edec70 | ||
|
|
72869fcf2b | ||
|
|
387d2c2341 | ||
|
|
a665caeea3 | ||
|
|
3079d2a3e1 | ||
|
|
7d5bdf4f22 | ||
|
|
2a3efa2908 | ||
|
|
ddee29a0e8 | ||
|
|
8596be07c6 | ||
|
|
a480ebe80a | ||
|
|
77ca50b901 | ||
|
|
ead9b904fa | ||
|
|
90956ecd44 | ||
|
|
f070c60e14 | ||
|
|
68edf07f6e | ||
|
|
7f161b1ad7 | ||
|
|
a41a432ef3 | ||
|
|
2b896b06d9 | ||
|
|
5070cafbfb | ||
|
|
9c0af7285c | ||
|
|
c67d937842 | ||
|
|
b79d87242f | ||
|
|
4d0ddcb319 | ||
|
|
3ff4ee6c4c | ||
|
|
90049182cf | ||
|
|
33f4601fdc | ||
|
|
2a62891d60 | ||
|
|
b043737e91 | ||
|
|
c61a0485ff | ||
|
|
f1539177eb | ||
|
|
6cbbb5580e | ||
|
|
c2d22ae12a | ||
|
|
7160d804cd | ||
|
|
3ac51baf7c | ||
|
|
48cc82001d | ||
|
|
43eae885c6 | ||
|
|
2bb29ff389 | ||
|
|
3811cbff3e | ||
|
|
2d49f58fb8 | ||
|
|
bbcf75b806 | ||
|
|
3e79c25147 | ||
|
|
2f69ad3f43 | ||
|
|
b08ad5a618 |
19
.travis.yml
@@ -1,4 +1,5 @@
|
||||
sudo: required
|
||||
os: linux
|
||||
dist: xenial
|
||||
language: generic
|
||||
services:
|
||||
- docker
|
||||
@@ -43,7 +44,7 @@ jobs:
|
||||
- cd images && zip ${IMAGE_NAME}.zip ${IMAGE_NAME}
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key: ${GITHUB_OAUTH_TOKEN}
|
||||
token: ${GITHUB_OAUTH_TOKEN}
|
||||
file: ${IMAGE_NAME}.zip
|
||||
skip_cleanup: true
|
||||
on:
|
||||
@@ -84,13 +85,13 @@ jobs:
|
||||
- gitbook build
|
||||
deploy:
|
||||
provider: pages
|
||||
local-dir: _book
|
||||
skip-cleanup: true
|
||||
github-token: ${GITHUB_OAUTH_TOKEN}
|
||||
keep-history: true
|
||||
target-branch: master
|
||||
repo: CopterExpress/clever.coex.tech
|
||||
fqdn: clever.coex.tech
|
||||
local_dir: _book
|
||||
skip_cleanup: true
|
||||
token: ${GITHUB_OAUTH_TOKEN}
|
||||
keep_history: true
|
||||
target_branch: master
|
||||
repo: CopterExpress/clover.coex.tech
|
||||
fqdn: clover.coex.tech
|
||||
verbose: true
|
||||
on:
|
||||
branch: master
|
||||
|
||||
234
README.md
@@ -1,103 +1,173 @@
|
||||
# CLEVER
|
||||
# COEX Clover Drone Kit
|
||||
|
||||
<img src="docs/assets/clever4-front-white.png" align="right" width="400px" alt="CLEVER drone">
|
||||
<table align=center>
|
||||
<tr>
|
||||
<td align=center><a href="https://px4.io"><img src="docs/assets/px4.svg" height=60></a></td>
|
||||
<td align=center><a href="https://www.raspberrypi.org"><img src="docs/assets/rpi.svg" height=60></a></td>
|
||||
<td align=center><a href="https://www.ros.org"><img src="docs/assets/ros.svg" height=60></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
CLEVER (Russian: *"Клевер"*, meaning *"Clover"*) is an educational programmable drone kit consisting of an unassembled quadcopter, open source software and documentation. The kit includes Pixhawk/Pixracer autopilot running PX4 firmware, Raspberry Pi 3 as companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices.
|
||||
This repository contains documentation, software platform source code and RPi image builder for COEX Clover drone kit.
|
||||
|
||||
Copter Express has implemented a large number of different autonomous drone projects using exactly the same platform: [automated pizza delivery](https://www.youtube.com/watch?v=hmkAoZOtF58) in Samara and Kazan, coffee delivery in Skolkovo Innovation Center, [autonomous quadcopter with charging station](https://www.youtube.com/watch?v=RjX6nUqw1mI) for site monitoring and security, winning drones on [Robocross-2016](https://www.youtube.com/watch?v=dGbDaz_VmYU) and [Robocross-2017](https://youtu.be/AQnd2CRczbQ) competitions and many others.
|
||||
<img src="docs/assets/clover42.png" align="right" width="400px" alt="COEX Clover">
|
||||
|
||||
**The main documentation is available [on Gitbook](https://clever.coex.tech/).**
|
||||
Clover is a [PX4](https://px4.io)- and [ROS](https://www.ros.org)-powered educational programmable drone kit consisting of an unassembled quadcopter, open source software and documentation. The kit includes Pixracer-compatible autopilot, Raspberry Pi 4 as companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices.
|
||||
|
||||
Use it to learn how to assemble, configure, pilot and program autonomous CLEVER drone.
|
||||
The main documentation is available at [https://clover.coex.tech](https://clover.coex.tech/). Official website: <a href="https://coex.tech/clover">coex.tech/clover</a>.
|
||||
|
||||
## Raspberry Pi image
|
||||
## Autonomous flights video
|
||||
|
||||
**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).**
|
||||
[](https://youtu.be/u3omgsYC4Fk)
|
||||
|
||||
[](https://travis-ci.org/CopterExpress/clever)
|
||||
Clover drone is used on a wide range of educational events, including [Copter Hack](https://www.youtube.com/watch?v=xgXheg3TTs4), WorldSkills Drone Operation competition, [Autonomous Vehicles Track of NTI Olympics 2016–2020](https://www.youtube.com/watch?v=E1_ehvJRKxg), Quadro Hack 2019 (National University of Science and Technology MISiS), Russian Robot Olympiad (autonomous flights), and others.
|
||||
|
||||
Image includes:
|
||||
## Features
|
||||
|
||||
* Raspbian Buster
|
||||
* ROS Melodic
|
||||
* Configured networking
|
||||
* OpenCV
|
||||
* mavros
|
||||
* Periphery drivers (`pigpiod`, `rpi_ws281x`, etc)
|
||||
* CLEVER software bundle for autonomous drone control
|
||||
### Prebuilt RPi image
|
||||
|
||||
API description (in Russian) for autonomous flights is available [on GitBook](https://clever.coex.tech/simple_offboard.html).
|
||||
...
|
||||
|
||||
### Common robotics software
|
||||
|
||||
Prebuilt image for Raspberry Pi includes:
|
||||
|
||||
|Software|Description|
|
||||
|-|-|
|
||||
|Raspbian Buster||
|
||||
|[ROS Melodic](http://wiki.ros.org/melodic)|Common robotics framework|
|
||||
|[OpenCV](https://opencv.org)|Computer vision library|
|
||||
|[`mavros`](http://wiki.ros.org/mavros)|ROS package for communication with the flight controller|
|
||||
|Configured networking||
|
||||
|Periphery drivers for ROS ([GPIO](https://clover.coex.tech/en/gpio.html), [LED strip](https://clover.coex.tech/en/leds.html), etc)||
|
||||
|`clover`|package for autonomous drone control|
|
||||
|`aruco_pose`|Package for marker-assisted navigation|
|
||||
|
||||
### QGroundControl Wi-Fi bridge
|
||||
|
||||
...
|
||||
|
||||
### Easy autonomous flights programming
|
||||
|
||||
By using `clover` package, taking off, navigating and landing is just:
|
||||
|
||||
```python
|
||||
navigate(x=0, y=0, z=1, frame_id='body', auto_arm=True) # takeoff and hover 1 m above the ground
|
||||
```
|
||||
|
||||
```python
|
||||
navigate(x=1, y=0, z=0, frame_id='body') # fly forward 1 m
|
||||
```
|
||||
|
||||
```
|
||||
land()
|
||||
```
|
||||
|
||||
See [programming documentation](https://clover.coex.tech) for further information.
|
||||
|
||||
### Optical flow positioning
|
||||
|
||||
<img src="docs/assets/optical-flow.gif">
|
||||
|
||||
RPi based optical flow....
|
||||
|
||||
See [details](https://clover.coex.tech/en/optical_flow.html) in the documentation.
|
||||
|
||||
### ArUco markers recognizing
|
||||
|
||||
<img src="docs/assets/aruco.gif">
|
||||
|
||||
...
|
||||
|
||||
See [details](https://clover.coex.tech/en/aruco.html) in the documentation.
|
||||
|
||||
### Easy working with peripheral devices
|
||||
|
||||
Preinstalled package for the [LED strip](https://clover.coex.tech/en/leds.html) allows high-level control (such as rainbow effect or color fade) as well as individual LED low-level control:
|
||||
|
||||
```python
|
||||
set_effect(r=0, g=100, b=0) # fill strip with green color
|
||||
```
|
||||
|
||||
```python
|
||||
set_effect(effect='fade', r=0, g=0, b=255) # fade to blue color
|
||||
```
|
||||
|
||||
```python
|
||||
set_effect(effect='rainbow') # show rainbow
|
||||
```
|
||||
|
||||
Preinstalled [VL53L1X rangefinder driver](https://clover.coex.tech/en/laser.html) passes data to the flight controller automatically and allows the user to get its data:
|
||||
|
||||
```python
|
||||
data = rospy.wait_for_message('rangefinder/range', Range) # get data from the rangefinder
|
||||
```
|
||||
|
||||
Preinstalled fast Python [GPIO library](https://clover.coex.tech/en/gpio.html).
|
||||
|
||||
```python
|
||||
pi.write(11, 1) # set signal of pin 11 to high
|
||||
```
|
||||
|
||||
```python
|
||||
level = pi.read(12) # read the state of pin 12
|
||||
```
|
||||
|
||||
### Simulator
|
||||
|
||||
<img src="docs/assets/simulator.jpg" width=400 align=center>
|
||||
|
||||
Clover repository includes three simulation-related repository for Gazebo-based simulation.
|
||||
|
||||
Screenshot...
|
||||
|
||||
See details in the [documentation](https://clover.coex.tech/en/simulation.html). The simulation environment also available as a virtual machine image.
|
||||
|
||||
### Remote control apps
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://itunes.apple.com/ru/app/clever-rc/id1396166572?mt=8">
|
||||
<img src="docs/assets/appstore.svg" height=40>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://play.google.com/store/apps/details?id=express.copter.cleverrc">
|
||||
<img src="docs/assets/google_play.png" height=40>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- <a href="https://itunes.apple.com/ru/app/clever-rc/id1396166572?mt=8"><img src="docs/assets/appstore.svg"></a><a href="https://play.google.com/store/apps/details?id=express.copter.cleverrc"><img src="docs/assets/google_play.png" width="15%"></a> -->
|
||||
|
||||
### Community
|
||||
|
||||
<img src="docs/assets/community/collage.jpg" width=400 align=center>
|
||||
|
||||
Clover is widely used ...
|
||||
|
||||
[Telegram chat](tg://resolve?domain=COEXHelpdesk)...
|
||||
|
||||
### Free and open source
|
||||
|
||||
The Clover software bundle is free, open source, and compatible with any PX4/ROS-based drone.
|
||||
|
||||
## Manual installation
|
||||
|
||||
Install ROS Melodic according to the [documentation](http://wiki.ros.org/melodic/Installation), then [create a Catkin workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace).
|
||||
For manual package installation and running see [`clover` package documentation](clover/README.md).
|
||||
|
||||
Clone this repo to directory `~/catkin_ws/src/clever`:
|
||||
## PX4 Dev Summit 2019 talk
|
||||
|
||||
```bash
|
||||
cd ~/catkin_ws/src
|
||||
git clone https://github.com/CopterExpress/clever.git clever
|
||||
```
|
||||
[](http://www.youtube.com/watch?v=CTG9E9PbJQ8)
|
||||
|
||||
All the required ROS packages (including `mavros` and `opencv`) can be installed using `rosdep`:
|
||||
## Other resources
|
||||
|
||||
```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
|
||||
cd ~/catkin_ws
|
||||
catkin_make -j1
|
||||
```
|
||||
|
||||
To complete `mavros` install you'll need to install `geographiclib` datasets:
|
||||
|
||||
```bash
|
||||
curl https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | sudo bash
|
||||
```
|
||||
|
||||
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/builder/assets/roscore.service
|
||||
sudo systemctl start roscore
|
||||
```
|
||||
|
||||
To start connection to SITL, use:
|
||||
|
||||
```bash
|
||||
roslaunch clever sitl.launch
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
* Official documentation: [https://clover.coex.tech](https://clover.coex.tech).
|
||||
* ROS Wiki page: [https://wiki.ros.org/Robots/clover](https://wiki.ros.org/Robots/clover).
|
||||
* ROS Robots page: [https://robots.ros.org/clover](https://robots.ros.org/clover).
|
||||
|
||||
## License
|
||||
|
||||
While the Clever platform source code is available under the MIT License, note, that the [documentation](docs/) is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||
While the Clover platform source code is available under the MIT License, note, that the [documentation](docs/) is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||
|
||||
0
apps/CATKIN_IGNORE
Normal file
@@ -1,8 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(aruco_pose)
|
||||
|
||||
add_definitions(-std=c++11 -Wall -g)
|
||||
|
||||
## Compile as C++11, supported in ROS Kinetic and newer
|
||||
add_compile_options(-std=c++11)
|
||||
|
||||
@@ -25,7 +23,7 @@ find_package(catkin REQUIRED COMPONENTS
|
||||
)
|
||||
|
||||
find_package(OpenCV 3 REQUIRED COMPONENTS core imgproc calib3d)
|
||||
if ("${OpenCV_VERSION_MINOR}" LESS "3")
|
||||
if ("${OpenCV_VERSION_MINOR}" LESS "9")
|
||||
message(STATUS "OpenCV version too low, using vendored ArUco package")
|
||||
include(vendor/VendorOpenCV.cmake)
|
||||
else()
|
||||
@@ -229,4 +227,5 @@ if (CATKIN_ENABLE_TESTING)
|
||||
add_rostest(test/test_parser_empty_map.test)
|
||||
add_rostest(test/test_node_failure.test)
|
||||
add_rostest(test/largemap.test)
|
||||
add_rostest(test/crash_opencv.test)
|
||||
endif()
|
||||
|
||||
@@ -58,10 +58,9 @@ using cv::Mat;
|
||||
|
||||
class ArucoDetect : public nodelet::Nodelet {
|
||||
private:
|
||||
ros::NodeHandle nh_, nh_priv_;
|
||||
tf2_ros::TransformBroadcaster br_;
|
||||
tf2_ros::Buffer tf_buffer_;
|
||||
tf2_ros::TransformListener tf_listener_{tf_buffer_};
|
||||
std::unique_ptr<tf2_ros::TransformBroadcaster> br_;
|
||||
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
std::shared_ptr<dynamic_reconfigure::Server<aruco_pose::DetectorConfig>> dyn_srv_;
|
||||
cv::Ptr<cv::aruco::Dictionary> dictionary_;
|
||||
cv::Ptr<cv::aruco::DetectorParameters> parameters_;
|
||||
@@ -81,30 +80,32 @@ private:
|
||||
public:
|
||||
virtual void onInit()
|
||||
{
|
||||
nh_ = getNodeHandle();
|
||||
nh_priv_ = getPrivateNodeHandle();
|
||||
ros::NodeHandle& nh_ = getNodeHandle();
|
||||
ros::NodeHandle& nh_priv_ = getPrivateNodeHandle();
|
||||
|
||||
br_.reset(new tf2_ros::TransformBroadcaster());
|
||||
tf_buffer_.reset(new tf2_ros::Buffer());
|
||||
tf_listener_.reset(new tf2_ros::TransformListener(*tf_buffer_, nh_));
|
||||
|
||||
int dictionary;
|
||||
nh_priv_.param("dictionary", dictionary, 2);
|
||||
nh_priv_.param("estimate_poses", estimate_poses_, true);
|
||||
nh_priv_.param("send_tf", send_tf_, true);
|
||||
dictionary = nh_priv_.param("dictionary", 2);
|
||||
estimate_poses_ = nh_priv_.param("estimate_poses", true);
|
||||
send_tf_ = nh_priv_.param("send_tf", true);
|
||||
if (estimate_poses_ && !nh_priv_.getParam("length", length_)) {
|
||||
NODELET_FATAL("can't estimate marker's poses as ~length parameter is not defined");
|
||||
ros::shutdown();
|
||||
}
|
||||
readLengthOverride();
|
||||
readLengthOverride(nh_priv_);
|
||||
|
||||
nh_priv_.param<std::string>("known_tilt", known_tilt_, "");
|
||||
nh_priv_.param("auto_flip", auto_flip_, false);
|
||||
known_tilt_ = nh_priv_.param<std::string>("known_tilt", "");
|
||||
auto_flip_ = nh_priv_.param("auto_flip", false);
|
||||
|
||||
nh_priv_.param<std::string>("frame_id_prefix", frame_id_prefix_, "aruco_");
|
||||
frame_id_prefix_ = nh_priv_.param<std::string>("frame_id_prefix", "aruco_");
|
||||
|
||||
camera_matrix_ = cv::Mat::zeros(3, 3, CV_64F);
|
||||
dist_coeffs_ = cv::Mat::zeros(8, 1, CV_64F);
|
||||
|
||||
dictionary_ = cv::aruco::getPredefinedDictionary(static_cast<cv::aruco::PREDEFINED_DICTIONARY_NAME>(dictionary));
|
||||
parameters_ = cv::aruco::DetectorParameters::create();
|
||||
parameters_->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX;
|
||||
|
||||
image_transport::ImageTransport it(nh_);
|
||||
image_transport::ImageTransport it_priv(nh_priv_);
|
||||
@@ -170,8 +171,8 @@ private:
|
||||
|
||||
if (!known_tilt_.empty()) {
|
||||
try {
|
||||
snap_to = tf_buffer_.lookupTransform(msg->header.frame_id, known_tilt_,
|
||||
msg->header.stamp, ros::Duration(0.02));
|
||||
snap_to = tf_buffer_->lookupTransform(msg->header.frame_id, known_tilt_,
|
||||
msg->header.stamp, ros::Duration(0.02));
|
||||
} catch (const tf2::TransformException& e) {
|
||||
NODELET_WARN_THROTTLE(5, "can't snap: %s", e.what());
|
||||
}
|
||||
@@ -205,7 +206,7 @@ private:
|
||||
if (map_markers_ids_.find(ids[i]) == map_markers_ids_.end()) {
|
||||
transform.transform.rotation = marker.pose.orientation;
|
||||
fillTranslation(transform.transform.translation, tvecs[i]);
|
||||
br_.sendTransform(transform);
|
||||
br_->sendTransform(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,10 +327,10 @@ private:
|
||||
return frame_id_prefix_ + std::to_string(id);
|
||||
}
|
||||
|
||||
void readLengthOverride()
|
||||
void readLengthOverride(ros::NodeHandle& nh)
|
||||
{
|
||||
std::map<std::string, double> length_override;
|
||||
nh_priv_.getParam("length_override", length_override);
|
||||
nh.getParam("length_override", length_override);
|
||||
for (auto const& item : length_override) {
|
||||
length_override_[std::stoi(item.first)] = item.second;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ typedef message_filters::sync_policies::ExactTime<Image, CameraInfo, MarkerArray
|
||||
|
||||
class ArucoMap : public nodelet::Nodelet {
|
||||
private:
|
||||
ros::NodeHandle nh_, nh_priv_;
|
||||
ros::Publisher img_pub_, pose_pub_, markers_pub_, vis_markers_pub_;
|
||||
image_transport::Publisher debug_pub_;
|
||||
message_filters::Subscriber<Image> image_sub_;
|
||||
@@ -83,8 +82,8 @@ private:
|
||||
public:
|
||||
virtual void onInit()
|
||||
{
|
||||
nh_ = getNodeHandle();
|
||||
nh_priv_ = getPrivateNodeHandle();
|
||||
ros::NodeHandle &nh_ = getNodeHandle();
|
||||
ros::NodeHandle &nh_priv_ = getPrivateNodeHandle();
|
||||
|
||||
image_transport::ImageTransport it_priv(nh_priv_);
|
||||
|
||||
@@ -96,19 +95,18 @@ public:
|
||||
board_->dictionary = cv::aruco::getPredefinedDictionary(
|
||||
static_cast<cv::aruco::PREDEFINED_DICTIONARY_NAME>(nh_priv_.param("dictionary", 2)));
|
||||
camera_matrix_ = cv::Mat::zeros(3, 3, CV_64F);
|
||||
dist_coeffs_ = cv::Mat::zeros(8, 1, CV_64F);
|
||||
|
||||
std::string type, map;
|
||||
nh_priv_.param<std::string>("type", type, "map");
|
||||
nh_priv_.param<std::string>("frame_id", transform_.child_frame_id, "aruco_map");
|
||||
nh_priv_.param<std::string>("known_tilt", known_tilt_, "");
|
||||
nh_priv_.param("auto_flip", auto_flip_, false);
|
||||
nh_priv_.param("image_width", image_width_, 2000);
|
||||
nh_priv_.param("image_height", image_height_, 2000);
|
||||
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_, "");
|
||||
type = nh_priv_.param<std::string>("type", "map");
|
||||
transform_.child_frame_id = nh_priv_.param<std::string>("frame_id", "aruco_map");
|
||||
known_tilt_ = nh_priv_.param<std::string>("known_tilt", "");
|
||||
auto_flip_ = nh_priv_.param("auto_flip", false);
|
||||
image_width_ = nh_priv_.param("image_width" , 2000);
|
||||
image_height_ = nh_priv_.param("image_height", 2000);
|
||||
image_margin_ = nh_priv_.param("image_margin", 200);
|
||||
image_axis_ = nh_priv_.param("image_axis", true);
|
||||
markers_parent_frame_ = nh_priv_.param<std::string>("markers/frame_id", transform_.child_frame_id);
|
||||
markers_frame_ = nh_priv_.param<std::string>("markers/child_frame_id_prefix", "");
|
||||
|
||||
// createStripLine();
|
||||
|
||||
@@ -116,7 +114,7 @@ public:
|
||||
param(nh_priv_, "map", map);
|
||||
loadMap(map);
|
||||
} else if (type == "gridboard") {
|
||||
createGridBoard();
|
||||
createGridBoard(nh_priv_);
|
||||
} else {
|
||||
NODELET_FATAL("unknown type: %s", type.c_str());
|
||||
ros::shutdown();
|
||||
@@ -331,7 +329,7 @@ publish_debug:
|
||||
NODELET_INFO("loading %s complete (%d markers)", filename.c_str(), static_cast<int>(board_->ids.size()));
|
||||
}
|
||||
|
||||
void createGridBoard()
|
||||
void createGridBoard(ros::NodeHandle& nh)
|
||||
{
|
||||
NODELET_INFO("generate gridboard");
|
||||
NODELET_WARN("gridboard maps are deprecated");
|
||||
@@ -339,15 +337,15 @@ publish_debug:
|
||||
int markers_x, markers_y, first_marker;
|
||||
double markers_side, markers_sep_x, markers_sep_y;
|
||||
std::vector<int> marker_ids;
|
||||
nh_priv_.param<int>("markers_x", markers_x, 10);
|
||||
nh_priv_.param<int>("markers_y", markers_y, 10);
|
||||
nh_priv_.param<int>("first_marker", first_marker, 0);
|
||||
markers_x = nh.param("markers_x", 10);
|
||||
markers_y = nh.param("markers_y", 10);
|
||||
first_marker = nh.param("first_marker", 0);
|
||||
|
||||
param(nh_priv_, "markers_side", markers_side);
|
||||
param(nh_priv_, "markers_sep_x", markers_sep_x);
|
||||
param(nh_priv_, "markers_sep_y", markers_sep_y);
|
||||
param(nh, "markers_side", markers_side);
|
||||
param(nh, "markers_sep_x", markers_sep_x);
|
||||
param(nh, "markers_sep_y", markers_sep_y);
|
||||
|
||||
if (nh_priv_.getParam("marker_ids", marker_ids)) {
|
||||
if (nh.getParam("marker_ids", marker_ids)) {
|
||||
if ((unsigned int)(markers_x * markers_y) != marker_ids.size()) {
|
||||
NODELET_FATAL("~marker_ids length should be equal to ~markers_x * ~markers_y");
|
||||
ros::shutdown();
|
||||
@@ -394,7 +392,7 @@ publish_debug:
|
||||
int num_markers = board_->dictionary->bytesList.rows;
|
||||
if (num_markers <= id) {
|
||||
NODELET_ERROR("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",
|
||||
"Please see https://github.com/CopterExpress/clover/blob/master/aruco_pose/README.md#parameters for details",
|
||||
id, num_markers);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (C) 2018 Copter Express Technologies
|
||||
#
|
||||
|
||||
@@ -35,9 +35,7 @@ static void parseCameraInfo(const sensor_msgs::CameraInfoConstPtr& cinfo, cv::Ma
|
||||
for (unsigned int i = 0; i < 3; ++i)
|
||||
for (unsigned int j = 0; j < 3; ++j)
|
||||
matrix.at<double>(i, j) = cinfo->K[3 * i + j];
|
||||
|
||||
for (unsigned int k = 0; k < cinfo->D.size(); k++)
|
||||
dist.at<double>(k) = cinfo->D[k];
|
||||
dist = cv::Mat(cinfo->D, true);
|
||||
}
|
||||
|
||||
inline void rotatePoint(cv::Point3f& p, cv::Point3f origin, float angle)
|
||||
|
||||
BIN
aruco_pose/test/crash_image_01.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
aruco_pose/test/crash_image_02.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
aruco_pose/test/crash_image_03.png
Normal file
|
After Width: | Height: | Size: 165 KiB |
18
aruco_pose/test/crash_opencv.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import rospy
|
||||
import pytest
|
||||
|
||||
from visualization_msgs.msg import MarkerArray as VisMarkerArray
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def node():
|
||||
return rospy.init_node('aruco_pose_opencv_crash', anonymous=True)
|
||||
|
||||
def test_opencv_crashes_img01(node):
|
||||
rospy.wait_for_message('aruco_detect_01/visualization', VisMarkerArray, timeout=5)
|
||||
|
||||
def test_opencv_crashes_img02(node):
|
||||
rospy.wait_for_message('aruco_detect_02/visualization', VisMarkerArray, timeout=5)
|
||||
|
||||
def test_opencv_crashes_img03(node):
|
||||
rospy.wait_for_message('aruco_detect_03/visualization', VisMarkerArray, timeout=5)
|
||||
51
aruco_pose/test/crash_opencv.test
Normal file
@@ -0,0 +1,51 @@
|
||||
<launch>
|
||||
<arg name="corner_method" default="2"/>
|
||||
|
||||
<node pkg="image_publisher" type="image_publisher" name="imgpub_01" args="$(find aruco_pose)/test/crash_image_01.png">
|
||||
<param name="frame_id" value="main_camera_optical"/>
|
||||
<param name="publish_rate" value="10"/>
|
||||
<param name="camera_info_url" value="file://$(find aruco_pose)/test/camera_info.yaml" />
|
||||
</node>
|
||||
|
||||
<node pkg="image_publisher" type="image_publisher" name="imgpub_02" args="$(find aruco_pose)/test/crash_image_02.png">
|
||||
<param name="frame_id" value="main_camera_optical"/>
|
||||
<param name="publish_rate" value="10"/>
|
||||
<param name="camera_info_url" value="file://$(find aruco_pose)/test/camera_info.yaml" />
|
||||
</node>
|
||||
|
||||
<node pkg="image_publisher" type="image_publisher" name="imgpub_03" args="$(find aruco_pose)/test/crash_image_03.png">
|
||||
<param name="frame_id" value="main_camera_optical"/>
|
||||
<param name="publish_rate" value="10"/>
|
||||
<param name="camera_info_url" value="file://$(find aruco_pose)/test/camera_info.yaml" />
|
||||
</node>
|
||||
|
||||
<node pkg="nodelet" type="nodelet" name="nodelet_manager_01" args="manager"/>
|
||||
|
||||
<node pkg="nodelet" clear_params="true" type="nodelet" name="aruco_detect_01" args="load aruco_pose/aruco_detect nodelet_manager_01">
|
||||
<remap from="image_raw" to="imgpub_01/image_raw"/>
|
||||
<remap from="camera_info" to="imgpub_01/camera_info"/>
|
||||
<param name="length" value="0.33"/>
|
||||
<param name="cornerRefinementMethod" value="$(arg corner_method)"/>
|
||||
</node>
|
||||
|
||||
<node pkg="nodelet" type="nodelet" name="nodelet_manager_02" args="manager"/>
|
||||
|
||||
<node pkg="nodelet" clear_params="true" type="nodelet" name="aruco_detect_02" args="load aruco_pose/aruco_detect nodelet_manager_02">
|
||||
<remap from="image_raw" to="imgpub_02/image_raw"/>
|
||||
<remap from="camera_info" to="imgpub_02/camera_info"/>
|
||||
<param name="length" value="0.33"/>
|
||||
<param name="cornerRefinementMethod" value="$(arg corner_method)"/>
|
||||
</node>
|
||||
|
||||
<node pkg="nodelet" type="nodelet" name="nodelet_manager_03" args="manager"/>
|
||||
|
||||
<node pkg="nodelet" clear_params="true" type="nodelet" name="aruco_detect_03" args="load aruco_pose/aruco_detect nodelet_manager_03">
|
||||
<remap from="image_raw" to="imgpub_03/image_raw"/>
|
||||
<remap from="camera_info" to="imgpub_03/camera_info"/>
|
||||
<param name="length" value="0.33"/>
|
||||
<param name="cornerRefinementMethod" value="$(arg corner_method)"/>
|
||||
</node>
|
||||
|
||||
<param name="test_module" value="$(find aruco_pose)/test/crash_opencv.py"/>
|
||||
<test test-name="crash_opencv" pkg="ros_pytest" type="ros_pytest_runner"/>
|
||||
</launch>
|
||||
@@ -1,19 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import unittest
|
||||
import json
|
||||
import rospy
|
||||
import pytest
|
||||
import rostest
|
||||
|
||||
from sensor_msgs.msg import Image
|
||||
from visualization_msgs.msg import MarkerArray as VisMarkerArray
|
||||
|
||||
@pytest.fixture
|
||||
def node():
|
||||
return rospy.init_node('test_aruco_largemap', anonymous=True)
|
||||
|
||||
def test_large_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 in ('mono8', 'rgb8')
|
||||
class TestArucoPose(unittest.TestCase):
|
||||
def setUp(self):
|
||||
rospy.init_node('test_aruco_largemap', anonymous=True)
|
||||
|
||||
def test_large_map_visualization(node):
|
||||
vis = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
|
||||
assert len(vis.markers) == 11
|
||||
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.assertIn(img.encoding, ('mono8', 'rgb8'))
|
||||
|
||||
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)
|
||||
|
||||
@@ -9,6 +9,5 @@
|
||||
<param name="map" value="$(find aruco_pose)/test/largemap.txt"/>
|
||||
</node>
|
||||
|
||||
<param name="test_module" value="$(find aruco_pose)/test/largemap.py"/>
|
||||
<test test-name="test_node_pass" pkg="ros_pytest" type="ros_pytest_runner"/>
|
||||
<test test-name="test_aruco_pose_largemap" pkg="aruco_pose" type="largemap.py"/>
|
||||
</launch>
|
||||
|
||||
2
aruco_pose/vendor/aruco/src/aruco.cpp
vendored
@@ -924,6 +924,8 @@ static void _refineCandidateLines(std::vector<Point>& nContours, std::vector<Poi
|
||||
// calculate the line :: who passes through the grouped points
|
||||
Point3f lines[4];
|
||||
for(int i=0; i<4; i++){
|
||||
// Don't try to "interpolate" single points
|
||||
if (cntPts[i].size() < 2) return;
|
||||
lines[i]=_interpolate2Dline(cntPts[i]);
|
||||
}
|
||||
|
||||
|
||||
12
book.json
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"title": "Clever",
|
||||
"title": "Clover",
|
||||
"description": "Конструктор квадрокоптера «Клевер»",
|
||||
"author": "Copter Express",
|
||||
"language": "en",
|
||||
@@ -28,7 +28,7 @@
|
||||
"blank": true
|
||||
},
|
||||
"sitemap": {
|
||||
"hostname": "https://clever.coex.tech"
|
||||
"hostname": "https://clover.coex.tech"
|
||||
},
|
||||
"toolbar": {
|
||||
"buttons":
|
||||
@@ -37,19 +37,19 @@
|
||||
"label": "Edit page on github",
|
||||
"icon": "fa fa-pencil-square-o",
|
||||
"position" : "left",
|
||||
"url": "https://github.com/CopterExpress/clever/edit/master/docs/{{filepath_lang}}"
|
||||
"url": "https://github.com/CopterExpress/clover/edit/master/docs/{{filepath_lang}}"
|
||||
},
|
||||
{
|
||||
"label": "GitHub",
|
||||
"icon": "fa fa-github",
|
||||
"position" : "left",
|
||||
"url": "https://github.com/CopterExpress/clever"
|
||||
"url": "https://github.com/CopterExpress/clover"
|
||||
}
|
||||
]
|
||||
},
|
||||
"addcssjs": {
|
||||
"css": ["../clever.css"],
|
||||
"js": ["../clever.js"]
|
||||
"css": ["../clover.css"],
|
||||
"js": ["../clover.js"]
|
||||
},
|
||||
"language-picker": {
|
||||
"languages": [["ru", "Russian"], ["en", "English"]]
|
||||
|
||||
34
builder/assets/avahi-services/sftp-ssh.service
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
|
||||
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
|
||||
|
||||
<!--
|
||||
This file is part of avahi.
|
||||
|
||||
avahi is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
avahi is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with avahi; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA.
|
||||
-->
|
||||
|
||||
<!-- See avahi.service(5) for more information about this configuration file -->
|
||||
|
||||
<service-group>
|
||||
|
||||
<name replace-wildcards="yes">%h</name>
|
||||
|
||||
<service>
|
||||
<type>_sftp-ssh._tcp</type>
|
||||
<port>22</port>
|
||||
</service>
|
||||
|
||||
</service-group>
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Information: https://clever.coex.tech/en/programming.html
|
||||
# Information: https://clover.coex.tech/programming
|
||||
|
||||
import rospy
|
||||
from clover import srv
|
||||
@@ -15,7 +15,7 @@ set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)
|
||||
set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)
|
||||
land = rospy.ServiceProxy('land', Trigger)
|
||||
|
||||
# Takeoff and hover 1 m above the ground
|
||||
# Take off and hover 1 m above the ground
|
||||
navigate(x=0, y=0, z=1, frame_id='body', auto_arm=True)
|
||||
|
||||
# Wait for 3 seconds
|
||||
|
||||
37
builder/assets/examples/flight_marker.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Information: https://clover.coex.tech/en/aruco.html
|
||||
|
||||
import rospy
|
||||
from clover import srv
|
||||
from std_srvs.srv import Trigger
|
||||
|
||||
rospy.init_node('flight')
|
||||
|
||||
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
|
||||
navigate = rospy.ServiceProxy('navigate', srv.Navigate)
|
||||
navigate_global = rospy.ServiceProxy('navigate_global', srv.NavigateGlobal)
|
||||
set_position = rospy.ServiceProxy('set_position', srv.SetPosition)
|
||||
set_velocity = rospy.ServiceProxy('set_velocity', srv.SetVelocity)
|
||||
set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)
|
||||
set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)
|
||||
land = rospy.ServiceProxy('land', Trigger)
|
||||
|
||||
# Take off and hover 1 m above the ground
|
||||
navigate(x=0, y=0, z=1, frame_id='body', auto_arm=True)
|
||||
|
||||
# Wait for 3 seconds
|
||||
rospy.sleep(3)
|
||||
|
||||
# Fly 1 meter above ArUco marker 0
|
||||
navigate(x=0, y=0, z=1, frame_id='aruco_0')
|
||||
|
||||
# Wait for 3 seconds
|
||||
rospy.sleep(3)
|
||||
|
||||
# Fly to x=1 y=1 z=1 relative to ArUco markers map
|
||||
navigate(x=1, y=1, z=1, frame_id='aruco_map')
|
||||
|
||||
# Wait for 3 seconds
|
||||
rospy.sleep(3)
|
||||
|
||||
# Perform landing
|
||||
land()
|
||||
@@ -1,4 +1,4 @@
|
||||
# Information: https://clever.coex.tech/en/leds.html
|
||||
# Information: https://clover.coex.tech/en/leds.html
|
||||
|
||||
import rospy
|
||||
from clover.srv import SetLEDEffect
|
||||
|
||||
41
builder/assets/examples/navigate_wait.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# Information: https://clover.coex.tech/en/snippets.html#block-nav
|
||||
|
||||
import math
|
||||
import rospy
|
||||
from clover import srv
|
||||
from std_srvs.srv import Trigger
|
||||
|
||||
rospy.init_node('flight')
|
||||
|
||||
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
|
||||
navigate = rospy.ServiceProxy('navigate', srv.Navigate)
|
||||
navigate_global = rospy.ServiceProxy('navigate_global', srv.NavigateGlobal)
|
||||
set_position = rospy.ServiceProxy('set_position', srv.SetPosition)
|
||||
set_velocity = rospy.ServiceProxy('set_velocity', srv.SetVelocity)
|
||||
set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)
|
||||
set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)
|
||||
land = rospy.ServiceProxy('land', Trigger)
|
||||
|
||||
def navigate_wait(x=0, y=0, z=0, yaw=float('nan'), yaw_rate=0, speed=0.5, \
|
||||
frame_id='body', tolerance=0.2, auto_arm=False):
|
||||
|
||||
res = navigate(x=x, y=y, z=z, yaw=yaw, yaw_rate=yaw_rate, speed=speed, \
|
||||
frame_id=frame_id, auto_arm=auto_arm)
|
||||
|
||||
if not res.success:
|
||||
return res
|
||||
|
||||
while not rospy.is_shutdown():
|
||||
telem = get_telemetry(frame_id='navigate_target')
|
||||
if math.sqrt(telem.x ** 2 + telem.y ** 2 + telem.z ** 2) < tolerance:
|
||||
return res
|
||||
rospy.sleep(0.2)
|
||||
|
||||
# Take off 1 meter
|
||||
navigate_wait(z=1, frame_id='body', auto_arm=True)
|
||||
|
||||
# Fly forward 1 m
|
||||
navigate_wait(x=1, frame_id='body')
|
||||
|
||||
# Land
|
||||
land()
|
||||
@@ -62,6 +62,10 @@ hostnamectl set-hostname $NEW_HOSTNAME
|
||||
sed -i 's/127\.0\.1\.1.*/127.0.1.1\t'${NEW_HOSTNAME}' '${NEW_HOSTNAME}'.local/g' /etc/hosts
|
||||
# .local (mdns) hostname added to make it accesable when wlan and ethernet interfaces are down
|
||||
|
||||
echo_stamp "Enable ROS services"
|
||||
systemctl enable roscore
|
||||
systemctl enable clover
|
||||
|
||||
echo_stamp "Harware setup"
|
||||
/root/hardware_setup.sh
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
# Example:
|
||||
# DocumentRoot /home/krypton/htdocs
|
||||
|
||||
DocumentRoot /home/pi/catkin_ws/src/clover/clover/www
|
||||
DocumentRoot /home/pi/.ros/www
|
||||
|
||||
# Redirect:
|
||||
# ---------
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
python3-wxgtk:
|
||||
debian:
|
||||
buster: [python3-wxgtk4.0]
|
||||
python3-serial:
|
||||
debian:
|
||||
buster: [python3-serial]
|
||||
python3-requests:
|
||||
debian:
|
||||
buster: [python3-requests]
|
||||
@@ -108,6 +108,8 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-software
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/examples' '/home/pi/'
|
||||
# network setup
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-network.sh'
|
||||
# avahi setup
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/avahi-services/sftp-ssh.service' '/etc/avahi/services'
|
||||
|
||||
# If RPi then use a one thread to build a ROS package on RPi, else use all
|
||||
[[ $(arch) == 'armv7l' ]] && NUMBER_THREADS=1 || NUMBER_THREADS=$(nproc --all)
|
||||
@@ -115,7 +117,6 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-network.
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clover.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/melodic-rosdep-clover.yaml' '/etc/ros/rosdep/'
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/python3.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/pigpiod.service' '/lib/systemd/system/'
|
||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/launch.nanorc' '/usr/share/nano/'
|
||||
|
||||
@@ -68,8 +68,7 @@ my_travis_retry() {
|
||||
# TODO: 'kinetic-rosdep-clover.yaml' should add only if we use our repo?
|
||||
echo_stamp "Init rosdep"
|
||||
my_travis_retry rosdep init
|
||||
echo "yaml file:///etc/ros/rosdep/melodic-rosdep-clover.yaml" > /etc/ros/rosdep/sources.list.d/30-clover.list
|
||||
echo "yaml file:///etc/ros/rosdep/python3.yaml" > /etc/ros/rosdep/sources.list.d/40-python3.list
|
||||
echo "yaml file:///etc/ros/rosdep/melodic-rosdep-clover.yaml" >> /etc/ros/rosdep/sources.list.d/20-default.list
|
||||
my_travis_retry rosdep update
|
||||
|
||||
echo_stamp "Populate rosdep for ROS user"
|
||||
@@ -88,7 +87,6 @@ resolve_rosdep() {
|
||||
}
|
||||
|
||||
export ROS_IP='127.0.0.1' # needed for running tests
|
||||
export ROS_PYTHON_VERSION=3
|
||||
|
||||
echo_stamp "Reconfiguring Clover repository for simplier unshallowing"
|
||||
cd /home/pi/catkin_ws/src/clover
|
||||
@@ -97,15 +95,11 @@ git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
|
||||
echo_stamp "Build and install Clover"
|
||||
cd /home/pi/catkin_ws
|
||||
resolve_rosdep $(pwd)
|
||||
my_travis_retry pip3 install wheel
|
||||
my_travis_retry pip3 install -r /home/pi/catkin_ws/src/clover/clover/requirements.txt
|
||||
my_travis_retry pip install wheel
|
||||
my_travis_retry pip install -r /home/pi/catkin_ws/src/clover/clover/requirements.txt
|
||||
source /opt/ros/melodic/setup.bash
|
||||
catkin_make -j2 -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
echo_stamp "Enable ROS services"
|
||||
systemctl enable roscore
|
||||
systemctl enable clover
|
||||
|
||||
echo_stamp "Install clever package (for backwards compatibility)"
|
||||
cd /home/pi/catkin_ws/src/clover/builder/assets/clever
|
||||
./setup.py install
|
||||
@@ -135,7 +129,7 @@ echo_stamp "Install GeographicLib datasets (needed for mavros)" \
|
||||
|
||||
# FIXME: Buster comes with tornado==5.1.1 but we need tornado==4.2.1 for rosbridge_suite
|
||||
# (note that Python 3 will still have a more recent version)
|
||||
pip3 install tornado==4.2.1
|
||||
pip install tornado==4.2.1
|
||||
|
||||
echo_stamp "Running tests"
|
||||
cd /home/pi/catkin_ws
|
||||
@@ -149,7 +143,6 @@ echo_stamp "Setup ROS environment"
|
||||
cat << EOF >> /home/pi/.bashrc
|
||||
LANG='C.UTF-8'
|
||||
LC_ALL='C.UTF-8'
|
||||
ROS_DISTRO='melodic'
|
||||
export ROS_HOSTNAME=\`hostname\`.local
|
||||
source /opt/ros/melodic/setup.bash
|
||||
source /home/pi/catkin_ws/devel/setup.bash
|
||||
|
||||
@@ -57,6 +57,10 @@ my_travis_retry() {
|
||||
return $result
|
||||
}
|
||||
|
||||
echo_stamp "Increase apt retries"
|
||||
|
||||
echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
|
||||
|
||||
echo_stamp "Install apt keys & repos"
|
||||
|
||||
# TODO: This STDOUT consist 'OK'
|
||||
@@ -67,7 +71,7 @@ apt-get update \
|
||||
|
||||
echo "deb http://packages.ros.org/ros/ubuntu buster main" > /etc/apt/sources.list.d/ros-latest.list
|
||||
echo "deb http://deb.coex.tech/opencv3 buster main" > /etc/apt/sources.list.d/opencv3.list
|
||||
echo "deb http://deb.coex.tech/melodic-py3 buster main" > /etc/apt/sources.list.d/rpi-ros-melodic.list
|
||||
echo "deb http://deb.coex.tech/rpi-ros-melodic buster main" > /etc/apt/sources.list.d/rpi-ros-melodic.list
|
||||
echo "deb http://deb.coex.tech/clover buster main" > /etc/apt/sources.list.d/clover.list
|
||||
|
||||
echo_stamp "Update apt cache"
|
||||
@@ -95,21 +99,21 @@ libjpeg8 \
|
||||
tcpdump \
|
||||
ltrace \
|
||||
libpoco-dev \
|
||||
python3-rosdep \
|
||||
python3-rosinstall-generator \
|
||||
python3-wstool \
|
||||
python3-rosinstall \
|
||||
libzbar0 \
|
||||
python-rosdep \
|
||||
python-rosinstall-generator \
|
||||
python-wstool \
|
||||
python-rosinstall \
|
||||
build-essential \
|
||||
libffi-dev \
|
||||
monkey \
|
||||
pigpio python-pigpio python3-pigpio \
|
||||
i2c-tools \
|
||||
espeak espeak-data python3-espeak \
|
||||
espeak espeak-data python-espeak \
|
||||
ntpdate \
|
||||
python-dev \
|
||||
python3-dev \
|
||||
python3-venv \
|
||||
python3-systemd \
|
||||
python-systemd \
|
||||
mjpg-streamer \
|
||||
python3-opencv \
|
||||
&& echo_stamp "Everything was installed!" "SUCCESS" \
|
||||
@@ -133,14 +137,13 @@ pip3 --version
|
||||
|
||||
echo_stamp "Install and enable Butterfly (web terminal)"
|
||||
echo_stamp "Workaround for tornado >= 6.0 breaking butterfly"
|
||||
my_travis_retry pip3 install tornado==4.2.1
|
||||
my_travis_retry pip3 install tornado==5.1.1
|
||||
my_travis_retry pip3 install butterfly
|
||||
my_travis_retry pip3 install butterfly[systemd]
|
||||
systemctl enable butterfly.socket
|
||||
|
||||
echo_stamp "Install ws281x library"
|
||||
my_travis_retry pip2 install --prefer-binary rpi_ws281x
|
||||
my_travis_retry pip3 install --prefer-binary rpi_ws281x
|
||||
my_travis_retry pip install --prefer-binary rpi_ws281x
|
||||
|
||||
echo_stamp "Setup Monkey"
|
||||
mv /etc/monkey/sites/default /etc/monkey/sites/default.orig
|
||||
@@ -156,9 +159,13 @@ rm -rf node-v10.15.0-linux-armv6l/
|
||||
rm node-v10.15.0-linux-armv6l.tar.gz
|
||||
|
||||
echo_stamp "Installing ptvsd"
|
||||
my_travis_retry pip2 install ptvsd
|
||||
my_travis_retry pip install ptvsd
|
||||
my_travis_retry pip3 install ptvsd
|
||||
|
||||
echo_stamp "Installing pyzbar"
|
||||
my_travis_retry pip install pyzbar
|
||||
my_travis_retry pip3 install pyzbar
|
||||
|
||||
echo_stamp "Add .vimrc"
|
||||
cat << EOF > /home/pi/.vimrc
|
||||
set mouse-=a
|
||||
|
||||
@@ -18,15 +18,13 @@ echo "Run image tests"
|
||||
|
||||
export ROS_DISTRO='melodic'
|
||||
export ROS_IP='127.0.0.1'
|
||||
export ROS_PYTHON_VERSION=3
|
||||
source /opt/ros/melodic/setup.bash
|
||||
source /home/pi/catkin_ws/devel/setup.bash
|
||||
|
||||
cd /home/pi/catkin_ws/src/clover/builder/test/
|
||||
./tests.sh
|
||||
./tests.py
|
||||
# Disable Python 2 tests for image - we're dropping support, right?
|
||||
# ./tests_py2.py
|
||||
./tests_py3.py
|
||||
[[ $(./tests_clever.py) == "Warning: clever package is renamed to clover" ]] # test backwards compatibility
|
||||
|
||||
echo "Move /etc/ld.so.preload back to its original position"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Perform a "standalone install" in a Docker container
|
||||
|
||||
set -e
|
||||
# Step 1: Install pip
|
||||
apt update
|
||||
apt install -y curl
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
|
||||
# validate all required modules installed
|
||||
|
||||
@@ -17,8 +17,6 @@ from std_srvs.srv import Trigger
|
||||
from clover.srv import GetTelemetry, Navigate, NavigateGlobal, SetPosition, SetVelocity, \
|
||||
SetAttitude, SetRates, SetLEDEffect
|
||||
|
||||
get_telemetry = rospy.ServiceProxy('get_telemetry', GetTelemetry)
|
||||
|
||||
import tf2_ros
|
||||
import tf2_geometry_msgs
|
||||
|
||||
@@ -28,5 +26,6 @@ from pymavlink import mavutil
|
||||
import rpi_ws281x
|
||||
import pigpio
|
||||
from espeak import espeak
|
||||
from pyzbar import pyzbar
|
||||
|
||||
print(cv2.getBuildInformation())
|
||||
print cv2.getBuildInformation()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
|
||||
# test backwards compatibility
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Make sure our Python 2 software is installed
|
||||
|
||||
import cv2
|
||||
|
||||
print(cv2.getBuildInformation())
|
||||
8
builder/test/tests_py3.py
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Make sure our Python 3 software is installed
|
||||
|
||||
import cv2
|
||||
from pyzbar import pyzbar
|
||||
|
||||
print(cv2.getBuildInformation())
|
||||
@@ -30,6 +30,12 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||
|
||||
find_package(GeographicLib REQUIRED)
|
||||
|
||||
find_package(OpenCV 3 REQUIRED
|
||||
COMPONENTS
|
||||
calib3d
|
||||
imgproc
|
||||
)
|
||||
|
||||
## System dependencies are found with CMake's conventions
|
||||
# find_package(Boost REQUIRED COMPONENTS system)
|
||||
|
||||
@@ -204,6 +210,7 @@ add_dependencies(shell ${PROJECT_NAME}_generate_messages_cpp)
|
||||
## Specify libraries to link a library or executable target against
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
${catkin_LIBRARIES}
|
||||
${OpenCV_LIBRARIES}
|
||||
)
|
||||
|
||||
#############
|
||||
|
||||
73
clover/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# `clover` ROS package
|
||||
|
||||
A bundle for autonomous navigation and drone control.
|
||||
|
||||
## Manual installation
|
||||
|
||||
Install ROS Melodic according to the [documentation](http://wiki.ros.org/melodic/Installation), then [create a Catkin workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace).
|
||||
|
||||
Clone this repo to directory `~/catkin_ws/src/clover`:
|
||||
|
||||
```bash
|
||||
cd ~/catkin_ws/src
|
||||
git clone https://github.com/CopterExpress/clover.git clover
|
||||
```
|
||||
|
||||
All the required ROS packages (including `mavros` and `opencv`) can be installed using `rosdep`:
|
||||
|
||||
```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
|
||||
cd ~/catkin_ws
|
||||
catkin_make -j1
|
||||
```
|
||||
|
||||
To complete `mavros` install you'll need to install `geographiclib` datasets:
|
||||
|
||||
```bash
|
||||
curl https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | sudo bash
|
||||
```
|
||||
|
||||
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/clover/clover/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/clover/builder/assets/roscore.service
|
||||
sudo systemctl start roscore
|
||||
```
|
||||
|
||||
To start connection to SITL, use:
|
||||
|
||||
```bash
|
||||
roslaunch clover sitl.launch
|
||||
```
|
||||
|
||||
To start connection to the flight controller, use:
|
||||
|
||||
```bash
|
||||
roslaunch clover clover.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/clover/deploy/clover.service
|
||||
sudo systemctl start clover
|
||||
```
|
||||
@@ -1,17 +1,17 @@
|
||||
image_width: 640
|
||||
image_height: 480
|
||||
distortion_model: plumb_bob
|
||||
camera_name: raspicam
|
||||
camera_name: main_camera_optical
|
||||
camera_matrix:
|
||||
rows: 3
|
||||
cols: 3
|
||||
data:
|
||||
- 332.47884746146343
|
||||
- 0.
|
||||
- 324.38022493658536
|
||||
- 320.0
|
||||
- 0.
|
||||
- 333.1761847948052
|
||||
- 219.6445547142857
|
||||
- 240.0
|
||||
- 0.
|
||||
- 0.
|
||||
- 1.
|
||||
@@ -1,45 +0,0 @@
|
||||
image_width: 320
|
||||
image_height: 240
|
||||
distortion_model: plumb_bob
|
||||
camera_name: raspicam
|
||||
camera_matrix:
|
||||
rows: 3
|
||||
cols: 3
|
||||
data:
|
||||
- 166.23942373073172
|
||||
- 0.
|
||||
- 162.19011246829268
|
||||
- 0.
|
||||
- 166.5880923974026
|
||||
- 109.82227735714285
|
||||
- 0.
|
||||
- 0.
|
||||
- 1.
|
||||
distortion_coefficients:
|
||||
rows: 1
|
||||
cols: 8
|
||||
data: [ 2.15356885e-01, -1.17472846e-01, -3.06197672e-04,
|
||||
-1.09444025e-04, -4.53657258e-03, 5.73090623e-01,
|
||||
-1.27574577e-01, -2.86125589e-02, 0.00000000e+00,
|
||||
0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
|
||||
0.00000000e+00, 0.00000000e+00]
|
||||
rectification_matrix:
|
||||
rows: 3
|
||||
cols: 3
|
||||
data: [1, 0, 0, 0, 1, 0, 0, 0, 1]
|
||||
projection_matrix:
|
||||
rows: 3
|
||||
cols: 4
|
||||
data:
|
||||
- 166.23942373073172
|
||||
- 0.
|
||||
- 162.19011246829268
|
||||
- 0.
|
||||
- 0.
|
||||
- 166.5880923974026
|
||||
- 109.82227735714285
|
||||
- 0.
|
||||
- 0.
|
||||
- 0.
|
||||
- 1.
|
||||
- 0.
|
||||
@@ -3,18 +3,20 @@
|
||||
<arg name="aruco_map" default="false"/>
|
||||
<arg name="aruco_vpe" default="false"/>
|
||||
|
||||
<!-- For additional help go to https://clever.coex.tech/aruco -->
|
||||
<!-- For additional help go to https://clover.coex.tech/aruco -->
|
||||
|
||||
<!-- aruco_detect: detect aruco markers, estimate poses -->
|
||||
<node name="aruco_detect" pkg="nodelet" if="$(arg aruco_detect)" type="nodelet" args="load aruco_pose/aruco_detect nodelet_manager" output="screen" clear_params="true">
|
||||
<remap from="image_raw" to="main_camera/image_raw"/>
|
||||
<remap from="camera_info" to="main_camera/camera_info"/>
|
||||
<remap from="map_markers" to="aruco_map/markers" if="$(arg aruco_map)"/>
|
||||
<param name="cornerRefinementMethod" value="2"/>
|
||||
<param name="estimate_poses" value="true"/>
|
||||
<param name="send_tf" value="true"/>
|
||||
<param name="known_tilt" value="map"/>
|
||||
<param name="length" value="0.33"/>
|
||||
<!-- aruco detector parameters -->
|
||||
<param name="cornerRefinementMethod" value="2"/> <!-- contour refinement -->
|
||||
<param name="minMarkerPerimeterRate" value="0.075"/> <!-- 0.075 for 320x240, 0.0375 for 640x480 -->
|
||||
</node>
|
||||
|
||||
<!-- aruco_map: estimate aruco map pose -->
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<launch>
|
||||
<arg name="fcu_conn" default="usb"/>
|
||||
<arg name="fcu_ip" default="127.0.0.1"/>
|
||||
<arg name="fcu_sys_id" default="1"/>
|
||||
<arg name="gcs_bridge" default="tcp"/>
|
||||
<arg name="web_video_server" default="true"/>
|
||||
<arg name="rosbridge" default="true"/>
|
||||
@@ -19,6 +20,7 @@
|
||||
<include file="$(find clover)/launch/mavros.launch">
|
||||
<arg name="fcu_conn" value="$(arg fcu_conn)"/>
|
||||
<arg name="fcu_ip" value="$(arg fcu_ip)"/>
|
||||
<arg name="fcu_sys_id" value="$(arg fcu_sys_id)"/>
|
||||
<arg name="gcs_bridge" value="$(arg gcs_bridge)"/>
|
||||
</include>
|
||||
|
||||
@@ -80,4 +82,9 @@
|
||||
|
||||
<!-- Shell access through ROS service -->
|
||||
<node name="shell" pkg="clover" type="shell" output="screen" if="$(arg shell)"/>
|
||||
|
||||
<!-- Update static directory -->
|
||||
<node pkg="roswww_static" name="roswww_static" type="main.py" clear_params="true">
|
||||
<param name="default_package" value="clover"/>
|
||||
</node>
|
||||
</launch>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<launch>
|
||||
<!-- article about camera setup: https://clever.coex.tech/camera_frame -->
|
||||
<!-- article about camera setup: https://clover.coex.tech/camera_setup -->
|
||||
|
||||
<arg name="direction_z" default="down"/> <!-- direction the camera points: down, up -->
|
||||
<arg name="direction_y" default="backward"/> <!-- direction the camera cable points: backward, forward -->
|
||||
@@ -18,14 +18,14 @@
|
||||
<node pkg="nodelet" type="nodelet" name="main_camera" args="load cv_camera/CvCameraNodelet nodelet_manager" clear_params="true">
|
||||
<param name="device_path" value="/dev/video0"/> <!-- v4l2 device -->
|
||||
<param name="frame_id" value="main_camera_optical"/>
|
||||
<param name="camera_info_url" value="file://$(find clover)/camera_info/fisheye_cam_320.yaml"/>
|
||||
<param name="camera_info_url" value="file://$(find clover)/camera_info/fisheye_cam.yaml"/>
|
||||
|
||||
<param name="rate" value="100"/> <!-- poll rate -->
|
||||
<param name="cv_cap_prop_fps" value="40"/> <!-- camera FPS -->
|
||||
<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 -->
|
||||
<param name="image_width" value="320"/>
|
||||
<param name="image_height" value="240"/>
|
||||
</node>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<launch>
|
||||
<arg name="fcu_conn" default="usb"/> <!-- options: usb, uart, tcp, udp, sitl -->
|
||||
<arg name="fcu_ip" default="127.0.0.1"/>
|
||||
<arg name="fcu_sys_id" default="1"/>
|
||||
<arg name="gcs_bridge" default="tcp"/>
|
||||
<arg name="viz" default="true"/>
|
||||
<arg name="respawn" default="true"/>
|
||||
@@ -19,6 +20,9 @@
|
||||
<!-- sitl since PX4 1.9.0 -->
|
||||
<param name="fcu_url" value="udp://@$(arg fcu_ip):14580" if="$(eval fcu_conn == 'sitl')"/>
|
||||
|
||||
<!-- set target_system_id -->
|
||||
<param name="target_system_id" value="$(arg fcu_sys_id)" />
|
||||
|
||||
<!-- gcs bridge -->
|
||||
<param name="gcs_url" value="tcp-l://0.0.0.0:5760" if="$(eval gcs_bridge == 'tcp')"/>
|
||||
<param name="gcs_url" value="udp://0.0.0.0:14550@14550" if="$(eval gcs_bridge == 'udp')"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<package format="3">
|
||||
<package format="2">
|
||||
<name>clover</name>
|
||||
<version>0.0.1</version>
|
||||
<description>The Clover package</description>
|
||||
@@ -7,7 +7,7 @@
|
||||
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
|
||||
<license>MIT</license>
|
||||
|
||||
<url type="website">https://clever.coex.tech/</url>
|
||||
<url type="website">https://clover.coex.tech/</url>
|
||||
<author email="okalachev@gmail.com">Oleg Kalachev</author>
|
||||
<author email="urpylka@gmail.com">Artem Smirnov</author>
|
||||
|
||||
@@ -37,10 +37,8 @@
|
||||
<depend>rosbridge_server</depend>
|
||||
<depend>web_video_server</depend>
|
||||
<depend>tf2_web_republisher</depend>
|
||||
<depend condition="$ROS_PYTHON_VERSION == 2">python-lxml</depend>
|
||||
<depend condition="$ROS_PYTHON_VERSION == 3">python3-lxml</depend>
|
||||
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-pymavlink</exec_depend>
|
||||
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python-pymavlink</exec_depend>
|
||||
<depend>python-lxml</depend>
|
||||
<exec_depend>python-pymavlink</exec_depend>
|
||||
<!-- Use test_depend for packages you need only for testing: -->
|
||||
<!-- <test_depend>gtest</test_depend> -->
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
flask==1.1.1
|
||||
docopt==0.6.2
|
||||
geopy==1.20.0
|
||||
smbus2==0.3.0
|
||||
VL53L1X==0.0.4
|
||||
geopy==1.11.0
|
||||
smbus2==0.2.1
|
||||
VL53L1X==0.0.2
|
||||
|
||||
@@ -34,9 +34,7 @@ class OpticalFlow : public nodelet::Nodelet
|
||||
{
|
||||
public:
|
||||
OpticalFlow():
|
||||
camera_matrix_(3, 3, CV_64F),
|
||||
dist_coeffs_(8, 1, CV_64F),
|
||||
tf_listener_(tf_buffer_)
|
||||
camera_matrix_(3, 3, CV_64F)
|
||||
{}
|
||||
|
||||
private:
|
||||
@@ -52,8 +50,8 @@ private:
|
||||
Mat hann_;
|
||||
Mat prev_, curr_;
|
||||
Mat camera_matrix_, dist_coeffs_;
|
||||
tf2_ros::Buffer tf_buffer_;
|
||||
tf2_ros::TransformListener tf_listener_;
|
||||
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
bool calc_flow_gyro_;
|
||||
|
||||
void onInit()
|
||||
@@ -63,11 +61,14 @@ private:
|
||||
image_transport::ImageTransport it(nh);
|
||||
image_transport::ImageTransport it_priv(nh_priv);
|
||||
|
||||
nh.param<std::string>("mavros/local_position/tf/frame_id", local_frame_id_, "map");
|
||||
nh.param<std::string>("mavros/local_position/tf/child_frame_id", fcu_frame_id_, "base_link");
|
||||
nh_priv.param("roi", roi_px_, 128);
|
||||
nh_priv.param("roi_rad", roi_rad_, 0.0);
|
||||
nh_priv.param("calc_flow_gyro", calc_flow_gyro_, false);
|
||||
tf_buffer_.reset(new tf2_ros::Buffer());
|
||||
tf_listener_.reset(new tf2_ros::TransformListener(*tf_buffer_, nh));
|
||||
|
||||
local_frame_id_ = nh.param<std::string>("mavros/local_position/tf/frame_id", "map");
|
||||
fcu_frame_id_ = nh.param<std::string>("mavros/local_position/tf/child_frame_id", "base_link");
|
||||
roi_px_ = nh_priv.param("roi", 128);
|
||||
roi_rad_ = nh_priv.param("roi_rad", 0.0);
|
||||
calc_flow_gyro_ = nh_priv.param("calc_flow_gyro", false);
|
||||
|
||||
img_sub_ = it.subscribeCamera("image_raw", 1, &OpticalFlow::flow, this);
|
||||
img_pub_ = it_priv.advertise("debug", 1);
|
||||
@@ -91,9 +92,7 @@ private:
|
||||
camera_matrix_.at<double>(i, j) = cinfo->K[3 * i + j];
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < cinfo->D.size(); k++) {
|
||||
dist_coeffs_.at<double>(k) = cinfo->D[k];
|
||||
}
|
||||
dist_coeffs_ = cv::Mat(cinfo->D, true);
|
||||
}
|
||||
|
||||
void drawFlow(Mat& frame, double x, double y, double quality) const
|
||||
@@ -186,7 +185,7 @@ private:
|
||||
flow_camera.vector.x = flow_y; // +y means counter-clockwise rotation around Y axis
|
||||
flow_camera.vector.y = -flow_x; // +x means clockwise rotation around X axis
|
||||
try {
|
||||
tf_buffer_.transform(flow_camera, flow_fcu, fcu_frame_id_);
|
||||
tf_buffer_->transform(flow_camera, flow_fcu, fcu_frame_id_);
|
||||
} catch (const tf2::TransformException& e) {
|
||||
// transform is not available yet
|
||||
return;
|
||||
@@ -200,7 +199,7 @@ private:
|
||||
try {
|
||||
auto flow_gyro_camera = calcFlowGyro(msg->header.frame_id, prev_stamp_, msg->header.stamp);
|
||||
static geometry_msgs::Vector3Stamped flow_gyro_fcu;
|
||||
tf_buffer_.transform(flow_gyro_camera, flow_gyro_fcu, fcu_frame_id_);
|
||||
tf_buffer_->transform(flow_gyro_camera, flow_gyro_fcu, fcu_frame_id_);
|
||||
flow_.integrated_xgyro = flow_gyro_fcu.vector.x;
|
||||
flow_.integrated_ygyro = flow_gyro_fcu.vector.y;
|
||||
flow_.integrated_zgyro = flow_gyro_fcu.vector.z;
|
||||
@@ -247,8 +246,8 @@ private:
|
||||
geometry_msgs::Vector3Stamped calcFlowGyro(const std::string& frame_id, const ros::Time& prev, const ros::Time& curr)
|
||||
{
|
||||
tf2::Quaternion prev_rot, curr_rot;
|
||||
tf2::fromMsg(tf_buffer_.lookupTransform(frame_id, local_frame_id_, prev).transform.rotation, prev_rot);
|
||||
tf2::fromMsg(tf_buffer_.lookupTransform(frame_id, local_frame_id_, curr, ros::Duration(0.1)).transform.rotation, curr_rot);
|
||||
tf2::fromMsg(tf_buffer_->lookupTransform(frame_id, local_frame_id_, prev).transform.rotation, prev_rot);
|
||||
tf2::fromMsg(tf_buffer_->lookupTransform(frame_id, local_frame_id_, curr, ros::Duration(0.1)).transform.rotation, curr_rot);
|
||||
|
||||
geometry_msgs::Vector3Stamped flow;
|
||||
flow.header.frame_id = frame_id;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
# Copyright (C) 2018 Copter Express Technologies
|
||||
@@ -138,7 +138,7 @@ def mavlink_exec(cmd, timeout=3.0):
|
||||
timeout=3,
|
||||
baudrate=0,
|
||||
count=len(cmd),
|
||||
data=[ord(c) for c in cmd.ljust(70, '\0')])
|
||||
data=map(ord, cmd.ljust(70, '\0')))
|
||||
msg.pack(link)
|
||||
ros_msg = mavlink.convert_to_rosmsg(msg)
|
||||
mavlink_pub.publish(ros_msg)
|
||||
@@ -210,7 +210,7 @@ def check_fcu():
|
||||
is_clover_firmware = True
|
||||
|
||||
if not is_clover_firmware:
|
||||
failure('not running Clover PX4 firmware, https://clever.coex.tech/firmware')
|
||||
failure('not running Clover PX4 firmware, https://clover.coex.tech/firmware')
|
||||
|
||||
est = get_param('SYS_MC_EST_GROUP')
|
||||
if est == 1:
|
||||
@@ -250,11 +250,11 @@ def check_fcu():
|
||||
try:
|
||||
battery = rospy.wait_for_message('mavros/battery', BatteryState, timeout=3)
|
||||
if not battery.cell_voltage:
|
||||
failure('cell voltage is not available, https://clever.coex.tech/power')
|
||||
failure('cell voltage is not available, https://clover.coex.tech/power')
|
||||
else:
|
||||
cell = battery.cell_voltage[0]
|
||||
if cell > 4.3 or cell < 3.0:
|
||||
failure('incorrect cell voltage: %.2f V, https://clever.coex.tech/power', cell)
|
||||
failure('incorrect cell voltage: %.2f V, https://clover.coex.tech/power', cell)
|
||||
elif cell < 3.7:
|
||||
failure('critically low cell voltage: %.2f V, recharge battery', cell)
|
||||
except rospy.ROSException:
|
||||
@@ -609,7 +609,7 @@ def check_rangefinder():
|
||||
|
||||
@check('Boot duration')
|
||||
def check_boot_duration():
|
||||
output = subprocess.check_output('systemd-analyze').decode()
|
||||
output = subprocess.check_output('systemd-analyze')
|
||||
r = re.compile(r'([\d\.]+)s\s*$', flags=re.MULTILINE)
|
||||
duration = float(r.search(output).groups()[0])
|
||||
if duration > 15:
|
||||
@@ -620,7 +620,7 @@ def check_boot_duration():
|
||||
def check_cpu_usage():
|
||||
WHITELIST = 'nodelet',
|
||||
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).decode()
|
||||
output = subprocess.check_output(CMD, shell=True)
|
||||
processes = output.split('\n')
|
||||
for process in processes:
|
||||
if not process:
|
||||
@@ -636,7 +636,7 @@ def check_cpu_usage():
|
||||
def check_clover_service():
|
||||
try:
|
||||
output = subprocess.check_output('systemctl show -p ActiveState --value clover.service'.split(),
|
||||
stderr=subprocess.STDOUT).decode()
|
||||
stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
failure('systemctl returned %s: %s', e.returncode, e.output)
|
||||
return
|
||||
@@ -701,7 +701,7 @@ def check_preflight_status():
|
||||
|
||||
@check('Network')
|
||||
def check_network():
|
||||
ros_hostname = os.environ.get('ROS_HOSTNAME').strip()
|
||||
ros_hostname = os.environ.get('ROS_HOSTNAME', '').strip()
|
||||
|
||||
if not ros_hostname:
|
||||
failure('no ROS_HOSTNAME is set')
|
||||
@@ -718,7 +718,7 @@ def check_network():
|
||||
if ros_hostname in parts:
|
||||
break
|
||||
else:
|
||||
failure('not found %s in /etc/hosts, ROS will malfunction if network interfaces are down, https://clever.coex.tech/hostname', ros_hostname)
|
||||
failure('not found %s in /etc/hosts, ROS will malfunction if network interfaces are down, https://clover.coex.tech/hostname', ros_hostname)
|
||||
|
||||
|
||||
@check('RPi health')
|
||||
@@ -751,7 +751,7 @@ def check_rpi_health():
|
||||
# <parameter>=<value>
|
||||
# In case of `get_throttled`, <value> is a hexadecimal number
|
||||
# with some of the FLAGs OR'ed together
|
||||
output = subprocess.check_output(['vcgencmd', 'get_throttled']).decode()
|
||||
output = subprocess.check_output(['vcgencmd', 'get_throttled'])
|
||||
except OSError:
|
||||
failure('could not call vcgencmd binary; not a Raspberry Pi?')
|
||||
return
|
||||
|
||||
@@ -490,7 +490,7 @@ inline void checkState()
|
||||
throw std::runtime_error("State timeout, check mavros settings");
|
||||
|
||||
if (!state.connected)
|
||||
throw std::runtime_error("No connection to FCU, https://clever.coex.tech/connection");
|
||||
throw std::runtime_error("No connection to FCU, https://clover.coex.tech/connection");
|
||||
}
|
||||
|
||||
#define ENSURE_FINITE(var) { if (!std::isfinite(var)) throw std::runtime_error(#var " argument cannot be NaN or Inf"); }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
import rospy
|
||||
import pytest
|
||||
from mavros_msgs.msg import State
|
||||
|
||||
0
clover/www/CATKIN_IGNORE
Normal file
@@ -1,7 +1,7 @@
|
||||
<h1>Clover Drone Kit Tools</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="docs">View documentation</a> (snapshot of <a href="https://clever.coex.tech">clever.coex.tech</a>)</li>
|
||||
<li><a href="docs">View documentation</a> (snapshot of <a href="https://clover.coex.tech">clover.coex.tech</a>)</li>
|
||||
<li><a href="" id="wvs">View image topics</a> (<code>web_video_server</code>)</li>
|
||||
<li><a href="" id="butterfly">Open web terminal</a> (<code>Butterfly</code>)</li>
|
||||
<li><a href="viz.html">View 3D visualization</a> (<code>ros3djs</code>)</li>
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
<script src="js/roslib.js"></script>
|
||||
<script type="text/javascript">
|
||||
document.querySelector("#wvs").href = location.origin + ':8080';
|
||||
document.querySelector("#butterfly").href = location.origin + ':57575';
|
||||
document.querySelector("#wvs").href = location.protocol + '//' + location.hostname + ':8080';
|
||||
document.querySelector("#butterfly").href = location.protocol + '//' + location.hostname + ':57575';
|
||||
|
||||
// Determine image version
|
||||
var ros = new ROSLIB.Ros({ url: 'ws://' + location.hostname + ':9090' });
|
||||
|
||||
0
docs/CATKIN_IGNORE
Normal file
BIN
docs/assets/aruco.gif
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
docs/assets/clover.png
Normal file
|
After Width: | Height: | Size: 614 KiB |
BIN
docs/assets/clover42.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
docs/assets/community/collage.jpg
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
18312
docs/assets/dxf/mounting_deck_small.dxf
Normal file
BIN
docs/assets/flysky_a8s/01_remove_cable_fs.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
docs/assets/flysky_a8s/02_remove_cable_fs.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
docs/assets/flysky_a8s/03_remove_cable_pixracer.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/assets/flysky_a8s/04_remove_cable_pixracer.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
docs/assets/flysky_a8s/05_remove_cable_coexpix.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
docs/assets/flysky_a8s/06_remove_cable_coexpix.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
docs/assets/flysky_a8s/07_wirecuts_1.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
docs/assets/flysky_a8s/08_wirecuts_2.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
docs/assets/flysky_a8s/09_wirecuts_stripped.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
docs/assets/flysky_a8s/10_heatshrink.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/assets/flysky_a8s/11_solder_scheme.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
docs/assets/flysky_a8s/12_heatshrink_heat.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/assets/flysky_a8s/13_cable_twist.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
docs/assets/flysky_a8s/14_coexpix_rcin.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
docs/assets/flysky_a8s/14_pixracer_rcin.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
docs/assets/flysky_a8s/15_bind_key.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
docs/assets/flysky_a8s/16_bind_indicator.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
docs/assets/flysky_a8s/16_blink_fast.gif
Normal file
|
After Width: | Height: | Size: 266 KiB |
BIN
docs/assets/flysky_a8s/16_blink_slow.gif
Normal file
|
After Width: | Height: | Size: 266 KiB |
BIN
docs/assets/flysky_a8s/17_controller_rxbind.png
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
docs/assets/flysky_a8s/18_qgc_radio.png
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
docs/assets/flysky_a8s/19_qgc_channels.png
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
docs/assets/js-ros.png
Normal file
|
After Width: | Height: | Size: 251 KiB |
BIN
docs/assets/optical-flow.gif
Normal file
|
After Width: | Height: | Size: 3.5 MiB |
BIN
docs/assets/p4df2_1.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
docs/assets/p4df2_2.jpg
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
docs/assets/p4df2_3.jpg
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
docs/assets/p4df2_4.jpg
Normal file
|
After Width: | Height: | Size: 98 KiB |
1
docs/assets/px4.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
134
docs/assets/ros.svg
Normal file
@@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
viewBox="0 0 387 103"
|
||||
height="103pt"
|
||||
width="387pt">
|
||||
<metadata
|
||||
id="metadata58">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs4">
|
||||
<clipPath
|
||||
id="clip1">
|
||||
<path
|
||||
id="path7"
|
||||
d="M 0.0585938 2 L 22 2 L 22 25 L 0.0585938 25 Z M 0.0585938 2 " />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clip2">
|
||||
<path
|
||||
id="path10"
|
||||
d="M 0.0585938 40 L 22 40 L 22 64 L 0.0585938 64 Z M 0.0585938 40 " />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clip3">
|
||||
<path
|
||||
id="path13"
|
||||
d="M 0.0585938 79 L 22 79 L 22 102 L 0.0585938 102 Z M 0.0585938 79 " />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clip4">
|
||||
<path
|
||||
id="path16"
|
||||
d="M 220 0.894531 L 302 0.894531 L 302 102.941406 L 220 102.941406 Z M 220 0.894531 " />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clip5">
|
||||
<path
|
||||
id="path19"
|
||||
d="M 316 0.894531 L 386.050781 0.894531 L 386.050781 102.941406 L 316 102.941406 Z M 316 0.894531 " />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
id="surface839">
|
||||
<g
|
||||
id="g22"
|
||||
clip-rule="nonzero"
|
||||
clip-path="url(#clip1)">
|
||||
<path
|
||||
id="path24"
|
||||
d="M 21.839844 13.492188 C 21.839844 19.722656 16.949219 24.777344 10.921875 24.777344 C 4.890625 24.777344 0 19.722656 0 13.492188 C 0 7.257812 4.890625 2.207031 10.921875 2.207031 C 16.949219 2.207031 21.839844 7.257812 21.839844 13.492188 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
</g>
|
||||
<g
|
||||
id="g26"
|
||||
clip-rule="nonzero"
|
||||
clip-path="url(#clip2)">
|
||||
<path
|
||||
id="path28"
|
||||
d="M 21.839844 51.949219 C 21.839844 58.179688 16.949219 63.234375 10.921875 63.234375 C 4.890625 63.234375 0 58.179688 0 51.949219 C 0 45.714844 4.890625 40.664062 10.921875 40.664062 C 16.949219 40.664062 21.839844 45.714844 21.839844 51.949219 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
</g>
|
||||
<g
|
||||
id="g30"
|
||||
clip-rule="nonzero"
|
||||
clip-path="url(#clip3)">
|
||||
<path
|
||||
id="path32"
|
||||
d="M 21.839844 90.40625 C 21.839844 96.636719 16.949219 101.691406 10.921875 101.691406 C 4.890625 101.691406 0 96.636719 0 90.40625 C 0 84.175781 4.890625 79.121094 10.921875 79.121094 C 16.949219 79.121094 21.839844 84.175781 21.839844 90.40625 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
</g>
|
||||
<path
|
||||
id="path34"
|
||||
d="M 59.945312 51.949219 C 59.945312 58.179688 55.058594 63.234375 49.027344 63.234375 C 42.996094 63.234375 38.105469 58.179688 38.105469 51.949219 C 38.105469 45.714844 42.996094 40.664062 49.027344 40.664062 C 55.058594 40.664062 59.945312 45.714844 59.945312 51.949219 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
<path
|
||||
id="path36"
|
||||
d="M 59.945312 13.492188 C 59.945312 19.722656 55.058594 24.777344 49.027344 24.777344 C 42.996094 24.777344 38.105469 19.722656 38.105469 13.492188 C 38.105469 7.257812 42.996094 2.207031 49.027344 2.207031 C 55.058594 2.207031 59.945312 7.257812 59.945312 13.492188 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
<path
|
||||
id="path38"
|
||||
d="M 98.054688 51.949219 C 98.054688 58.179688 93.164062 63.234375 87.132812 63.234375 C 81.101562 63.234375 76.214844 58.179688 76.214844 51.949219 C 76.214844 45.714844 81.101562 40.664062 87.132812 40.664062 C 93.164062 40.664062 98.054688 45.714844 98.054688 51.949219 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
<path
|
||||
id="path40"
|
||||
d="M 98.054688 13.492188 C 98.054688 19.722656 93.164062 24.777344 87.132812 24.777344 C 81.101562 24.777344 76.214844 19.722656 76.214844 13.492188 C 76.214844 7.257812 81.101562 2.207031 87.132812 2.207031 C 93.164062 2.207031 98.054688 7.257812 98.054688 13.492188 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
<path
|
||||
id="path42"
|
||||
d="M 98.054688 90.40625 C 98.054688 96.636719 93.164062 101.691406 87.132812 101.691406 C 81.101562 101.691406 76.214844 96.636719 76.214844 90.40625 C 76.214844 84.175781 81.101562 79.121094 87.132812 79.121094 C 93.164062 79.121094 98.054688 84.175781 98.054688 90.40625 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
<path
|
||||
id="path44"
|
||||
d="M 59.945312 90.40625 C 59.945312 96.636719 55.058594 101.691406 49.027344 101.691406 C 42.996094 101.691406 38.105469 96.636719 38.105469 90.40625 C 38.105469 84.175781 42.996094 79.121094 49.027344 79.121094 C 55.058594 79.121094 59.945312 84.175781 59.945312 90.40625 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
<path
|
||||
id="path46"
|
||||
d="M 171.613281 16.453125 L 143.695312 16.453125 L 143.695312 48.269531 L 171.613281 48.269531 C 181.191406 48.269531 187.894531 43.179688 187.894531 32.433594 C 187.894531 22.109375 181.328125 16.453125 171.613281 16.453125 Z M 181.328125 61 L 200.894531 101.445312 L 184.339844 101.445312 L 165.316406 62.273438 L 143.695312 62.273438 L 143.695312 101.445312 L 129.601562 101.445312 L 129.601562 2.449219 L 171.613281 2.449219 C 188.308594 2.449219 202.402344 11.644531 202.402344 32.007812 C 202.402344 47.847656 194.328125 57.605469 181.328125 61 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
<g
|
||||
id="g48"
|
||||
clip-rule="nonzero"
|
||||
clip-path="url(#clip4)">
|
||||
<path
|
||||
id="path50"
|
||||
d="M 260.5625 15.746094 C 243.867188 15.746094 234.699219 29.746094 234.699219 51.949219 C 234.699219 74.152344 243.867188 88.152344 260.5625 88.152344 C 277.394531 88.152344 286.5625 74.152344 286.5625 51.949219 C 286.5625 29.746094 277.394531 15.746094 260.5625 15.746094 Z M 260.5625 103 C 235.796875 103 220.058594 81.929688 220.058594 51.949219 C 220.058594 21.96875 235.796875 0.894531 260.5625 0.894531 C 285.46875 0.894531 301.203125 21.96875 301.203125 51.949219 C 301.203125 81.929688 285.46875 103 260.5625 103 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
</g>
|
||||
<g
|
||||
id="g52"
|
||||
clip-rule="nonzero"
|
||||
clip-path="url(#clip5)">
|
||||
<path
|
||||
id="path54"
|
||||
d="M 350.609375 103 C 336.648438 103 324.609375 96.777344 316.535156 87.019531 L 326.796875 76.695312 C 333.230469 83.910156 342.671875 88.433594 351.703125 88.433594 C 365.113281 88.433594 371.542969 83.625 371.542969 74.007812 C 371.542969 66.371094 365.933594 62.554688 349.921875 57.605469 C 329.671875 51.382812 319.957031 46.148438 319.957031 28.472656 C 319.957031 11.359375 333.914062 0.894531 351.566406 0.894531 C 364.566406 0.894531 374.417969 5.847656 382.902344 14.332031 L 372.777344 24.9375 C 366.753906 18.574219 359.914062 15.460938 350.472656 15.460938 C 339.25 15.460938 334.460938 21.117188 334.460938 27.765625 C 334.460938 34.695312 338.839844 38.089844 355.398438 43.179688 C 374.28125 49.121094 386.050781 55.34375 386.050781 73.019531 C 386.050781 90.839844 375.101562 103 350.609375 103 "
|
||||
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
69
docs/assets/rpi.svg
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 656.47998 825.76001"
|
||||
height="825.76001"
|
||||
width="656.47998"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6" /><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,825.76)"
|
||||
id="g10"><g
|
||||
transform="scale(0.1)"
|
||||
id="g12"><path
|
||||
id="path14"
|
||||
style="fill:#040606;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1332.8,6193.06 c -31.79,-0.96 -66.04,-12.52 -104.87,-42.73 -95.16,36.15 -187.4,48.71 -269.879,-24.86 -127.371,16.28 -168.774,-17.31 -200.141,-56.51 -27.953,0.57 -209.25,28.3 -292.375,-93.84 -208.914,24.34 -274.953,-121.05 -200.14,-256.61 -42.661,-65.07 -86.86,-129.35 12.902,-253.37 -35.285,-69.08 -13.41,-144.01 69.746,-234.72 -21.949,-97.11 21.199,-165.62 98.555,-219.02 -14.481,-132.88 123.715,-210.15 164.984,-237.69 15.836,-77.42 48.871,-150.5 206.723,-190.89 26.019,-115.41 120.89,-135.33 212.755,-159.55 C 727.426,4249.43 467.074,4020.7 468.832,3459.5 L 424.34,3381.35 C 76.2109,3172.81 -237.016,2502.55 252.781,1957.78 284.773,1787.23 338.43,1664.75 386.207,1529.2 457.668,982.91 924.004,727.121 1047.01,696.859 1227.25,561.641 1419.2,433.332 1678.97,343.441 1923.85,94.6914 2189.13,-0.121094 2455.89,0.03125 c 3.91,0 7.89,-0.0507813 11.8,0 266.75,-0.160156 532.05,94.64065 776.91,343.40975 259.78,89.891 451.74,218.2 631.98,353.418 123,30.262 589.33,286.051 660.79,832.341 47.77,135.55 101.44,258.03 133.42,428.58 489.81,544.82 176.59,1215.13 -171.57,1423.67 l -44.53,78.13 c 1.76,561.15 -258.63,789.88 -562.24,963.77 91.87,24.21 186.73,44.14 212.76,159.53 157.86,40.42 190.88,113.49 206.71,190.91 41.28,27.52 179.47,104.8 164.99,237.7 77.36,53.39 120.5,121.91 98.57,219.01 83.14,90.7 105.03,165.63 69.73,234.71 99.8,123.99 55.51,188.26 12.91,253.33 74.75,135.56 8.79,280.94 -200.21,256.59 -83.11,122.15 -264.34,94.41 -292.36,93.85 -31.37,39.2 -72.74,72.79 -200.12,56.51 -82.48,73.57 -174.73,61.01 -269.87,24.87 -112.99,87.81 -187.74,17.43 -273.13,-9.18 -136.77,44.02 -168.05,-16.29 -235.24,-40.84 -149.18,31.05 -194.51,-36.54 -266.03,-107.9 l -83.19,1.62 c -224.98,-130.58 -336.74,-396.52 -376.36,-533.23 -39.64,136.74 -151.17,402.67 -376.1,533.23 l -83.18,-1.62 c -71.6,71.36 -116.94,138.95 -266.1,107.9 -67.2,24.55 -98.38,84.86 -235.25,40.84 -56.05,17.46 -107.61,53.77 -168.29,51.92 l 0.11,-0.04" /><path
|
||||
id="path16"
|
||||
style="fill:#63c54d;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 889.32,5618.51 c 596.92,-303.11 943.94,-548.33 1134.04,-757.16 -97.35,-384.36 -605.24,-401.9 -790.94,-391.11 38.01,17.43 69.74,38.32 80.99,70.4 -46.59,32.6 -211.83,3.44 -327.176,67.27 44.296,9.05 65.036,17.84 85.746,50.06 -108.968,34.23 -226.367,63.74 -295.402,120.46 37.266,-0.47 72.035,-8.21 120.707,25.03 -97.629,51.82 -201.781,92.87 -282.707,172.08 50.457,1.2 104.875,0.5 120.695,18.77 -89.335,54.51 -164.726,115.15 -227.128,181.47 70.644,-8.4 100.464,-1.17 117.546,10.95 -67.539,68.12 -153.023,125.66 -193.773,209.63 52.445,-17.81 100.422,-24.63 135.016,1.56 -22.957,51.01 -121.286,81.08 -177.903,200.24 55.223,-5.26 113.774,-11.85 125.489,0 -25.637,102.83 -69.598,160.66 -112.727,220.55 118.152,1.72 297.172,-0.46 289.066,9.39 l -73.05,73.53 c 115.406,30.6 233.496,-4.92 319.238,-31.3 38.488,29.92 -0.684,67.76 -47.652,106.4 98.089,-12.92 186.715,-35.13 266.815,-65.73 42.82,38.08 -27.77,76.15 -61.94,114.21 151.54,-28.32 215.75,-68.1 279.54,-107.95 46.3,43.71 2.65,80.85 -28.59,118.89 114.26,-41.68 173.12,-95.49 235.07,-148.61 21.01,27.92 53.37,48.39 14.3,115.77 81.11,-46.06 142.2,-100.33 187.42,-161.13 50.19,31.47 29.9,74.53 30.17,114.2 84.3,-67.56 137.81,-139.44 203.31,-209.63 13.18,9.45 24.74,41.55 34.93,92.3 201.12,-192.2 485.32,-676.3 73.06,-868.24 -350.87,285.03 -769.91,492.21 -1234.281,647.62 l 0.121,0.08" /><path
|
||||
id="path18"
|
||||
style="fill:#63c54d;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 4050.89,5618.51 c -596.87,-303.16 -943.87,-548.29 -1133.98,-757.16 97.36,-384.36 605.26,-401.9 790.96,-391.11 -38.03,17.43 -69.74,38.32 -80.99,70.4 46.6,32.6 211.83,3.44 327.18,67.27 -44.3,9.05 -65.04,17.84 -85.76,50.06 108.99,34.23 226.38,63.74 295.42,120.46 -37.26,-0.47 -72.06,-8.21 -120.71,25.03 97.61,51.82 201.78,92.87 282.7,172.08 -50.47,1.2 -104.87,0.5 -120.71,18.77 89.37,54.51 164.75,115.15 227.14,181.47 -70.63,-8.4 -100.45,-1.17 -117.54,10.95 67.55,68.12 153.02,125.66 193.78,209.63 -52.44,-17.81 -100.42,-24.63 -135.01,1.56 22.95,51.01 121.27,81.08 177.88,200.24 -55.21,-5.26 -113.75,-11.85 -125.47,0 25.67,102.88 69.65,160.7 112.76,220.6 -118.16,1.72 -297.16,-0.46 -289.08,9.38 l 73.09,73.52 c -115.43,30.61 -233.52,-4.9 -319.26,-31.28 -38.48,29.92 0.68,67.76 47.64,106.37 -98.08,-12.89 -186.71,-35.1 -266.82,-65.7 -42.8,38.06 27.79,76.13 61.94,114.2 -151.53,-28.32 -215.73,-68.11 -279.54,-107.94 -46.29,43.7 -2.63,80.85 28.6,118.88 -114.26,-41.67 -173.12,-95.48 -235.06,-148.6 -21.01,27.92 -53.36,48.38 -14.3,115.77 -81.13,-46.07 -142.21,-100.34 -187.41,-161.14 -50.2,31.48 -29.91,74.53 -30.19,114.19 -84.3,-67.54 -137.82,-139.43 -203.29,-209.62 -13.19,9.46 -24.74,41.56 -34.95,92.3 -201.13,-192.2 -485.34,-676.3 -73.05,-868.24 350.68,285.09 769.69,492.26 1234.1,647.66 h -0.07" /><path
|
||||
id="path20"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3192,1704.72 c 2.08,-358.64 -316.36,-650.93 -711.23,-652.82 -394.87,-1.89 -716.68,287.32 -718.76,645.98 0,2.28 0,4.56 0,6.84 -2.07,358.66 316.35,650.95 711.24,652.83 394.87,1.89 716.68,-287.31 718.75,-645.98 0.01,-2.29 0.01,-4.56 0,-6.85" /><path
|
||||
id="path22"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 2077.17,3559.87 c 296.27,-191.17 349.68,-624.54 119.3,-967.92 -230.38,-343.39 -657.31,-466.8 -953.56,-275.62 v 0 c -296.265,191.19 -349.68,624.56 -119.29,967.96 230.38,343.38 657.3,466.78 953.55,275.58 v 0" /><path
|
||||
id="path24"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 2876.82,3594.49 c -296.27,-191.18 -349.67,-624.56 -119.29,-967.93 230.39,-343.39 657.3,-466.8 953.56,-275.61 v 0 c 296.27,191.18 349.68,624.55 119.3,967.95 -230.38,343.39 -657.3,466.78 -953.57,275.59 v 0" /><path
|
||||
id="path26"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="M 614.797,3245.31 C 934.641,3329.76 722.777,1941.9 462.535,2055.77 176.246,2282.58 84.0352,2946.78 614.797,3245.31" /><path
|
||||
id="path28"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 4311.21,3262.62 c -319.88,84.42 -107.98,-1303.48 152.29,-1189.61 286.27,226.82 378.47,891.08 -152.29,1189.61 v 0" /><path
|
||||
id="path30"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3238.44,4298.12 c 551.99,91.81 1011.31,-231.21 992.77,-820.8 -18.15,-226.03 -1196.15,787.15 -992.77,820.8" /><path
|
||||
id="path32"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1713.29,4315.43 c -552.04,91.81 -1011.313,-231.29 -992.77,-820.82 18.136,-226.02 1196.14,787.16 992.77,820.82" /><path
|
||||
id="path34"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 2473.78,4452.92 c -329.46,8.44 -645.64,-240.85 -646.41,-385.43 -0.92,-175.69 260.48,-355.58 648.65,-360.15 396.41,-2.79 649.34,143.99 650.62,325.31 1.46,205.43 -360.52,423.45 -652.86,420.29 v -0.02" /><path
|
||||
id="path36"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 2499.23,850.172 c 287.23,12.359 672.67,-91.121 673.43,-228.391 4.77,-133.301 -349.56,-434.48 -692.48,-428.672 -355.16,-15.078 -703.39,286.551 -698.83,391.11 -5.32,153.301 432.44,272.98 717.88,265.953 v 0" /><path
|
||||
id="path38"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 1436.19,1663.74 c 204.49,-242.69 297.72,-669.049 127.07,-794.72 -161.47,-95.961 -553.57,-56.45 -832.276,337.92 -187.925,330.88 -163.722,667.63 -31.746,766.53 197.344,118.42 502.252,-41.52 736.952,-309.73 v 0" /><path
|
||||
id="path40"
|
||||
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 3495.16,1740.65 c -221.27,-255.27 -344.49,-720.88 -183.07,-870.83 154.33,-116.488 568.64,-100.199 874.69,318.05 222.21,280.91 147.75,750.07 20.83,874.64 -188.58,143.66 -459.26,-40.19 -712.45,-321.78 v -0.08" /><path
|
||||
id="path42"
|
||||
style="fill:#171818;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 4594.78,4119.88 c -150.79,0 -273.01,122.19 -273.01,273.02 0,150.91 122.22,273.01 273.01,273.01 150.78,0 273.01,-122.1 273.01,-273.01 0,-150.83 -122.23,-273.02 -273.01,-273.02 z m 0,600.67 c -180.97,0 -327.6,-146.68 -327.6,-327.65 0,-180.88 146.63,-327.56 327.6,-327.56 180.96,0 327.6,146.68 327.6,327.56 0,180.97 -146.64,327.65 -327.6,327.65" /><path
|
||||
id="path44"
|
||||
style="fill:#171818;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 4533.92,4413.81 h 84.36 c 34.39,0 52.99,14.79 52.99,50.12 0,33.72 -18.6,48.51 -52.99,48.51 h -84.36 z m -77.02,158.46 h 188.88 c 62.84,0 102.55,-43.62 102.55,-96.47 0,-41.36 -16.67,-72.25 -55.44,-87.99 v -0.94 c 37.78,-9.8 48.52,-46.54 51.02,-81.96 1.46,-22.05 0.98,-63.21 14.74,-82.91 h -77.01 c -9.37,22.15 -8.39,55.87 -12.3,83.94 -5.37,36.83 -19.59,52.95 -58.36,52.95 h -77.06 V 4222 h -77.02 v 350.27" /></g></g></svg>
|
||||
|
After Width: | Height: | Size: 9.7 KiB |
BIN
docs/assets/simulator.jpg
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
docs/assets/stl/mounting_deck_small.stl
Normal file
BIN
docs/assets/web-gcs.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
@@ -40,7 +40,7 @@ section ul li:before {
|
||||
margin-bottom: 0.85em;
|
||||
}
|
||||
|
||||
/* Main Clever image */
|
||||
/* Main Clover image */
|
||||
.book img.bigclever {
|
||||
margin-bottom: -12%;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ The project was created in collaboration with Texel inc. that develops 3D-scanne
|
||||
|
||||
Our fellows from Texel provided a module consisting of a Raspberry Pi and a PrimeSense 3D-sensor.
|
||||
|
||||
We provided a Clever 3 drone that's capable of autonomous flight and wrote a flight program.
|
||||
We provided a Clover 3 drone that's capable of autonomous flight and wrote a flight program.
|
||||
|
||||
To make it all work we conducted many tests, made changes in the drone's design and tuned the drone properly.
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# COEX Clever
|
||||
# COEX Clover
|
||||
|
||||
<img class="center bigclever zoom" src="../assets/clever4-front-white-large.png" width="80%" alt="COEX Clever 4">
|
||||
<img class="center bigclever zoom" src="../assets/clever4-front-white-large.png" width="80%" alt="COEX Clover 4">
|
||||
|
||||
CLEVER (Russian: *"Клевер"*, meaning *"Clover"*) is an educational kit of a programmable quadcopter that consists of popular open source components, and a set of necessary documentation and libraries for working with it.
|
||||
**Clover** is an educational kit of a programmable quadcopter that consists of popular open source components, and a set of necessary documentation and libraries for working with it.
|
||||
|
||||
The kit includes a Pixhawk/Pixracer flight controller with the PX4 flight stack, a [Raspberry Pi 3](raspberry.md) as a controlling onboard computer, and a [camera module](camera.md) for performing flights with the use of computer vision, as well as a set of various sensors and other peripherals.
|
||||
The kit includes a Pixhawk/Pixracer flight controller with the PX4 flight stack, a [Raspberry Pi 4](raspberry.md) as a controlling onboard computer, and a [camera module](camera.md) for performing flights with the use of computer vision, as well as a set of various sensors and other peripherals.
|
||||
|
||||
The Clever platform contains a [pre-configured image for Raspberry Pi](image.md) with the full set of required software for working with peripheral devices and [programming autonomous flights](simple_offboard.md). The source code of the platform and of the documentation is open and [available on GitHub](https://github.com/CopterExpress/clever).
|
||||
The Clover platform contains a [pre-configured image for Raspberry Pi](image.md) with the full set of required software for working with peripheral devices and [programming autonomous flights](simple_offboard.md). The source code of the platform and of the documentation is open and [available on GitHub](https://github.com/CopterExpress/clover).
|
||||
|
||||
If you have studied the documentation but have not found an answer to your question, join our support chat and our specialists will be happy to answer you: [@COEXHelpdesk](tg://resolve?domain=COEXHelpdesk).
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
* [Glossary](gloss.md)
|
||||
* [Safety tips](safety.md)
|
||||
* Assembly
|
||||
* [Clever 4 assembly](assemble_4.md)
|
||||
* [Clever 3 assembly](assemble_3.md)
|
||||
* [Clever 2 assembly](assemble_2.md)
|
||||
* [Clover 4 assembly](assemble_4.md)
|
||||
* [Clover 3 assembly](assemble_3.md)
|
||||
* [Clover 2 assembly](assemble_2.md)
|
||||
* Configuration
|
||||
* [Initial setup](setup.md)
|
||||
* [Sensor calibration](calibration.md)
|
||||
* [RC setup](radio.md)
|
||||
* [Using FS-A8S](rc_flysky_a8s.md)
|
||||
* [Flight modes](modes.md)
|
||||
* [Power setup](power.md)
|
||||
* [Failsafe configuration](failsafe.md)
|
||||
@@ -41,7 +42,8 @@
|
||||
* [Interfacing with a sonar](sonar.md)
|
||||
* [Computer vision basics](camera.md)
|
||||
* [Using rviz and rqt](rviz.md)
|
||||
* [Software autorun](autolaunch.md)
|
||||
* [Software autorun](autolaunch.md)
|
||||
* [Using JavaScript](javascript.md)
|
||||
* [ROS](ros.md)
|
||||
* [MAVROS](mavros.md)
|
||||
* Supplementary materials
|
||||
@@ -52,8 +54,9 @@
|
||||
* [PID Setup](calibratePID.md)
|
||||
* [Model files for parts](models.md)
|
||||
* [ROS Melodic installation](ros-install.md)
|
||||
* [Camera calibration](camera_calibration.md)
|
||||
* [Quadcopter control with 4G communication](4g.md)
|
||||
* [Clever and Jetson Nano](jetson_nano.md)
|
||||
* [Clover and Jetson Nano](jetson_nano.md)
|
||||
* [Remote control app](rc.md)
|
||||
* [Wi-Fi Configuration](network.md)
|
||||
* [UART settings](uart.md)
|
||||
@@ -64,18 +67,20 @@
|
||||
* [Multimeter usage](test_connection.md)
|
||||
* [RC Troubleshooting](radioerrors.md)
|
||||
* [Flashing ESCs](esc_firmware.md)
|
||||
* [Camera calibration](camera_calibration.md)
|
||||
* [Interfacing with Arduino](arduino.md)
|
||||
* [Connecting GPS](gps.md)
|
||||
* [Working with IR sensors on Raspberry Pi 3](ir_sensors.md)
|
||||
* [FPV Setup](fpv.md)
|
||||
* [Trainer mode](trainer_mode.md)
|
||||
* [Tinning](tinning.md)
|
||||
* [Types of power connectors](connectortypes.md)
|
||||
* [Connecting 4 in 1 ESCs](4in1.md)
|
||||
* [Soldering safety](tb.md)
|
||||
* [LED strip (legacy)](leds_old.md)
|
||||
* [Contribution Guidelines](contributing.md)
|
||||
* Clever-based projects
|
||||
* [Migration to v0.20](migrate20.md)
|
||||
* Clover-based projects
|
||||
* [Drone show](clever-show.md)
|
||||
* [Copter spheric guard](shield.md)
|
||||
* [Face recognition system](face_recognition.md)
|
||||
* [Android RC app](android.md)
|
||||
@@ -84,3 +89,5 @@
|
||||
* [Copter Hack 2019](copterhack2019.md)
|
||||
* [Copter Hack 2018](copterhack2018.md)
|
||||
* [Copter Hack 2017](copterhack2017.md)
|
||||
* [Robocross-2019](robocross2019.md)
|
||||
* [Camera calibration (legacy)](camera_calib.md)
|
||||
|
||||
@@ -14,11 +14,11 @@ However, to make you fully understand the application, I will tell you about eac
|
||||
|
||||
## Wrapper
|
||||
|
||||
Let's start with the simplest thing — the appearance of our application. At [**GitHub**](https://github.com/CopterExpress/clever/tree/master/apps/android/app/src/main/assets), you can find *HTML*, *CSS* and *JavaScript* files, which make up the web page to be used for controlling the copter. To have this page displayed in our application, do the following:
|
||||
Let's start with the simplest thing — the appearance of our application. At [**GitHub**](https://github.com/CopterExpress/clover/tree/master/apps/android/app/src/main/assets), you can find *HTML*, *CSS* and *JavaScript* files, which make up the web page to be used for controlling the copter. To have this page displayed in our application, do the following:
|
||||
|
||||
1. Create folder **assets** in the main folder of the app named **app**
|
||||
|
||||
2. Add to it all files from [here](https://github.com/CopterExpress/clever/tree/master/apps/android/app/src/main/assets)
|
||||
2. Add to it all files from [here](https://github.com/CopterExpress/clover/tree/master/apps/android/app/src/main/assets)
|
||||
|
||||
If you reached this stage, you already have the web page you want, congratulations! Now we have to display it somehow in the app. To do this, in class *activity* in method **onCreate**, write the following code:
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ For interaction with ROS topics and services on a Raspberry Pi, you can use the
|
||||
|
||||
The main tutorial for rosserial: http://wiki.ros.org/rosserial_arduino/Tutorials
|
||||
|
||||
Arudino is to be installed on Clever and connected via a USB port.
|
||||
Arudino is to be installed on Clover and connected via a USB port.
|
||||
|
||||
## Configuring Arduino IDE
|
||||
|
||||
@@ -21,19 +21,19 @@ The obtained folder `ros_lib` is to be copied to `<sketches folder>/libraries` o
|
||||
To run the program on Arduino once, you can use command:
|
||||
|
||||
```(bash)
|
||||
roslaunch clever arduino.launch
|
||||
roslaunch clover arduino.launch
|
||||
```
|
||||
|
||||
To start the link with Arduino at the startup automatically, set argument `arudino` in the Clever launch file (`~/catkin_ws/src/clever/clever/launch/clever.launch`):
|
||||
To start the link with Arduino at the startup automatically, set argument `arudino` in the Clover launch file (`~/catkin_ws/src/clover/clover/launch/clover.launch`):
|
||||
|
||||
```xml
|
||||
<arg name="arduino" default="true"/>
|
||||
```
|
||||
|
||||
After the launch file is edited, restart package `clever`:
|
||||
After the launch file is edited, restart the `clover` service:
|
||||
|
||||
```(bash)
|
||||
sudo systemctl restart clever
|
||||
sudo systemctl restart clover
|
||||
```
|
||||
|
||||
## Delays
|
||||
@@ -59,7 +59,7 @@ for(int i=0; i<8; i++) {
|
||||
}
|
||||
```
|
||||
|
||||
## Working with Clever
|
||||
## Working with Clover
|
||||
|
||||
The set of services and topics is similar to the regular set in [simple_offboard](simple_offboard.md) and [mavros](mavros.md).
|
||||
|
||||
@@ -69,11 +69,11 @@ An example of a program that controls the copter by position using the `navigate
|
||||
// Connecting libraries for working with rosseral
|
||||
#include <ros.h>
|
||||
|
||||
// Connecting Clever and MAVROS package message header files
|
||||
#include <clever/Navigate.h>
|
||||
// Connecting Clover and MAVROS package message header files
|
||||
#include <clover/Navigate.h>
|
||||
#include <mavros_msgs/SetMode.h>
|
||||
|
||||
using namespace clever;
|
||||
using namespace clover;
|
||||
using namespace mavros_msgs;
|
||||
|
||||
ros::NodeHandle nh;
|
||||
@@ -174,7 +174,7 @@ With Arduino, you can use the [`get_telemetry` service](simple_offboard.md). To
|
||||
|
||||
// ...
|
||||
|
||||
#include <clever/GetTelemetry.h>
|
||||
#include <clover/GetTelemetry.h>
|
||||
|
||||
// ...
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ArUco markers
|
||||
|
||||
> **Note** The following applies to [image versions](image.md) **0.16** and up. Older documentation is still available for [for version **0.15.1**](https://github.com/CopterExpress/clever/blob/v0.15.1/docs/ru/aruco.md).
|
||||
> **Note** The following applies to [image versions](image.md) **0.16** and up. Older documentation is still available for [for version **0.15.1**](https://github.com/CopterExpress/clover/blob/v0.15.1/docs/en/aruco.md).
|
||||
|
||||
[ArUco markers](https://docs.opencv.org/3.2.0/d5/dae/tutorial_aruco_detection.html) are commonly used for vision-based position estimation.
|
||||
|
||||
@@ -12,13 +12,13 @@ Examples of ArUco markers:
|
||||
|
||||
For rapid generation of markers for printing, you may use an online tool: http://chev.me/arucogen/.
|
||||
|
||||
[Clever Raspberry Pi image](image.md) contains a pre-installed `aruco_pose` ROS package, which can be used for marker detection.
|
||||
[Clover Raspberry Pi image](image.md) contains a pre-installed `aruco_pose` ROS package, which can be used for marker detection.
|
||||
|
||||
## Modes of operation
|
||||
|
||||
There are several preconfigured modes of operation for ArUco markers on the Clever drone:
|
||||
There are several preconfigured modes of operation for ArUco markers on the Clover drone:
|
||||
|
||||
* [single marker detection and navigation](aruco_marker.md);
|
||||
* [map-based navigation](aruco_map.md).
|
||||
|
||||
> **Info** Additional documentation for the `aruco_pose` ROS package is available [on GitHub](https://github.com/CopterExpress/clever/blob/master/aruco_pose/README.md).
|
||||
> **Info** Additional documentation for the `aruco_pose` ROS package is available [on GitHub](https://github.com/CopterExpress/clover/blob/master/aruco_pose/README.md).
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
|
||||
## Configuration
|
||||
|
||||
Set the `aruco` argument in `~/catkin_ws/src/clever/clever/launch/clever.launch` to `true`:
|
||||
Set the `aruco` argument in `~/catkin_ws/src/clover/clover/launch/clover.launch` to `true`:
|
||||
|
||||
```xml
|
||||
<arg name="aruco" default="true"/>
|
||||
```
|
||||
|
||||
In order to enable map detection set `aruco_map` and `aruco_detect` arguments to `true` in `~/catkin_ws/src/clever/clever/launch/aruco.launch`:
|
||||
In order to enable map detection set `aruco_map` and `aruco_detect` arguments to `true` in `~/catkin_ws/src/clover/clover/launch/aruco.launch`:
|
||||
|
||||
```xml
|
||||
<arg name="aruco_detect" default="true"/>
|
||||
@@ -45,12 +45,12 @@ Map path is defined in the `map` parameter:
|
||||
<param name="map" value="$(find aruco_pose)/map/map.txt"/>
|
||||
```
|
||||
|
||||
Some map examples are provided in [`~/catkin_ws/src/clever/aruco_pose/map`](https://github.com/CopterExpress/clever/tree/master/aruco_pose/map).
|
||||
Some map examples are provided in [`~/catkin_ws/src/clover/aruco_pose/map`](https://github.com/CopterExpress/clover/tree/master/aruco_pose/map).
|
||||
|
||||
Grid maps may be generated using the `genmap.py` script:
|
||||
|
||||
```bash
|
||||
rosrun aruco_pose genmap.py length x y dist_x dist_y first > ~/catkin_ws/src/clever/aruco_pose/map/test_map.txt
|
||||
rosrun aruco_pose genmap.py length x y dist_x dist_y first > ~/catkin_ws/src/clover/aruco_pose/map/test_map.txt
|
||||
```
|
||||
|
||||
`length` is the size of each marker, `x` is the marker count along the *x* axis, `y` is the marker count along the *y* axis, `dist_x` is the distance between the centers of adjacent markers along the *x* axis, `dist_y` is the distance between the centers of the *y* axis, `first` is the ID of the first marker (top left marker, unless `--bottom-left` is specified), `test_map.txt` is the name of the generated map file. The optional `--bottom-left` parameter changes the numbering of markers, making the bottom left marker the first one.
|
||||
@@ -58,7 +58,7 @@ rosrun aruco_pose genmap.py length x y dist_x dist_y first > ~/catkin_ws/src/cle
|
||||
Usage example:
|
||||
|
||||
```bash
|
||||
rosrun aruco_pose genmap.py 0.33 2 4 1 1 0 > ~/catkin_ws/src/clever/aruco_pose/map/test_map.txt
|
||||
rosrun aruco_pose genmap.py 0.33 2 4 1 1 0 > ~/catkin_ws/src/clover/aruco_pose/map/test_map.txt
|
||||
```
|
||||
|
||||
Additional information on the utility can be obtained using `-h` key: `rosrun aruco_pose genmap.py -h`.
|
||||
@@ -91,13 +91,6 @@ The marker map adheres to the [ROS coordinate system convention](http://www.ros.
|
||||
|
||||
In order to enable vision position estimation you should use the following [PX4 parameters](px4_parameters.md).
|
||||
|
||||
If you're using **EKF2** estimator (`SYS_MC_EST_GROUP` parameter is set to `ekf2`), make sure the following is set:
|
||||
|
||||
* `EKF2_AID_MASK` should have `vision position fusion` and `vision yaw fusion` flags set.
|
||||
* Vision angle observations noise: `EKF2_EVA_NOISE` = 0.1 rad.
|
||||
* Vision position observations noise: `EKF2_EVP_NOISE` = 0.1 m.
|
||||
* `EKF2_EV_DELAY` = 0.
|
||||
|
||||
If you're using **LPE** (`SYS_MC_EST_GROUP` parameter is set to `local_position_estimator,attitude_estimator_q`):
|
||||
|
||||
* `LPE_FUSION` should have `vision position` and `land detector` flags set. We suggest unsetting the `baro` flag for indoor flights.
|
||||
@@ -108,6 +101,13 @@ If you're using **LPE** (`SYS_MC_EST_GROUP` parameter is set to `local_position_
|
||||
|
||||
<!-- * Compass should not be fused: `ATT_W_MAG` = 0 -->
|
||||
|
||||
If you're using **EKF2** estimator (`SYS_MC_EST_GROUP` parameter is set to `ekf2`), make sure the following is set:
|
||||
|
||||
* `EKF2_AID_MASK` should have `vision position fusion` and `vision yaw fusion` flags set.
|
||||
* Vision angle observations noise: `EKF2_EVA_NOISE` = 0.1 rad.
|
||||
* Vision position observations noise: `EKF2_EVP_NOISE` = 0.1 m.
|
||||
* `EKF2_EV_DELAY` = 0.
|
||||
|
||||
> **Hint** We recommend using **LPE** for marker-based navigation.
|
||||
|
||||
You may use [the `selfcheck.py` utility](selfcheck.md) to check your settings.
|
||||
@@ -152,7 +152,7 @@ If the drone's altitude is not stable, try increasing the `MPC_Z_VEL_P` paramete
|
||||
|
||||
In order to navigate using markers on the ceiling, mount the onboard camera so that it points up and [adjust the camera frame accordingly](camera_setup.md).
|
||||
|
||||
You should also set the `known_tilt` parameter to `map_flipped` in both `aruco_detect` and `aruco_map` sections of `~/catkin_ws/src/clever/clever/launch/aruco.launch`:
|
||||
You should also set the `known_tilt` parameter to `map_flipped` in both `aruco_detect` and `aruco_map` sections of `~/catkin_ws/src/clover/clover/launch/aruco.launch`:
|
||||
|
||||
```xml
|
||||
<param name="known_tilt" value="map_flipped"/>
|
||||
|
||||