Compare commits

..

23 Commits

Author SHA1 Message Date
Alexey Rogachevskiy
cda7858fb9 clover: Update ros3djs, THREE.js 2020-03-19 21:44:16 +03:00
Alexey Rogachevskiy
a01d199890 selfcheck: Be more Python3-compatible 2020-03-19 21:21:21 +03:00
Alexey Rogachevskiy
63a792b29d aruco_pose: Use python2 shebang
This shebang will be ignored with newer dynamic_reconfigure packages, and its presence should allow builds to succeed when older dynamic_reconfigure is used.
2020-03-18 21:46:09 +03:00
Alexey Rogachevskiy
360eb02909 Revert "aruco_pose: Use bash trampoline for dynamic_reconfigure"
This reverts commit 6b9d90d3d7.

Newer dynamic_reconfigure uses PYTHON_EXECUTABLE CMake substitution, eliminating the need for a shebang (or a trampoline).
2020-03-18 21:44:39 +03:00
Alexey Rogachevskiy
688b4e3acb aruco_pose: Convert largemap test to ros_pytest 2020-03-18 21:05:49 +03:00
Alexey Rogachevskiy
8042669ade clever: Remove shebang from basic.py test
Tests executed by ros_pytest are not meant to have shebangs anyway.
2020-03-18 20:47:09 +03:00
Alexey Rogachevskiy
6b9d90d3d7 aruco_pose: Use bash trampoline for dynamic_reconfigure 2020-03-18 19:17:17 +03:00
Alexey Rogachevskiy
4f110d4eaa builder: Install rpi_ws281x for Python 2 and 3 2020-03-18 17:10:50 +03:00
Alexey Rogachevskiy
f7eda0be97 Merge remote-tracking branch 'origin/master' into buster-python3 2020-03-18 16:03:02 +03:00
Alexey Rogachevskiy
1da2f76758 builder: Use pip3 for butterfly installation 2020-03-18 16:00:04 +03:00
Alexey Rogachevskiy
60a77a35a5 builder: Make pip refer to pip2 by default
This may break rosdep down the line, but it seems to call `pip3` explicitly
2020-03-18 15:58:12 +03:00
Alexey Rogachevskiy
0ffde38b8b builder: Install ptvsd for python2 explicitly 2020-02-20 21:43:48 +03:00
Alexey Rogachevskiy
99632bf554 Merge remote-tracking branch 'origin/master' into buster-python3 2020-02-20 15:44:08 +03:00
Alexey Rogachevskiy
d44a80b357 builder: Don't try to deactivate nonexistent venv 2020-02-19 13:24:42 +03:00
Alexey Rogachevskiy
77189b5f5f builder: Install butterfly system-wide 2020-02-17 14:52:24 +03:00
Alexey Rogachevskiy
b37a32d4dc builder: Add pip for python2 back 2020-02-17 14:44:41 +03:00
Alexey Rogachevskiy
b359414377 builder: Drop python2 tests 2020-02-12 23:29:04 +03:00
Alexey Rogachevskiy
6d4dd6956f tests: Use python3 for most of it, python2 for cv2 2020-02-12 22:18:03 +03:00
Alexey Rogachevskiy
cb26f0933e builder: Fix python3.yaml identation 2020-02-11 19:44:51 +03:00
Alexey Rogachevskiy
d944f57ebb builder: Put python3.yaml into image 2020-02-11 19:20:54 +03:00
Alexey Rogachevskiy
ad430284de builder: Fix typo (meodic -> melodic) 2020-02-11 18:59:23 +03:00
Alexey Rogachevskiy
b5cf47fdb5 tests: Create ServiceProxy during validation 2020-02-11 18:53:17 +03:00
Alexey Rogachevskiy
99f24abf8d builder: Build against python3 2020-02-11 18:46:23 +03:00
224 changed files with 1239 additions and 21572 deletions

View File

@@ -1,5 +1,4 @@
os: linux
dist: xenial
sudo: required
language: generic
services:
- docker
@@ -44,7 +43,7 @@ jobs:
- cd images && zip ${IMAGE_NAME}.zip ${IMAGE_NAME}
deploy:
provider: releases
token: ${GITHUB_OAUTH_TOKEN}
api_key: ${GITHUB_OAUTH_TOKEN}
file: ${IMAGE_NAME}.zip
skip_cleanup: true
on:
@@ -85,13 +84,13 @@ jobs:
- gitbook build
deploy:
provider: pages
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
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
verbose: true
on:
branch: master

234
README.md
View File

@@ -1,173 +1,103 @@
# COEX Clover Drone Kit
# CLEVER
<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>
<img src="docs/assets/clever4-front-white.png" align="right" width="400px" alt="CLEVER drone">
This repository contains documentation, software platform source code and RPi image builder for COEX Clover drone kit.
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.
<img src="docs/assets/clover42.png" align="right" width="400px" alt="COEX Clover">
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.
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.
**The main documentation is available [on Gitbook](https://clever.coex.tech/).**
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>.
Use it to learn how to assemble, configure, pilot and program autonomous CLEVER drone.
## Autonomous flights video
## Raspberry Pi image
[![Clover Drone Kit autonomy compilation](http://img.youtube.com/vi/u3omgsYC4Fk/hqdefault.jpg)](https://youtu.be/u3omgsYC4Fk)
**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).**
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 20162020](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.
[![Build Status](https://travis-ci.org/CopterExpress/clever.svg?branch=master)](https://travis-ci.org/CopterExpress/clever)
## Features
Image includes:
### Prebuilt RPi image
* Raspbian Buster
* ROS Melodic
* Configured networking
* OpenCV
* mavros
* Periphery drivers (`pigpiod`, `rpi_ws281x`, etc)
* CLEVER software bundle for autonomous drone control
...
### 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.
API description (in Russian) for autonomous flights is available [on GitBook](https://clever.coex.tech/simple_offboard.html).
## Manual installation
For manual package installation and running see [`clover` package documentation](clover/README.md).
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).
## PX4 Dev Summit 2019 talk
Clone this repo to directory `~/catkin_ws/src/clever`:
[![](http://img.youtube.com/vi/CTG9E9PbJQ8/0.jpg)](http://www.youtube.com/watch?v=CTG9E9PbJQ8)
```bash
cd ~/catkin_ws/src
git clone https://github.com/CopterExpress/clever.git clever
```
## Other resources
All the required ROS packages (including `mavros` and `opencv`) can be installed using `rosdep`:
* 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).
```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
```
## 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.
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.

View File

View File

@@ -1,6 +1,8 @@
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)
@@ -23,7 +25,7 @@ find_package(catkin REQUIRED COMPONENTS
)
find_package(OpenCV 3 REQUIRED COMPONENTS core imgproc calib3d)
if ("${OpenCV_VERSION_MINOR}" LESS "9")
if ("${OpenCV_VERSION_MINOR}" LESS "3")
message(STATUS "OpenCV version too low, using vendored ArUco package")
include(vendor/VendorOpenCV.cmake)
else()
@@ -227,5 +229,4 @@ 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()

View File

@@ -58,9 +58,10 @@ using cv::Mat;
class ArucoDetect : public nodelet::Nodelet {
private:
std::unique_ptr<tf2_ros::TransformBroadcaster> br_;
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
ros::NodeHandle nh_, nh_priv_;
tf2_ros::TransformBroadcaster br_;
tf2_ros::Buffer tf_buffer_;
tf2_ros::TransformListener tf_listener_{tf_buffer_};
std::shared_ptr<dynamic_reconfigure::Server<aruco_pose::DetectorConfig>> dyn_srv_;
cv::Ptr<cv::aruco::Dictionary> dictionary_;
cv::Ptr<cv::aruco::DetectorParameters> parameters_;
@@ -80,32 +81,30 @@ private:
public:
virtual void onInit()
{
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_));
nh_ = getNodeHandle();
nh_priv_ = getPrivateNodeHandle();
int dictionary;
dictionary = nh_priv_.param("dictionary", 2);
estimate_poses_ = nh_priv_.param("estimate_poses", true);
send_tf_ = nh_priv_.param("send_tf", true);
nh_priv_.param("dictionary", dictionary, 2);
nh_priv_.param("estimate_poses", estimate_poses_, true);
nh_priv_.param("send_tf", 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(nh_priv_);
readLengthOverride();
known_tilt_ = nh_priv_.param<std::string>("known_tilt", "");
auto_flip_ = nh_priv_.param("auto_flip", false);
nh_priv_.param<std::string>("known_tilt", known_tilt_, "");
nh_priv_.param("auto_flip", auto_flip_, false);
frame_id_prefix_ = nh_priv_.param<std::string>("frame_id_prefix", "aruco_");
nh_priv_.param<std::string>("frame_id_prefix", 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_);
@@ -171,8 +170,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());
}
@@ -206,7 +205,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);
}
}
}
@@ -327,10 +326,10 @@ private:
return frame_id_prefix_ + std::to_string(id);
}
void readLengthOverride(ros::NodeHandle& nh)
void readLengthOverride()
{
std::map<std::string, double> length_override;
nh.getParam("length_override", length_override);
nh_priv_.getParam("length_override", length_override);
for (auto const& item : length_override) {
length_override_[std::stoi(item.first)] = item.second;
}

View File

@@ -58,6 +58,7 @@ 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_;
@@ -82,8 +83,8 @@ private:
public:
virtual void onInit()
{
ros::NodeHandle &nh_ = getNodeHandle();
ros::NodeHandle &nh_priv_ = getPrivateNodeHandle();
nh_ = getNodeHandle();
nh_priv_ = getPrivateNodeHandle();
image_transport::ImageTransport it_priv(nh_priv_);
@@ -95,18 +96,19 @@ 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;
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", "");
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_, "");
// createStripLine();
@@ -114,7 +116,7 @@ public:
param(nh_priv_, "map", map);
loadMap(map);
} else if (type == "gridboard") {
createGridBoard(nh_priv_);
createGridBoard();
} else {
NODELET_FATAL("unknown type: %s", type.c_str());
ros::shutdown();
@@ -329,7 +331,7 @@ publish_debug:
NODELET_INFO("loading %s complete (%d markers)", filename.c_str(), static_cast<int>(board_->ids.size()));
}
void createGridBoard(ros::NodeHandle& nh)
void createGridBoard()
{
NODELET_INFO("generate gridboard");
NODELET_WARN("gridboard maps are deprecated");
@@ -337,15 +339,15 @@ publish_debug:
int markers_x, markers_y, first_marker;
double markers_side, markers_sep_x, markers_sep_y;
std::vector<int> marker_ids;
markers_x = nh.param("markers_x", 10);
markers_y = nh.param("markers_y", 10);
first_marker = nh.param("first_marker", 0);
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);
param(nh, "markers_side", markers_side);
param(nh, "markers_sep_x", markers_sep_x);
param(nh, "markers_sep_y", markers_sep_y);
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);
if (nh.getParam("marker_ids", marker_ids)) {
if (nh_priv_.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();
@@ -392,7 +394,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/clover/blob/master/aruco_pose/README.md#parameters for details",
"Please see https://github.com/CopterExpress/clever/blob/master/aruco_pose/README.md#parameters for details",
id, num_markers);
return;
}

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# Copyright (C) 2018 Copter Express Technologies
#

View File

@@ -35,7 +35,9 @@ 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];
dist = cv::Mat(cinfo->D, true);
for (unsigned int k = 0; k < cinfo->D.size(); k++)
dist.at<double>(k) = cinfo->D[k];
}
inline void rotatePoint(cv::Point3f& p, cv::Point3f origin, float angle)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

View File

@@ -1,18 +0,0 @@
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)

View File

@@ -1,51 +0,0 @@
<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>

View File

@@ -1,26 +1,19 @@
#!/usr/bin/env python
import sys
import unittest
import json
import rospy
import rostest
import pytest
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)
class TestArucoPose(unittest.TestCase):
def setUp(self):
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')
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)
def test_large_map_visualization(node):
vis = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
assert len(vis.markers) == 11

View File

@@ -9,5 +9,6 @@
<param name="map" value="$(find aruco_pose)/test/largemap.txt"/>
</node>
<test test-name="test_aruco_pose_largemap" pkg="aruco_pose" type="largemap.py"/>
<param name="test_module" value="$(find aruco_pose)/test/largemap.py"/>
<test test-name="test_node_pass" pkg="ros_pytest" type="ros_pytest_runner"/>
</launch>

View File

@@ -924,8 +924,6 @@ 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]);
}

View File

@@ -1,5 +1,5 @@
{
"title": "Clover",
"title": "Clever",
"description": "Конструктор квадрокоптера «Клевер»",
"author": "Copter Express",
"language": "en",
@@ -28,7 +28,7 @@
"blank": true
},
"sitemap": {
"hostname": "https://clover.coex.tech"
"hostname": "https://clever.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/clover/edit/master/docs/{{filepath_lang}}"
"url": "https://github.com/CopterExpress/clever/edit/master/docs/{{filepath_lang}}"
},
{
"label": "GitHub",
"icon": "fa fa-github",
"position" : "left",
"url": "https://github.com/CopterExpress/clover"
"url": "https://github.com/CopterExpress/clever"
}
]
},
"addcssjs": {
"css": ["../clover.css"],
"js": ["../clover.js"]
"css": ["../clever.css"],
"js": ["../clever.js"]
},
"language-picker": {
"languages": [["ru", "Russian"], ["en", "English"]]

View File

@@ -1,34 +0,0 @@
<?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>

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from distutils.core import setup

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/programming
# Information: https://clever.coex.tech/en/programming.html
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)
# Take off and hover 1 m above the ground
# Takeoff and hover 1 m above the ground
navigate(x=0, y=0, z=1, frame_id='body', auto_arm=True)
# Wait for 3 seconds

View File

@@ -1,37 +0,0 @@
# 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()

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/en/leds.html
# Information: https://clever.coex.tech/en/leds.html
import rospy
from clover.srv import SetLEDEffect

View File

@@ -1,41 +0,0 @@
# 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()

View File

@@ -62,10 +62,6 @@ 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

View File

@@ -20,7 +20,7 @@
# Example:
# DocumentRoot /home/krypton/htdocs
DocumentRoot /home/pi/.ros/www
DocumentRoot /home/pi/catkin_ws/src/clover/clover/www
# Redirect:
# ---------

View File

@@ -0,0 +1,9 @@
python3-wxgtk:
debian:
buster: [python3-wxgtk4.0]
python3-serial:
debian:
buster: [python3-serial]
python3-requests:
debian:
buster: [python3-requests]

View File

@@ -108,8 +108,6 @@ ${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)
@@ -117,6 +115,7 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/avahi-s
${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/'

View File

@@ -68,7 +68,8 @@ 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/20-default.list
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
my_travis_retry rosdep update
echo_stamp "Populate rosdep for ROS user"
@@ -87,6 +88,7 @@ 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
@@ -95,11 +97,15 @@ 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 pip install wheel
my_travis_retry pip install -r /home/pi/catkin_ws/src/clover/clover/requirements.txt
my_travis_retry pip3 install wheel
my_travis_retry pip3 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
@@ -129,7 +135,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)
pip install tornado==4.2.1
pip3 install tornado==4.2.1
echo_stamp "Running tests"
cd /home/pi/catkin_ws
@@ -143,6 +149,7 @@ 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

View File

@@ -57,10 +57,6 @@ 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'
@@ -71,7 +67,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/rpi-ros-melodic buster main" > /etc/apt/sources.list.d/rpi-ros-melodic.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/clover buster main" > /etc/apt/sources.list.d/clover.list
echo_stamp "Update apt cache"
@@ -99,21 +95,21 @@ libjpeg8 \
tcpdump \
ltrace \
libpoco-dev \
libzbar0 \
python-rosdep \
python-rosinstall-generator \
python-wstool \
python-rosinstall \
python3-rosdep \
python3-rosinstall-generator \
python3-wstool \
python3-rosinstall \
build-essential \
libffi-dev \
monkey \
pigpio python-pigpio python3-pigpio \
i2c-tools \
espeak espeak-data python-espeak \
espeak espeak-data python3-espeak \
ntpdate \
python-dev \
python3-dev \
python-systemd \
python3-venv \
python3-systemd \
mjpg-streamer \
python3-opencv \
&& echo_stamp "Everything was installed!" "SUCCESS" \
@@ -137,13 +133,14 @@ 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==5.1.1
my_travis_retry pip3 install tornado==4.2.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 pip install --prefer-binary rpi_ws281x
my_travis_retry pip2 install --prefer-binary rpi_ws281x
my_travis_retry pip3 install --prefer-binary rpi_ws281x
echo_stamp "Setup Monkey"
mv /etc/monkey/sites/default /etc/monkey/sites/default.orig
@@ -159,13 +156,9 @@ rm -rf node-v10.15.0-linux-armv6l/
rm node-v10.15.0-linux-armv6l.tar.gz
echo_stamp "Installing ptvsd"
my_travis_retry pip install ptvsd
my_travis_retry pip2 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

View File

@@ -18,13 +18,15 @@ 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
./tests_py3.py
# Disable Python 2 tests for image - we're dropping support, right?
# ./tests_py2.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"

View File

@@ -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

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# validate all required modules installed
@@ -17,6 +17,8 @@ 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
@@ -26,6 +28,5 @@ from pymavlink import mavutil
import rpi_ws281x
import pigpio
from espeak import espeak
from pyzbar import pyzbar
print cv2.getBuildInformation()
print(cv2.getBuildInformation())

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# test backwards compatibility

7
builder/test/tests_py2.py Executable file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env python
# Make sure our Python 2 software is installed
import cv2
print(cv2.getBuildInformation())

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env python3
# Make sure our Python 3 software is installed
import cv2
from pyzbar import pyzbar
print(cv2.getBuildInformation())

View File

@@ -30,12 +30,6 @@ 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)
@@ -210,7 +204,6 @@ 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}
)
#############

View File

@@ -1,73 +0,0 @@
# `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
```

View File

@@ -0,0 +1,45 @@
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.

View File

@@ -1,17 +1,17 @@
image_width: 640
image_height: 480
distortion_model: plumb_bob
camera_name: main_camera_optical
camera_name: raspicam
camera_matrix:
rows: 3
cols: 3
data:
- 332.47884746146343
- 0.
- 320.0
- 324.38022493658536
- 0.
- 333.1761847948052
- 240.0
- 219.6445547142857
- 0.
- 0.
- 1.

View File

@@ -3,20 +3,18 @@
<arg name="aruco_map" default="false"/>
<arg name="aruco_vpe" default="false"/>
<!-- For additional help go to https://clover.coex.tech/aruco -->
<!-- For additional help go to https://clever.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 -->

View File

@@ -1,7 +1,6 @@
<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"/>
@@ -20,7 +19,6 @@
<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>
@@ -82,9 +80,4 @@
<!-- 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>

View File

@@ -1,5 +1,5 @@
<launch>
<!-- article about camera setup: https://clover.coex.tech/camera_setup -->
<!-- article about camera setup: https://clever.coex.tech/camera_frame -->
<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.yaml"/>
<param name="camera_info_url" value="file://$(find clover)/camera_info/fisheye_cam_320.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 -->
<!-- camera resolution, NOTE: camera_info file should match it -->
<param name="image_width" value="320"/>
<param name="image_height" value="240"/>
</node>

View File

@@ -1,7 +1,6 @@
<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"/>
@@ -20,9 +19,6 @@
<!-- 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')"/>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<package format="2">
<package format="3">
<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://clover.coex.tech/</url>
<url type="website">https://clever.coex.tech/</url>
<author email="okalachev@gmail.com">Oleg Kalachev</author>
<author email="urpylka@gmail.com">Artem Smirnov</author>
@@ -37,8 +37,10 @@
<depend>rosbridge_server</depend>
<depend>web_video_server</depend>
<depend>tf2_web_republisher</depend>
<depend>python-lxml</depend>
<exec_depend>python-pymavlink</exec_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>
<!-- Use test_depend for packages you need only for testing: -->
<!-- <test_depend>gtest</test_depend> -->

View File

@@ -1,5 +1,5 @@
flask==1.1.1
docopt==0.6.2
geopy==1.11.0
smbus2==0.2.1
VL53L1X==0.0.2
geopy==1.20.0
smbus2==0.3.0
VL53L1X==0.0.4

View File

@@ -34,7 +34,9 @@ class OpticalFlow : public nodelet::Nodelet
{
public:
OpticalFlow():
camera_matrix_(3, 3, CV_64F)
camera_matrix_(3, 3, CV_64F),
dist_coeffs_(8, 1, CV_64F),
tf_listener_(tf_buffer_)
{}
private:
@@ -50,8 +52,8 @@ private:
Mat hann_;
Mat prev_, curr_;
Mat camera_matrix_, dist_coeffs_;
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
tf2_ros::Buffer tf_buffer_;
tf2_ros::TransformListener tf_listener_;
bool calc_flow_gyro_;
void onInit()
@@ -61,14 +63,11 @@ private:
image_transport::ImageTransport it(nh);
image_transport::ImageTransport it_priv(nh_priv);
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);
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);
img_sub_ = it.subscribeCamera("image_raw", 1, &OpticalFlow::flow, this);
img_pub_ = it_priv.advertise("debug", 1);
@@ -92,7 +91,9 @@ private:
camera_matrix_.at<double>(i, j) = cinfo->K[3 * i + j];
}
}
dist_coeffs_ = cv::Mat(cinfo->D, true);
for (int k = 0; k < cinfo->D.size(); k++) {
dist_coeffs_.at<double>(k) = cinfo->D[k];
}
}
void drawFlow(Mat& frame, double x, double y, double quality) const
@@ -185,7 +186,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;
@@ -199,7 +200,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;
@@ -246,8 +247,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;

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# 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=map(ord, cmd.ljust(70, '\0')))
data=[ord(c) for c in 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://clover.coex.tech/firmware')
failure('not running Clover PX4 firmware, https://clever.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://clover.coex.tech/power')
failure('cell voltage is not available, https://clever.coex.tech/power')
else:
cell = battery.cell_voltage[0]
if cell > 4.3 or cell < 3.0:
failure('incorrect cell voltage: %.2f V, https://clover.coex.tech/power', cell)
failure('incorrect cell voltage: %.2f V, https://clever.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')
output = subprocess.check_output('systemd-analyze').decode()
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)
output = subprocess.check_output(CMD, shell=True).decode()
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)
stderr=subprocess.STDOUT).decode()
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://clover.coex.tech/hostname', ros_hostname)
failure('not found %s in /etc/hosts, ROS will malfunction if network interfaces are down, https://clever.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'])
output = subprocess.check_output(['vcgencmd', 'get_throttled']).decode()
except OSError:
failure('could not call vcgencmd binary; not a Raspberry Pi?')
return

View File

@@ -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://clover.coex.tech/connection");
throw std::runtime_error("No connection to FCU, https://clever.coex.tech/connection");
}
#define ENSURE_FINITE(var) { if (!std::isfinite(var)) throw std::runtime_error(#var " argument cannot be NaN or Inf"); }

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
import rospy
import pytest
from mavros_msgs.msg import State

View File

@@ -1,7 +1,7 @@
<h1>Clover Drone Kit Tools</h1>
<ul>
<li><a href="docs">View documentation</a> (snapshot of <a href="https://clover.coex.tech">clover.coex.tech</a>)</li>
<li><a href="docs">View documentation</a> (snapshot of <a href="https://clever.coex.tech">clever.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.protocol + '//' + location.hostname + ':8080';
document.querySelector("#butterfly").href = location.protocol + '//' + location.hostname + ':57575';
document.querySelector("#wvs").href = location.origin + ':8080';
document.querySelector("#butterfly").href = location.origin + ':57575';
// Determine image version
var ros = new ROSLIB.Ros({ url: 'ws://' + location.hostname + ':9090' });

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,134 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -1,69 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

View File

@@ -40,7 +40,7 @@ section ul li:before {
margin-bottom: 0.85em;
}
/* Main Clover image */
/* Main Clever image */
.book img.bigclever {
margin-bottom: -12%;
}

View File

@@ -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 Clover 3 drone that's capable of autonomous flight and wrote a flight program.
We provided a Clever 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.

View File

@@ -1,12 +1,12 @@
# COEX Clover
# COEX Clever
<img class="center bigclever zoom" src="../assets/clever4-front-white-large.png" width="80%" alt="COEX Clover 4">
<img class="center bigclever zoom" src="../assets/clever4-front-white-large.png" width="80%" alt="COEX Clever 4">
**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.
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.
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 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 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).
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).
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).

View File

@@ -4,14 +4,13 @@
* [Glossary](gloss.md)
* [Safety tips](safety.md)
* Assembly
* [Clover 4 assembly](assemble_4.md)
* [Clover 3 assembly](assemble_3.md)
* [Clover 2 assembly](assemble_2.md)
* [Clever 4 assembly](assemble_4.md)
* [Clever 3 assembly](assemble_3.md)
* [Clever 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)
@@ -42,8 +41,7 @@
* [Interfacing with a sonar](sonar.md)
* [Computer vision basics](camera.md)
* [Using rviz and rqt](rviz.md)
* [Software autorun](autolaunch.md)
* [Using JavaScript](javascript.md)
* [Software autorun](autolaunch.md)
* [ROS](ros.md)
* [MAVROS](mavros.md)
* Supplementary materials
@@ -54,9 +52,8 @@
* [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)
* [Clover and Jetson Nano](jetson_nano.md)
* [Clever and Jetson Nano](jetson_nano.md)
* [Remote control app](rc.md)
* [Wi-Fi Configuration](network.md)
* [UART settings](uart.md)
@@ -67,20 +64,18 @@
* [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)
* [Migration to v0.20](migrate20.md)
* Clover-based projects
* [Drone show](clever-show.md)
* Clever-based projects
* [Copter spheric guard](shield.md)
* [Face recognition system](face_recognition.md)
* [Android RC app](android.md)
@@ -89,5 +84,3 @@
* [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)

View File

@@ -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/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:
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:
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/clover/tree/master/apps/android/app/src/main/assets)
2. Add to it all files from [here](https://github.com/CopterExpress/clever/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:

View File

@@ -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 Clover and connected via a USB port.
Arudino is to be installed on Clever 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 clover arduino.launch
roslaunch clever arduino.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`):
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`):
```xml
<arg name="arduino" default="true"/>
```
After the launch file is edited, restart the `clover` service:
After the launch file is edited, restart package `clever`:
```(bash)
sudo systemctl restart clover
sudo systemctl restart clever
```
## Delays
@@ -59,7 +59,7 @@ for(int i=0; i<8; i++) {
}
```
## Working with Clover
## Working with Clever
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 Clover and MAVROS package message header files
#include <clover/Navigate.h>
// Connecting Clever and MAVROS package message header files
#include <clever/Navigate.h>
#include <mavros_msgs/SetMode.h>
using namespace clover;
using namespace clever;
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 <clover/GetTelemetry.h>
#include <clever/GetTelemetry.h>
// ...

View File

@@ -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/clover/blob/v0.15.1/docs/en/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/clever/blob/v0.15.1/docs/ru/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/.
[Clover Raspberry Pi image](image.md) contains a pre-installed `aruco_pose` ROS package, which can be used for marker detection.
[Clever 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 Clover drone:
There are several preconfigured modes of operation for ArUco markers on the Clever 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/clover/blob/master/aruco_pose/README.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).

View File

@@ -10,13 +10,13 @@
## Configuration
Set the `aruco` argument in `~/catkin_ws/src/clover/clover/launch/clover.launch` to `true`:
Set the `aruco` argument in `~/catkin_ws/src/clever/clever/launch/clever.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/clover/clover/launch/aruco.launch`:
In order to enable map detection set `aruco_map` and `aruco_detect` arguments to `true` in `~/catkin_ws/src/clever/clever/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/clover/aruco_pose/map`](https://github.com/CopterExpress/clover/tree/master/aruco_pose/map).
Some map examples are provided in [`~/catkin_ws/src/clever/aruco_pose/map`](https://github.com/CopterExpress/clever/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/clover/aruco_pose/map/test_map.txt
rosrun aruco_pose genmap.py length x y dist_x dist_y first > ~/catkin_ws/src/clever/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/clo
Usage example:
```bash
rosrun aruco_pose genmap.py 0.33 2 4 1 1 0 > ~/catkin_ws/src/clover/aruco_pose/map/test_map.txt
rosrun aruco_pose genmap.py 0.33 2 4 1 1 0 > ~/catkin_ws/src/clever/aruco_pose/map/test_map.txt
```
Additional information on the utility can be obtained using `-h` key: `rosrun aruco_pose genmap.py -h`.
@@ -91,6 +91,13 @@ 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.
@@ -101,13 +108,6 @@ 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/clover/clover/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/clever/clever/launch/aruco.launch`:
```xml
<param name="known_tilt" value="map_flipped"/>

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