Compare commits

...

76 Commits

Author SHA1 Message Date
Oleg Kalachev
34560c0b34 Continue working on the new readme page 2020-08-28 21:32:02 +03:00
Oleg Kalachev
4bf9f728b1 Rework main readme.md 2020-07-29 09:53:17 +03:00
Oleg Kalachev
0172d6e892 docs: simplify leds examples 2020-06-13 02:11:45 +03:00
Oleg Kalachev
bcb7351a90 roswww_static: infrastructure for web-based Clover plugins (#230)
* Package for generating static web sites for ROS

* rosstatic: add CMakeLists.txt

* rosstatic: utilize rospkg, store static directory in ROS_HOME

* rosstatic: default_package param

* rosstatic: fix URLs in docs

* clover.launch: make clover the default package for www

* Unused import

* Rename rosstatic to roswww_static

* Fixes
2020-06-13 02:08:00 +03:00
Oleg Kalachev
c71a46ce9d Put CATKIN_IGNORE file to some directories 2020-06-11 16:13:07 +03:00
Oleg Kalachev
91dd7799ef image: remove unneeded ROS_DISTRO settings from .bashrc 2020-06-10 23:25:57 +03:00
Oleg Kalachev
3682e253a7 selfcheck.py: don’t fall when ROS_HOSTNAME is not set 2020-06-10 22:40:49 +03:00
Alexey Rogachevskiy
66ecbb4d09 docs: Update ROS repository keys (en/ru) 2020-06-10 14:51:13 +03:00
Alexey Rogachevskiy
f041b6125b Add Avahi services broadcasting (#231)
* Builder: Add Avahi services broadcasting

* avahi-services: Remove http.service

* builder: Expose sftp-ssh instead of just ssh, fix build
2020-06-03 22:35:48 +03:00
Oleg Kalachev
a4f2bab3d7 docs: fix incorrect order of focused and unfocused camera image 2020-06-03 08:15:35 +03:00
Oleg Kalachev
56bcfa5c87 Enable back publishing documentation 2020-06-02 11:54:08 +03:00
Alexey Rogachevskiy
998796045c aruco_pose nodelet cleanup (#239)
* aruco_pose: Unhardcode contour refinement

Besides, this was basically a no-op anyway, since dynamic parameters
overwrote that anyway.

* aruco_pose: Late-construct objects that use ROS

* aruco_map: Don't create/store node handle

* aruco_pose: Don't assume dist_coeffs size

* aruco_pose: more const == more better

* aruco_pose: Be more obvious about changing variables

* aruco_pose: Fix building for Kinetic

* aruco_pose: Remove global add_definitions
2020-05-30 01:59:51 +03:00
Alexey Rogachevskiy
c5e954b56a optical_flow: Use functional-style parameter fetching 2020-05-30 01:58:14 +03:00
Alexey Rogachevskiy
2814fea9cd optical_flow: Pass nodelet callback queue to TransformListener 2020-05-30 01:58:14 +03:00
Alexey Rogachevskiy
b85326c02a optical_flow: Use cv::Mat(std::vector, bool) ctor for dist_coeffs_ 2020-05-30 01:58:14 +03:00
Alexey Rogachevskiy
98d5d50607 aruco_pose: Prevent OpenCV from crashing (#238)
* aruco_pose: Add tests that crash OpenCV

* aruco_pose: Don't try to interpolate single points
2020-05-30 01:57:14 +03:00
Alexey Rogachevskiy
69c46786de builder: Set apt retries to 3
This should lower the number of builds that failed due to
repositories being unstable
2020-05-29 21:25:58 +03:00
Oleg Kalachev
abb495275b docs: translate robocross-2019 article 2020-05-26 06:54:42 +03:00
Oleg Kalachev
044d6c6d33 docs: switch lpe and ekf2 settings in aruco map navigation articles 2020-05-21 21:01:16 +03:00
Alexey Rogachevskiy
22d5a356b6 clover: Update ros3djs, THREE.js 2020-05-18 16:25:56 +03:00
Alexey Rogachevskiy
c7828557ca standalone_install: Fail on error 2020-05-16 15:49:38 +03:00
Alexey Rogachevskiy
514c0f1b65 Flysky FS-A8S article (#229)
* docs: Add FS-A8S article draft

* docs: Fix image links

* docs/flysky_a8s: Make images appear smaller

* docs: Add animated images

* docs/flysky_a8s: Proofreading

* docs/flysky_a8s: Sync up header to summary entry

* docs/flysky_a8s: Add Flysky FS-A8S article (en)

* docs/flysky_a8s: More proofreading
2020-05-12 12:35:05 +03:00
Oleg Kalachev
6a79b8292a docs: little fix 2020-05-08 17:02:36 +03:00
Oleg Kalachev
10b6661266 docs: add images for ROS javascript article 2020-05-08 16:54:10 +03:00
Oleg Kalachev
7f2cb1c63e docs: add using ROS with javascript article 2020-05-08 16:51:15 +03:00
Oleg Kalachev
1d48c79c52 docs: rename package and service to clover 2020-05-07 19:43:25 +03:00
Oleg Kalachev
ad46a0918c Temporarily disable documentation upload 2020-05-07 19:03:51 +03:00
Alexey Rogachevskiy
9487522992 clover: Use saner min marker perimeter rate 2020-05-07 18:07:11 +03:00
Oleg Kalachev
80b35d3b90 Change camera calibration name to main_camera_optical 2020-05-06 19:49:45 +03:00
VeneraDal
12e292c9d7 docs: add Russian and English trainer mode article (#219)
* Upload trainer_mode.md

Add an English version of the file

* Update trainer mode article

* Update SUMMARY.md

For adding the trainer mode article

* Update SUMMARY.md

For adding trainer mode article

* docs: edit trainer mode articles

* docs: move trainer mode article in summary

* docs: fix

* Update SUMMARY.md

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2020-05-06 19:41:17 +03:00
Alexey Rogachevskiy
9b28e9cad2 travis: Resolve some issues with validation 2020-05-06 16:39:24 +03:00
Alexey Rogachevskiy
d57ab82f38 docs: Fix up according to MD037 2020-05-06 15:03:39 +03:00
Oleg Kalachev
c8da639eab Merge pull request #227 from goldarte/target-system-id
Add fcu_sys_id argument to clover.launch
2020-05-06 13:30:46 +03:00
Alexey Rogachevskiy
c7e7edec70 builder: Enable ROS services after first boot (#208)
Merging this into master, this should not break anything.
2020-05-06 13:24:53 +03:00
Oleg Kalachev
72869fcf2b Merge pull request #216 from CopterExpress/new-camera-calib
Average camera calibration
2020-05-01 01:04:04 +03:00
Oleg Kalachev
387d2c2341 Update documentation links 2020-05-01 00:39:38 +03:00
Oleg Kalachev
a665caeea3 docs: small fixes 2020-04-30 20:04:20 +03:00
Oleg Kalachev
3079d2a3e1 docs: typos 2020-04-30 20:02:31 +03:00
Alexey Rogachevskiy
7d5bdf4f22 docs/migrate20: Remove extra space character 2020-04-30 19:35:51 +03:00
Oleg Kalachev
2a3efa2908 docs: reflect camera frame configuration changes 2020-04-30 05:03:29 +03:00
Oleg Kalachev
ddee29a0e8 docs: English version on 0.20 image transition article + add to summary 2020-04-30 04:19:09 +03:00
Oleg Kalachev
8596be07c6 docs: add article on migration to v0.20 2020-04-30 04:02:52 +03:00
Oleg Kalachev
a480ebe80a Continue renaming to Clover 2020-04-30 03:41:14 +03:00
Oleg Kalachev
77ca50b901 docs: change rpi version on main page 2020-04-30 01:39:56 +03:00
Oleg Kalachev
ead9b904fa docs: small fix 2020-04-29 05:05:22 +03:00
Oleg Kalachev
90956ecd44 docs: English version of new camera calibration article 2020-04-29 04:44:52 +03:00
Oleg Kalachev
f070c60e14 docs: add example of wait_for_message for rangefinder 2020-04-28 05:53:45 +03:00
Arthur Golubtsov
68edf07f6e Add fcu_sys_id argument to clover.launch and mavros.launch to set up target_system_id parameter in mavros 2020-04-27 15:36:08 +03:00
Oleg Kalachev
7f161b1ad7 Fix Travis badge 2020-04-26 08:00:33 +03:00
Oleg Kalachev
a41a432ef3 Fixes 2020-04-23 21:20:29 +03:00
Oleg Kalachev
2b896b06d9 Move manual installation and running to clover/readme.md 2020-04-23 21:19:46 +03:00
Oleg Kalachev
5070cafbfb Update main readme 2020-04-23 20:54:15 +03:00
Oleg Kalachev
9c0af7285c docs: decrease video size in clever-show article 2020-04-20 18:25:06 +03:00
Arthur Golubtsov
c67d937842 docs: Add article about clever-show (#226)
* docs: Add article about clever-show

* docs: Fix mistake in sentence in en clever-show article

* docs: Add dots to clever-show article

* docs: resolve conflict

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2020-04-20 13:30:20 +03:00
Oleg Kalachev
b79d87242f docs: add p4df2 team article in NTI olympics 2020 2020-04-18 15:42:55 +03:00
Alamoris
4d0ddcb319 docs: fix .html link typo 2020-04-18 15:12:09 +03:00
Oleg Kalachev
3ff4ee6c4c docs: add instructions on easy way of sending documentation updates 2020-04-18 14:36:15 +03:00
Oleg Kalachev
90049182cf image: add navigate_wait example 2020-04-09 15:44:48 +03:00
Oleg Kalachev
33f4601fdc docs: add example on retrieving one camera frame 2020-04-09 15:32:45 +03:00
Arthur Golubtsov
2a62891d60 Install pyzbar to image (#225)
* Install pyzbar to image

I suggest installing pyzbar to RPi image for making barcodes scanning easier during different competitions.

* pyzbar: Add libzbar0 install

* pyzbar: Add simple tests

* pyzbar: Update docs
2020-04-09 04:16:05 +03:00
Alamoris
b043737e91 docs: An article on how to configure an image for flying on wall markers (#221)
* docs: Add a draft of an article about flying using wall markers

* docs: Add paragraph about setting up launch files

* docs: Fix typos and add some links

* Small logic fixes

* docs: fix

* docs: Add description setting for earlier version

* docs: Fix sed string

* docs: Add article about wall aruco in summary
2020-04-08 15:13:32 +03:00
Oleg Kalachev
c61a0485ff docs: fix 2020-04-07 17:35:07 +03:00
Arthur Golubtsov
f1539177eb docs: Update install instruction for qr code scan 2020-04-07 17:25:11 +03:00
Arthur Golubtsov
6cbbb5580e docs (en): Update qr code scan instruction and script 2020-04-07 17:06:05 +03:00
Arthur Golubtsov
c2d22ae12a docs: fix codestyle in camera.md 2020-04-07 16:58:20 +03:00
Arthur Golubtsov
7160d804cd docs (ru): Update qr code scan instruction and script 2020-04-07 16:47:03 +03:00
Oleg Kalachev
3ac51baf7c docs: small fix
It’s better not to nest the throttled image topic as this way consumers would subscribe to appropriate camera_info topic automatically
2020-04-07 02:58:08 +03:00
Alamoris
48cc82001d docs: Fix typo 2020-04-03 21:15:04 +03:00
Alamoris
43eae885c6 docs: Add small mounting deck model 2020-04-03 21:13:14 +03:00
Alexey Rogachevskiy
2bb29ff389 clover: Add required OpenCV libraries 2020-03-31 23:56:04 +03:00
Oleg Kalachev
3811cbff3e examples: fix markers example link 2020-03-19 13:10:05 +03:00
Oleg Kalachev
2d49f58fb8 image: add markers flight example 2020-03-19 13:09:31 +03:00
Oleg Kalachev
bbcf75b806 docs: add gyro calibration snippet 2020-03-18 21:52:19 +03:00
Oleg Kalachev
3e79c25147 Camera info resolution matching camera resolution is not necessary with auto rescaling 2020-02-20 19:16:23 +03:00
Oleg Kalachev
2f69ad3f43 Keep only one calibration file 2020-02-13 23:17:52 +03:00
Oleg Kalachev
b08ad5a618 Camera calibration: set principal point strictly to the center 2020-02-13 23:14:05 +03:00
216 changed files with 77869 additions and 5455 deletions

View File

@@ -1,4 +1,5 @@
sudo: required
os: linux
dist: xenial
language: generic
services:
- docker
@@ -43,7 +44,7 @@ jobs:
- cd images && zip ${IMAGE_NAME}.zip ${IMAGE_NAME}
deploy:
provider: releases
api_key: ${GITHUB_OAUTH_TOKEN}
token: ${GITHUB_OAUTH_TOKEN}
file: ${IMAGE_NAME}.zip
skip_cleanup: true
on:
@@ -84,13 +85,13 @@ jobs:
- gitbook build
deploy:
provider: pages
local-dir: _book
skip-cleanup: true
github-token: ${GITHUB_OAUTH_TOKEN}
keep-history: true
target-branch: master
repo: CopterExpress/clever.coex.tech
fqdn: clever.coex.tech
local_dir: _book
skip_cleanup: true
token: ${GITHUB_OAUTH_TOKEN}
keep_history: true
target_branch: master
repo: CopterExpress/clover.coex.tech
fqdn: clover.coex.tech
verbose: true
on:
branch: master

234
README.md
View File

@@ -1,103 +1,173 @@
# CLEVER
# COEX Clover Drone Kit
<img src="docs/assets/clever4-front-white.png" align="right" width="400px" alt="CLEVER drone">
<table align=center>
<tr>
<td align=center><a href="https://px4.io"><img src="docs/assets/px4.svg" height=60></a></td>
<td align=center><a href="https://www.raspberrypi.org"><img src="docs/assets/rpi.svg" height=60></a></td>
<td align=center><a href="https://www.ros.org"><img src="docs/assets/ros.svg" height=60></a></td>
</tr>
</table>
CLEVER (Russian: *"Клевер"*, meaning *"Clover"*) is an educational programmable drone kit consisting of an unassembled quadcopter, open source software and documentation. The kit includes Pixhawk/Pixracer autopilot running PX4 firmware, Raspberry Pi 3 as companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices.
This repository contains documentation, software platform source code and RPi image builder for COEX Clover drone kit.
Copter Express has implemented a large number of different autonomous drone projects using exactly the same platform: [automated pizza delivery](https://www.youtube.com/watch?v=hmkAoZOtF58) in Samara and Kazan, coffee delivery in Skolkovo Innovation Center, [autonomous quadcopter with charging station](https://www.youtube.com/watch?v=RjX6nUqw1mI) for site monitoring and security, winning drones on [Robocross-2016](https://www.youtube.com/watch?v=dGbDaz_VmYU) and [Robocross-2017](https://youtu.be/AQnd2CRczbQ) competitions and many others.
<img src="docs/assets/clover42.png" align="right" width="400px" alt="COEX Clover">
**The main documentation is available [on Gitbook](https://clever.coex.tech/).**
Clover is a [PX4](https://px4.io)- and [ROS](https://www.ros.org)-powered educational programmable drone kit consisting of an unassembled quadcopter, open source software and documentation. The kit includes Pixracer-compatible autopilot, Raspberry Pi 4 as companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices.
Use it to learn how to assemble, configure, pilot and program autonomous CLEVER drone.
The main documentation is available at [https://clover.coex.tech](https://clover.coex.tech/). Official website: <a href="https://coex.tech/clover">coex.tech/clover</a>.
## Raspberry Pi image
## Autonomous flights video
**Preconfigured image for Raspberry Pi 3 with installed and configured software, ready to fly, is available [in the Releases section](https://github.com/CopterExpress/clever/releases).**
[![Clover Drone Kit autonomy compilation](http://img.youtube.com/vi/u3omgsYC4Fk/hqdefault.jpg)](https://youtu.be/u3omgsYC4Fk)
[![Build Status](https://travis-ci.org/CopterExpress/clever.svg?branch=master)](https://travis-ci.org/CopterExpress/clever)
Clover drone is used on a wide range of educational events, including [Copter Hack](https://www.youtube.com/watch?v=xgXheg3TTs4), WorldSkills Drone Operation competition, [Autonomous Vehicles Track of NTI Olympics 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.
Image includes:
## Features
* Raspbian Buster
* ROS Melodic
* Configured networking
* OpenCV
* mavros
* Periphery drivers (`pigpiod`, `rpi_ws281x`, etc)
* CLEVER software bundle for autonomous drone control
### Prebuilt RPi image
API description (in Russian) for autonomous flights is available [on GitBook](https://clever.coex.tech/simple_offboard.html).
...
### Common robotics software
Prebuilt image for Raspberry Pi includes:
|Software|Description|
|-|-|
|Raspbian Buster||
|[ROS Melodic](http://wiki.ros.org/melodic)|Common robotics framework|
|[OpenCV](https://opencv.org)|Computer vision library|
|[`mavros`](http://wiki.ros.org/mavros)|ROS package for communication with the flight controller|
|Configured networking||
|Periphery drivers for ROS ([GPIO](https://clover.coex.tech/en/gpio.html), [LED strip](https://clover.coex.tech/en/leds.html), etc)||
|`clover`|package for autonomous drone control|
|`aruco_pose`|Package for marker-assisted navigation|
### QGroundControl Wi-Fi bridge
...
### Easy autonomous flights programming
By using `clover` package, taking off, navigating and landing is just:
```python
navigate(x=0, y=0, z=1, frame_id='body', auto_arm=True) # takeoff and hover 1 m above the ground
```
```python
navigate(x=1, y=0, z=0, frame_id='body') # fly forward 1 m
```
```
land()
```
See [programming documentation](https://clover.coex.tech) for further information.
### Optical flow positioning
<img src="docs/assets/optical-flow.gif">
RPi based optical flow....
See [details](https://clover.coex.tech/en/optical_flow.html) in the documentation.
### ArUco markers recognizing
<img src="docs/assets/aruco.gif">
...
See [details](https://clover.coex.tech/en/aruco.html) in the documentation.
### Easy working with peripheral devices
Preinstalled package for the [LED strip](https://clover.coex.tech/en/leds.html) allows high-level control (such as rainbow effect or color fade) as well as individual LED low-level control:
```python
set_effect(r=0, g=100, b=0) # fill strip with green color
```
```python
set_effect(effect='fade', r=0, g=0, b=255) # fade to blue color
```
```python
set_effect(effect='rainbow') # show rainbow
```
Preinstalled [VL53L1X rangefinder driver](https://clover.coex.tech/en/laser.html) passes data to the flight controller automatically and allows the user to get its data:
```python
data = rospy.wait_for_message('rangefinder/range', Range) # get data from the rangefinder
```
Preinstalled fast Python [GPIO library](https://clover.coex.tech/en/gpio.html).
```python
pi.write(11, 1) # set signal of pin 11 to high
```
```python
level = pi.read(12) # read the state of pin 12
```
### Simulator
<img src="docs/assets/simulator.jpg" width=400 align=center>
Clover repository includes three simulation-related repository for Gazebo-based simulation.
Screenshot...
See details in the [documentation](https://clover.coex.tech/en/simulation.html). The simulation environment also available as a virtual machine image.
### Remote control apps
<table>
<tr>
<td>
<a href="https://itunes.apple.com/ru/app/clever-rc/id1396166572?mt=8">
<img src="docs/assets/appstore.svg" height=40>
</a>
</td>
<td>
<a href="https://play.google.com/store/apps/details?id=express.copter.cleverrc">
<img src="docs/assets/google_play.png" height=40>
</a>
</td>
</tr>
</table>
<!-- <a href="https://itunes.apple.com/ru/app/clever-rc/id1396166572?mt=8"><img src="docs/assets/appstore.svg"></a><a href="https://play.google.com/store/apps/details?id=express.copter.cleverrc"><img src="docs/assets/google_play.png" width="15%"></a> -->
### Community
<img src="docs/assets/community/collage.jpg" width=400 align=center>
Clover is widely used ...
[Telegram chat](tg://resolve?domain=COEXHelpdesk)...
### Free and open source
The Clover software bundle is free, open source, and compatible with any PX4/ROS-based drone.
## Manual installation
Install ROS Melodic according to the [documentation](http://wiki.ros.org/melodic/Installation), then [create a Catkin workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace).
For manual package installation and running see [`clover` package documentation](clover/README.md).
Clone this repo to directory `~/catkin_ws/src/clever`:
## PX4 Dev Summit 2019 talk
```bash
cd ~/catkin_ws/src
git clone https://github.com/CopterExpress/clever.git clever
```
[![](http://img.youtube.com/vi/CTG9E9PbJQ8/0.jpg)](http://www.youtube.com/watch?v=CTG9E9PbJQ8)
All the required ROS packages (including `mavros` and `opencv`) can be installed using `rosdep`:
## Other resources
```bash
cd ~/catkin_ws/
rosdep install -y --from-paths src --ignore-src
```
Build ROS packages (on memory constrained platforms you might be going to need to use `-j1` key):
```bash
cd ~/catkin_ws
catkin_make -j1
```
To complete `mavros` install you'll need to install `geographiclib` datasets:
```bash
curl https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | sudo bash
```
You may optionally install udev rules to provide `/dev/px4fmu` symlink to your PX4-based flight controller connected over USB. Copy `99-px4fmu.rules` to your `/lib/udev/rules.d` folder:
```bash
cd ~/catkin_ws/src/clever/clever/config
sudo cp 99-px4fmu.rules /lib/udev/rules.d
```
Alternatively you may change the `fcu_url` property in `mavros.launch` file to point to your flight controller device.
## Running
Enable systemd service `roscore` (if not running):
```bash
sudo systemctl enable /home/<username>/catkin_ws/src/clever/builder/assets/roscore.service
sudo systemctl start roscore
```
To start connection to SITL, use:
```bash
roslaunch clever sitl.launch
```
To start connection to the flight controller, use:
```bash
roslaunch clever clever.launch
```
> Note that the package is configured to connect to `/dev/px4fmu` by default (see [previous section](#manual-installation)). Install udev rules or specify path to your FCU device in `mavros.launch`.
Also, you can enable and start the systemd service:
```bash
sudo systemctl enable /home/<username>/catkin_ws/src/clever/deploy/clever.service
sudo systemctl start clever
```
* Official documentation: [https://clover.coex.tech](https://clover.coex.tech).
* ROS Wiki page: [https://wiki.ros.org/Robots/clover](https://wiki.ros.org/Robots/clover).
* ROS Robots page: [https://robots.ros.org/clover](https://robots.ros.org/clover).
## License
While the Clever platform source code is available under the MIT License, note, that the [documentation](docs/) is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
While the Clover platform source code is available under the MIT License, note, that the [documentation](docs/) is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

0
apps/CATKIN_IGNORE Normal file
View File

View File

@@ -1,8 +1,6 @@
cmake_minimum_required(VERSION 3.0)
project(aruco_pose)
add_definitions(-std=c++11 -Wall -g)
## Compile as C++11, supported in ROS Kinetic and newer
add_compile_options(-std=c++11)
@@ -25,7 +23,7 @@ find_package(catkin REQUIRED COMPONENTS
)
find_package(OpenCV 3 REQUIRED COMPONENTS core imgproc calib3d)
if ("${OpenCV_VERSION_MINOR}" LESS "3")
if ("${OpenCV_VERSION_MINOR}" LESS "9")
message(STATUS "OpenCV version too low, using vendored ArUco package")
include(vendor/VendorOpenCV.cmake)
else()
@@ -229,4 +227,5 @@ if (CATKIN_ENABLE_TESTING)
add_rostest(test/test_parser_empty_map.test)
add_rostest(test/test_node_failure.test)
add_rostest(test/largemap.test)
add_rostest(test/crash_opencv.test)
endif()

View File

@@ -58,10 +58,9 @@ using cv::Mat;
class ArucoDetect : public nodelet::Nodelet {
private:
ros::NodeHandle nh_, nh_priv_;
tf2_ros::TransformBroadcaster br_;
tf2_ros::Buffer tf_buffer_;
tf2_ros::TransformListener tf_listener_{tf_buffer_};
std::unique_ptr<tf2_ros::TransformBroadcaster> br_;
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
std::shared_ptr<dynamic_reconfigure::Server<aruco_pose::DetectorConfig>> dyn_srv_;
cv::Ptr<cv::aruco::Dictionary> dictionary_;
cv::Ptr<cv::aruco::DetectorParameters> parameters_;
@@ -81,30 +80,32 @@ private:
public:
virtual void onInit()
{
nh_ = getNodeHandle();
nh_priv_ = getPrivateNodeHandle();
ros::NodeHandle& nh_ = getNodeHandle();
ros::NodeHandle& nh_priv_ = getPrivateNodeHandle();
br_.reset(new tf2_ros::TransformBroadcaster());
tf_buffer_.reset(new tf2_ros::Buffer());
tf_listener_.reset(new tf2_ros::TransformListener(*tf_buffer_, nh_));
int dictionary;
nh_priv_.param("dictionary", dictionary, 2);
nh_priv_.param("estimate_poses", estimate_poses_, true);
nh_priv_.param("send_tf", send_tf_, true);
dictionary = nh_priv_.param("dictionary", 2);
estimate_poses_ = nh_priv_.param("estimate_poses", true);
send_tf_ = nh_priv_.param("send_tf", true);
if (estimate_poses_ && !nh_priv_.getParam("length", length_)) {
NODELET_FATAL("can't estimate marker's poses as ~length parameter is not defined");
ros::shutdown();
}
readLengthOverride();
readLengthOverride(nh_priv_);
nh_priv_.param<std::string>("known_tilt", known_tilt_, "");
nh_priv_.param("auto_flip", auto_flip_, false);
known_tilt_ = nh_priv_.param<std::string>("known_tilt", "");
auto_flip_ = nh_priv_.param("auto_flip", false);
nh_priv_.param<std::string>("frame_id_prefix", frame_id_prefix_, "aruco_");
frame_id_prefix_ = nh_priv_.param<std::string>("frame_id_prefix", "aruco_");
camera_matrix_ = cv::Mat::zeros(3, 3, CV_64F);
dist_coeffs_ = cv::Mat::zeros(8, 1, CV_64F);
dictionary_ = cv::aruco::getPredefinedDictionary(static_cast<cv::aruco::PREDEFINED_DICTIONARY_NAME>(dictionary));
parameters_ = cv::aruco::DetectorParameters::create();
parameters_->cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX;
image_transport::ImageTransport it(nh_);
image_transport::ImageTransport it_priv(nh_priv_);
@@ -170,8 +171,8 @@ private:
if (!known_tilt_.empty()) {
try {
snap_to = tf_buffer_.lookupTransform(msg->header.frame_id, known_tilt_,
msg->header.stamp, ros::Duration(0.02));
snap_to = tf_buffer_->lookupTransform(msg->header.frame_id, known_tilt_,
msg->header.stamp, ros::Duration(0.02));
} catch (const tf2::TransformException& e) {
NODELET_WARN_THROTTLE(5, "can't snap: %s", e.what());
}
@@ -205,7 +206,7 @@ private:
if (map_markers_ids_.find(ids[i]) == map_markers_ids_.end()) {
transform.transform.rotation = marker.pose.orientation;
fillTranslation(transform.transform.translation, tvecs[i]);
br_.sendTransform(transform);
br_->sendTransform(transform);
}
}
}
@@ -326,10 +327,10 @@ private:
return frame_id_prefix_ + std::to_string(id);
}
void readLengthOverride()
void readLengthOverride(ros::NodeHandle& nh)
{
std::map<std::string, double> length_override;
nh_priv_.getParam("length_override", length_override);
nh.getParam("length_override", length_override);
for (auto const& item : length_override) {
length_override_[std::stoi(item.first)] = item.second;
}

View File

@@ -58,7 +58,6 @@ typedef message_filters::sync_policies::ExactTime<Image, CameraInfo, MarkerArray
class ArucoMap : public nodelet::Nodelet {
private:
ros::NodeHandle nh_, nh_priv_;
ros::Publisher img_pub_, pose_pub_, markers_pub_, vis_markers_pub_;
image_transport::Publisher debug_pub_;
message_filters::Subscriber<Image> image_sub_;
@@ -83,8 +82,8 @@ private:
public:
virtual void onInit()
{
nh_ = getNodeHandle();
nh_priv_ = getPrivateNodeHandle();
ros::NodeHandle &nh_ = getNodeHandle();
ros::NodeHandle &nh_priv_ = getPrivateNodeHandle();
image_transport::ImageTransport it_priv(nh_priv_);
@@ -96,19 +95,18 @@ public:
board_->dictionary = cv::aruco::getPredefinedDictionary(
static_cast<cv::aruco::PREDEFINED_DICTIONARY_NAME>(nh_priv_.param("dictionary", 2)));
camera_matrix_ = cv::Mat::zeros(3, 3, CV_64F);
dist_coeffs_ = cv::Mat::zeros(8, 1, CV_64F);
std::string type, map;
nh_priv_.param<std::string>("type", type, "map");
nh_priv_.param<std::string>("frame_id", transform_.child_frame_id, "aruco_map");
nh_priv_.param<std::string>("known_tilt", known_tilt_, "");
nh_priv_.param("auto_flip", auto_flip_, false);
nh_priv_.param("image_width", image_width_, 2000);
nh_priv_.param("image_height", image_height_, 2000);
nh_priv_.param("image_margin", image_margin_, 200);
nh_priv_.param("image_axis", image_axis_, true);
nh_priv_.param<std::string>("markers/frame_id", markers_parent_frame_, transform_.child_frame_id);
nh_priv_.param<std::string>("markers/child_frame_id_prefix", markers_frame_, "");
type = nh_priv_.param<std::string>("type", "map");
transform_.child_frame_id = nh_priv_.param<std::string>("frame_id", "aruco_map");
known_tilt_ = nh_priv_.param<std::string>("known_tilt", "");
auto_flip_ = nh_priv_.param("auto_flip", false);
image_width_ = nh_priv_.param("image_width" , 2000);
image_height_ = nh_priv_.param("image_height", 2000);
image_margin_ = nh_priv_.param("image_margin", 200);
image_axis_ = nh_priv_.param("image_axis", true);
markers_parent_frame_ = nh_priv_.param<std::string>("markers/frame_id", transform_.child_frame_id);
markers_frame_ = nh_priv_.param<std::string>("markers/child_frame_id_prefix", "");
// createStripLine();
@@ -116,7 +114,7 @@ public:
param(nh_priv_, "map", map);
loadMap(map);
} else if (type == "gridboard") {
createGridBoard();
createGridBoard(nh_priv_);
} else {
NODELET_FATAL("unknown type: %s", type.c_str());
ros::shutdown();
@@ -331,7 +329,7 @@ publish_debug:
NODELET_INFO("loading %s complete (%d markers)", filename.c_str(), static_cast<int>(board_->ids.size()));
}
void createGridBoard()
void createGridBoard(ros::NodeHandle& nh)
{
NODELET_INFO("generate gridboard");
NODELET_WARN("gridboard maps are deprecated");
@@ -339,15 +337,15 @@ publish_debug:
int markers_x, markers_y, first_marker;
double markers_side, markers_sep_x, markers_sep_y;
std::vector<int> marker_ids;
nh_priv_.param<int>("markers_x", markers_x, 10);
nh_priv_.param<int>("markers_y", markers_y, 10);
nh_priv_.param<int>("first_marker", first_marker, 0);
markers_x = nh.param("markers_x", 10);
markers_y = nh.param("markers_y", 10);
first_marker = nh.param("first_marker", 0);
param(nh_priv_, "markers_side", markers_side);
param(nh_priv_, "markers_sep_x", markers_sep_x);
param(nh_priv_, "markers_sep_y", markers_sep_y);
param(nh, "markers_side", markers_side);
param(nh, "markers_sep_x", markers_sep_x);
param(nh, "markers_sep_y", markers_sep_y);
if (nh_priv_.getParam("marker_ids", marker_ids)) {
if (nh.getParam("marker_ids", marker_ids)) {
if ((unsigned int)(markers_x * markers_y) != marker_ids.size()) {
NODELET_FATAL("~marker_ids length should be equal to ~markers_x * ~markers_y");
ros::shutdown();
@@ -394,7 +392,7 @@ publish_debug:
int num_markers = board_->dictionary->bytesList.rows;
if (num_markers <= id) {
NODELET_ERROR("Marker id %d is not in dictionary; current dictionary contains %d markers. "
"Please see https://github.com/CopterExpress/clever/blob/master/aruco_pose/README.md#parameters for details",
"Please see https://github.com/CopterExpress/clover/blob/master/aruco_pose/README.md#parameters for details",
id, num_markers);
return;
}

View File

@@ -35,9 +35,7 @@ static void parseCameraInfo(const sensor_msgs::CameraInfoConstPtr& cinfo, cv::Ma
for (unsigned int i = 0; i < 3; ++i)
for (unsigned int j = 0; j < 3; ++j)
matrix.at<double>(i, j) = cinfo->K[3 * i + j];
for (unsigned int k = 0; k < cinfo->D.size(); k++)
dist.at<double>(k) = cinfo->D[k];
dist = cv::Mat(cinfo->D, true);
}
inline void rotatePoint(cv::Point3f& p, cv::Point3f origin, float angle)

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

View File

@@ -0,0 +1,18 @@
import rospy
import pytest
from visualization_msgs.msg import MarkerArray as VisMarkerArray
@pytest.fixture
def node():
return rospy.init_node('aruco_pose_opencv_crash', anonymous=True)
def test_opencv_crashes_img01(node):
rospy.wait_for_message('aruco_detect_01/visualization', VisMarkerArray, timeout=5)
def test_opencv_crashes_img02(node):
rospy.wait_for_message('aruco_detect_02/visualization', VisMarkerArray, timeout=5)
def test_opencv_crashes_img03(node):
rospy.wait_for_message('aruco_detect_03/visualization', VisMarkerArray, timeout=5)

View File

@@ -0,0 +1,51 @@
<launch>
<arg name="corner_method" default="2"/>
<node pkg="image_publisher" type="image_publisher" name="imgpub_01" args="$(find aruco_pose)/test/crash_image_01.png">
<param name="frame_id" value="main_camera_optical"/>
<param name="publish_rate" value="10"/>
<param name="camera_info_url" value="file://$(find aruco_pose)/test/camera_info.yaml" />
</node>
<node pkg="image_publisher" type="image_publisher" name="imgpub_02" args="$(find aruco_pose)/test/crash_image_02.png">
<param name="frame_id" value="main_camera_optical"/>
<param name="publish_rate" value="10"/>
<param name="camera_info_url" value="file://$(find aruco_pose)/test/camera_info.yaml" />
</node>
<node pkg="image_publisher" type="image_publisher" name="imgpub_03" args="$(find aruco_pose)/test/crash_image_03.png">
<param name="frame_id" value="main_camera_optical"/>
<param name="publish_rate" value="10"/>
<param name="camera_info_url" value="file://$(find aruco_pose)/test/camera_info.yaml" />
</node>
<node pkg="nodelet" type="nodelet" name="nodelet_manager_01" args="manager"/>
<node pkg="nodelet" clear_params="true" type="nodelet" name="aruco_detect_01" args="load aruco_pose/aruco_detect nodelet_manager_01">
<remap from="image_raw" to="imgpub_01/image_raw"/>
<remap from="camera_info" to="imgpub_01/camera_info"/>
<param name="length" value="0.33"/>
<param name="cornerRefinementMethod" value="$(arg corner_method)"/>
</node>
<node pkg="nodelet" type="nodelet" name="nodelet_manager_02" args="manager"/>
<node pkg="nodelet" clear_params="true" type="nodelet" name="aruco_detect_02" args="load aruco_pose/aruco_detect nodelet_manager_02">
<remap from="image_raw" to="imgpub_02/image_raw"/>
<remap from="camera_info" to="imgpub_02/camera_info"/>
<param name="length" value="0.33"/>
<param name="cornerRefinementMethod" value="$(arg corner_method)"/>
</node>
<node pkg="nodelet" type="nodelet" name="nodelet_manager_03" args="manager"/>
<node pkg="nodelet" clear_params="true" type="nodelet" name="aruco_detect_03" args="load aruco_pose/aruco_detect nodelet_manager_03">
<remap from="image_raw" to="imgpub_03/image_raw"/>
<remap from="camera_info" to="imgpub_03/camera_info"/>
<param name="length" value="0.33"/>
<param name="cornerRefinementMethod" value="$(arg corner_method)"/>
</node>
<param name="test_module" value="$(find aruco_pose)/test/crash_opencv.py"/>
<test test-name="crash_opencv" pkg="ros_pytest" type="ros_pytest_runner"/>
</launch>

View File

@@ -924,6 +924,8 @@ static void _refineCandidateLines(std::vector<Point>& nContours, std::vector<Poi
// calculate the line :: who passes through the grouped points
Point3f lines[4];
for(int i=0; i<4; i++){
// Don't try to "interpolate" single points
if (cntPts[i].size() < 2) return;
lines[i]=_interpolate2Dline(cntPts[i]);
}

View File

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

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<!--
This file is part of avahi.
avahi is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
avahi is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with avahi; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
-->
<!-- See avahi.service(5) for more information about this configuration file -->
<service-group>
<name replace-wildcards="yes">%h</name>
<service>
<type>_sftp-ssh._tcp</type>
<port>22</port>
</service>
</service-group>

View File

@@ -1,4 +1,4 @@
# Information: https://clever.coex.tech/en/programming.html
# Information: https://clover.coex.tech/programming
import rospy
from clover import srv
@@ -15,7 +15,7 @@ set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)
set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)
land = rospy.ServiceProxy('land', Trigger)
# Takeoff and hover 1 m above the ground
# Take off and hover 1 m above the ground
navigate(x=0, y=0, z=1, frame_id='body', auto_arm=True)
# Wait for 3 seconds

View File

@@ -0,0 +1,37 @@
# Information: https://clover.coex.tech/en/aruco.html
import rospy
from clover import srv
from std_srvs.srv import Trigger
rospy.init_node('flight')
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
navigate = rospy.ServiceProxy('navigate', srv.Navigate)
navigate_global = rospy.ServiceProxy('navigate_global', srv.NavigateGlobal)
set_position = rospy.ServiceProxy('set_position', srv.SetPosition)
set_velocity = rospy.ServiceProxy('set_velocity', srv.SetVelocity)
set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)
set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)
land = rospy.ServiceProxy('land', Trigger)
# Take off and hover 1 m above the ground
navigate(x=0, y=0, z=1, frame_id='body', auto_arm=True)
# Wait for 3 seconds
rospy.sleep(3)
# Fly 1 meter above ArUco marker 0
navigate(x=0, y=0, z=1, frame_id='aruco_0')
# Wait for 3 seconds
rospy.sleep(3)
# Fly to x=1 y=1 z=1 relative to ArUco markers map
navigate(x=1, y=1, z=1, frame_id='aruco_map')
# Wait for 3 seconds
rospy.sleep(3)
# Perform landing
land()

View File

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

View File

@@ -0,0 +1,41 @@
# Information: https://clover.coex.tech/en/snippets.html#block-nav
import math
import rospy
from clover import srv
from std_srvs.srv import Trigger
rospy.init_node('flight')
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
navigate = rospy.ServiceProxy('navigate', srv.Navigate)
navigate_global = rospy.ServiceProxy('navigate_global', srv.NavigateGlobal)
set_position = rospy.ServiceProxy('set_position', srv.SetPosition)
set_velocity = rospy.ServiceProxy('set_velocity', srv.SetVelocity)
set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)
set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)
land = rospy.ServiceProxy('land', Trigger)
def navigate_wait(x=0, y=0, z=0, yaw=float('nan'), yaw_rate=0, speed=0.5, \
frame_id='body', tolerance=0.2, auto_arm=False):
res = navigate(x=x, y=y, z=z, yaw=yaw, yaw_rate=yaw_rate, speed=speed, \
frame_id=frame_id, auto_arm=auto_arm)
if not res.success:
return res
while not rospy.is_shutdown():
telem = get_telemetry(frame_id='navigate_target')
if math.sqrt(telem.x ** 2 + telem.y ** 2 + telem.z ** 2) < tolerance:
return res
rospy.sleep(0.2)
# Take off 1 meter
navigate_wait(z=1, frame_id='body', auto_arm=True)
# Fly forward 1 m
navigate_wait(x=1, frame_id='body')
# Land
land()

View File

@@ -62,6 +62,10 @@ hostnamectl set-hostname $NEW_HOSTNAME
sed -i 's/127\.0\.1\.1.*/127.0.1.1\t'${NEW_HOSTNAME}' '${NEW_HOSTNAME}'.local/g' /etc/hosts
# .local (mdns) hostname added to make it accesable when wlan and ethernet interfaces are down
echo_stamp "Enable ROS services"
systemctl enable roscore
systemctl enable clover
echo_stamp "Harware setup"
/root/hardware_setup.sh

View File

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

View File

@@ -108,6 +108,8 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-software
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/examples' '/home/pi/'
# network setup
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-network.sh'
# avahi setup
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/avahi-services/sftp-ssh.service' '/etc/avahi/services'
# If RPi then use a one thread to build a ROS package on RPi, else use all
[[ $(arch) == 'armv7l' ]] && NUMBER_THREADS=1 || NUMBER_THREADS=$(nproc --all)

View File

@@ -100,10 +100,6 @@ my_travis_retry pip install -r /home/pi/catkin_ws/src/clover/clover/requirements
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
@@ -147,7 +143,6 @@ echo_stamp "Setup ROS environment"
cat << EOF >> /home/pi/.bashrc
LANG='C.UTF-8'
LC_ALL='C.UTF-8'
ROS_DISTRO='melodic'
export ROS_HOSTNAME=\`hostname\`.local
source /opt/ros/melodic/setup.bash
source /home/pi/catkin_ws/devel/setup.bash

View File

@@ -57,6 +57,10 @@ my_travis_retry() {
return $result
}
echo_stamp "Increase apt retries"
echo "APT::Acquire::Retries \"3\";" > /etc/apt/apt.conf.d/80-retries
echo_stamp "Install apt keys & repos"
# TODO: This STDOUT consist 'OK'
@@ -95,6 +99,7 @@ libjpeg8 \
tcpdump \
ltrace \
libpoco-dev \
libzbar0 \
python-rosdep \
python-rosinstall-generator \
python-wstool \
@@ -157,6 +162,10 @@ echo_stamp "Installing ptvsd"
my_travis_retry pip install ptvsd
my_travis_retry pip3 install ptvsd
echo_stamp "Installing pyzbar"
my_travis_retry pip install pyzbar
my_travis_retry pip3 install pyzbar
echo_stamp "Add .vimrc"
cat << EOF > /home/pi/.vimrc
set mouse-=a

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

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

View File

@@ -3,5 +3,6 @@
# Make sure our Python 3 software is installed
import cv2
from pyzbar import pyzbar
print(cv2.getBuildInformation())

View File

@@ -30,6 +30,12 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
find_package(GeographicLib REQUIRED)
find_package(OpenCV 3 REQUIRED
COMPONENTS
calib3d
imgproc
)
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
@@ -204,6 +210,7 @@ add_dependencies(shell ${PROJECT_NAME}_generate_messages_cpp)
## Specify libraries to link a library or executable target against
target_link_libraries(${PROJECT_NAME}
${catkin_LIBRARIES}
${OpenCV_LIBRARIES}
)
#############

73
clover/README.md Normal file
View File

@@ -0,0 +1,73 @@
# `clover` ROS package
A bundle for autonomous navigation and drone control.
## Manual installation
Install ROS Melodic according to the [documentation](http://wiki.ros.org/melodic/Installation), then [create a Catkin workspace](http://wiki.ros.org/catkin/Tutorials/create_a_workspace).
Clone this repo to directory `~/catkin_ws/src/clover`:
```bash
cd ~/catkin_ws/src
git clone https://github.com/CopterExpress/clover.git clover
```
All the required ROS packages (including `mavros` and `opencv`) can be installed using `rosdep`:
```bash
cd ~/catkin_ws/
rosdep install -y --from-paths src --ignore-src
```
Build ROS packages (on memory constrained platforms you might be going to need to use `-j1` key):
```bash
cd ~/catkin_ws
catkin_make -j1
```
To complete `mavros` install you'll need to install `geographiclib` datasets:
```bash
curl https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | sudo bash
```
You may optionally install udev rules to provide `/dev/px4fmu` symlink to your PX4-based flight controller connected over USB. Copy `99-px4fmu.rules` to your `/lib/udev/rules.d` folder:
```bash
cd ~/catkin_ws/src/clover/clover/config
sudo cp 99-px4fmu.rules /lib/udev/rules.d
```
Alternatively you may change the `fcu_url` property in `mavros.launch` file to point to your flight controller device.
## Running
Enable systemd service `roscore` (if not running):
```bash
sudo systemctl enable /home/<username>/catkin_ws/src/clover/builder/assets/roscore.service
sudo systemctl start roscore
```
To start connection to SITL, use:
```bash
roslaunch clover sitl.launch
```
To start connection to the flight controller, use:
```bash
roslaunch clover clover.launch
```
> Note that the package is configured to connect to `/dev/px4fmu` by default (see [previous section](#manual-installation)). Install udev rules or specify path to your FCU device in `mavros.launch`.
Also, you can enable and start the systemd service:
```bash
sudo systemctl enable /home/<username>/catkin_ws/src/clover/deploy/clover.service
sudo systemctl start clover
```

View File

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

View File

@@ -1,45 +0,0 @@
image_width: 320
image_height: 240
distortion_model: plumb_bob
camera_name: raspicam
camera_matrix:
rows: 3
cols: 3
data:
- 166.23942373073172
- 0.
- 162.19011246829268
- 0.
- 166.5880923974026
- 109.82227735714285
- 0.
- 0.
- 1.
distortion_coefficients:
rows: 1
cols: 8
data: [ 2.15356885e-01, -1.17472846e-01, -3.06197672e-04,
-1.09444025e-04, -4.53657258e-03, 5.73090623e-01,
-1.27574577e-01, -2.86125589e-02, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00]
rectification_matrix:
rows: 3
cols: 3
data: [1, 0, 0, 0, 1, 0, 0, 0, 1]
projection_matrix:
rows: 3
cols: 4
data:
- 166.23942373073172
- 0.
- 162.19011246829268
- 0.
- 0.
- 166.5880923974026
- 109.82227735714285
- 0.
- 0.
- 0.
- 1.
- 0.

View File

@@ -3,18 +3,20 @@
<arg name="aruco_map" default="false"/>
<arg name="aruco_vpe" default="false"/>
<!-- For additional help go to https://clever.coex.tech/aruco -->
<!-- For additional help go to https://clover.coex.tech/aruco -->
<!-- aruco_detect: detect aruco markers, estimate poses -->
<node name="aruco_detect" pkg="nodelet" if="$(arg aruco_detect)" type="nodelet" args="load aruco_pose/aruco_detect nodelet_manager" output="screen" clear_params="true">
<remap from="image_raw" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/>
<remap from="map_markers" to="aruco_map/markers" if="$(arg aruco_map)"/>
<param name="cornerRefinementMethod" value="2"/>
<param name="estimate_poses" value="true"/>
<param name="send_tf" value="true"/>
<param name="known_tilt" value="map"/>
<param name="length" value="0.33"/>
<!-- aruco detector parameters -->
<param name="cornerRefinementMethod" value="2"/> <!-- contour refinement -->
<param name="minMarkerPerimeterRate" value="0.075"/> <!-- 0.075 for 320x240, 0.0375 for 640x480 -->
</node>
<!-- aruco_map: estimate aruco map pose -->

View File

@@ -1,6 +1,7 @@
<launch>
<arg name="fcu_conn" default="usb"/>
<arg name="fcu_ip" default="127.0.0.1"/>
<arg name="fcu_sys_id" default="1"/>
<arg name="gcs_bridge" default="tcp"/>
<arg name="web_video_server" default="true"/>
<arg name="rosbridge" default="true"/>
@@ -19,6 +20,7 @@
<include file="$(find clover)/launch/mavros.launch">
<arg name="fcu_conn" value="$(arg fcu_conn)"/>
<arg name="fcu_ip" value="$(arg fcu_ip)"/>
<arg name="fcu_sys_id" value="$(arg fcu_sys_id)"/>
<arg name="gcs_bridge" value="$(arg gcs_bridge)"/>
</include>
@@ -80,4 +82,9 @@
<!-- Shell access through ROS service -->
<node name="shell" pkg="clover" type="shell" output="screen" if="$(arg shell)"/>
<!-- Update static directory -->
<node pkg="roswww_static" name="roswww_static" type="main.py" clear_params="true">
<param name="default_package" value="clover"/>
</node>
</launch>

View File

@@ -1,5 +1,5 @@
<launch>
<!-- article about camera setup: https://clever.coex.tech/camera_frame -->
<!-- article about camera setup: https://clover.coex.tech/camera_setup -->
<arg name="direction_z" default="down"/> <!-- direction the camera points: down, up -->
<arg name="direction_y" default="backward"/> <!-- direction the camera cable points: backward, forward -->
@@ -18,14 +18,14 @@
<node pkg="nodelet" type="nodelet" name="main_camera" args="load cv_camera/CvCameraNodelet nodelet_manager" clear_params="true">
<param name="device_path" value="/dev/video0"/> <!-- v4l2 device -->
<param name="frame_id" value="main_camera_optical"/>
<param name="camera_info_url" value="file://$(find clover)/camera_info/fisheye_cam_320.yaml"/>
<param name="camera_info_url" value="file://$(find clover)/camera_info/fisheye_cam.yaml"/>
<param name="rate" value="100"/> <!-- poll rate -->
<param name="cv_cap_prop_fps" value="40"/> <!-- camera FPS -->
<param name="capture_delay" value="0.02"/> <!-- approximate delay on frame retrieving -->
<param name="rescale_camera_info" value="true"/> <!-- automatically rescale camera calibration info -->
<!-- camera resolution, NOTE: camera_info file should match it -->
<!-- camera resolution -->
<param name="image_width" value="320"/>
<param name="image_height" value="240"/>
</node>

View File

@@ -1,6 +1,7 @@
<launch>
<arg name="fcu_conn" default="usb"/> <!-- options: usb, uart, tcp, udp, sitl -->
<arg name="fcu_ip" default="127.0.0.1"/>
<arg name="fcu_sys_id" default="1"/>
<arg name="gcs_bridge" default="tcp"/>
<arg name="viz" default="true"/>
<arg name="respawn" default="true"/>
@@ -19,6 +20,9 @@
<!-- sitl since PX4 1.9.0 -->
<param name="fcu_url" value="udp://@$(arg fcu_ip):14580" if="$(eval fcu_conn == 'sitl')"/>
<!-- set target_system_id -->
<param name="target_system_id" value="$(arg fcu_sys_id)" />
<!-- gcs bridge -->
<param name="gcs_url" value="tcp-l://0.0.0.0:5760" if="$(eval gcs_bridge == 'tcp')"/>
<param name="gcs_url" value="udp://0.0.0.0:14550@14550" if="$(eval gcs_bridge == 'udp')"/>

View File

@@ -7,7 +7,7 @@
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
<license>MIT</license>
<url type="website">https://clever.coex.tech/</url>
<url type="website">https://clover.coex.tech/</url>
<author email="okalachev@gmail.com">Oleg Kalachev</author>
<author email="urpylka@gmail.com">Artem Smirnov</author>

View File

@@ -34,9 +34,7 @@ class OpticalFlow : public nodelet::Nodelet
{
public:
OpticalFlow():
camera_matrix_(3, 3, CV_64F),
dist_coeffs_(8, 1, CV_64F),
tf_listener_(tf_buffer_)
camera_matrix_(3, 3, CV_64F)
{}
private:
@@ -52,8 +50,8 @@ private:
Mat hann_;
Mat prev_, curr_;
Mat camera_matrix_, dist_coeffs_;
tf2_ros::Buffer tf_buffer_;
tf2_ros::TransformListener tf_listener_;
std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
bool calc_flow_gyro_;
void onInit()
@@ -63,11 +61,14 @@ private:
image_transport::ImageTransport it(nh);
image_transport::ImageTransport it_priv(nh_priv);
nh.param<std::string>("mavros/local_position/tf/frame_id", local_frame_id_, "map");
nh.param<std::string>("mavros/local_position/tf/child_frame_id", fcu_frame_id_, "base_link");
nh_priv.param("roi", roi_px_, 128);
nh_priv.param("roi_rad", roi_rad_, 0.0);
nh_priv.param("calc_flow_gyro", calc_flow_gyro_, false);
tf_buffer_.reset(new tf2_ros::Buffer());
tf_listener_.reset(new tf2_ros::TransformListener(*tf_buffer_, nh));
local_frame_id_ = nh.param<std::string>("mavros/local_position/tf/frame_id", "map");
fcu_frame_id_ = nh.param<std::string>("mavros/local_position/tf/child_frame_id", "base_link");
roi_px_ = nh_priv.param("roi", 128);
roi_rad_ = nh_priv.param("roi_rad", 0.0);
calc_flow_gyro_ = nh_priv.param("calc_flow_gyro", false);
img_sub_ = it.subscribeCamera("image_raw", 1, &OpticalFlow::flow, this);
img_pub_ = it_priv.advertise("debug", 1);
@@ -91,9 +92,7 @@ private:
camera_matrix_.at<double>(i, j) = cinfo->K[3 * i + j];
}
}
for (int k = 0; k < cinfo->D.size(); k++) {
dist_coeffs_.at<double>(k) = cinfo->D[k];
}
dist_coeffs_ = cv::Mat(cinfo->D, true);
}
void drawFlow(Mat& frame, double x, double y, double quality) const
@@ -186,7 +185,7 @@ private:
flow_camera.vector.x = flow_y; // +y means counter-clockwise rotation around Y axis
flow_camera.vector.y = -flow_x; // +x means clockwise rotation around X axis
try {
tf_buffer_.transform(flow_camera, flow_fcu, fcu_frame_id_);
tf_buffer_->transform(flow_camera, flow_fcu, fcu_frame_id_);
} catch (const tf2::TransformException& e) {
// transform is not available yet
return;
@@ -200,7 +199,7 @@ private:
try {
auto flow_gyro_camera = calcFlowGyro(msg->header.frame_id, prev_stamp_, msg->header.stamp);
static geometry_msgs::Vector3Stamped flow_gyro_fcu;
tf_buffer_.transform(flow_gyro_camera, flow_gyro_fcu, fcu_frame_id_);
tf_buffer_->transform(flow_gyro_camera, flow_gyro_fcu, fcu_frame_id_);
flow_.integrated_xgyro = flow_gyro_fcu.vector.x;
flow_.integrated_ygyro = flow_gyro_fcu.vector.y;
flow_.integrated_zgyro = flow_gyro_fcu.vector.z;
@@ -247,8 +246,8 @@ private:
geometry_msgs::Vector3Stamped calcFlowGyro(const std::string& frame_id, const ros::Time& prev, const ros::Time& curr)
{
tf2::Quaternion prev_rot, curr_rot;
tf2::fromMsg(tf_buffer_.lookupTransform(frame_id, local_frame_id_, prev).transform.rotation, prev_rot);
tf2::fromMsg(tf_buffer_.lookupTransform(frame_id, local_frame_id_, curr, ros::Duration(0.1)).transform.rotation, curr_rot);
tf2::fromMsg(tf_buffer_->lookupTransform(frame_id, local_frame_id_, prev).transform.rotation, prev_rot);
tf2::fromMsg(tf_buffer_->lookupTransform(frame_id, local_frame_id_, curr, ros::Duration(0.1)).transform.rotation, curr_rot);
geometry_msgs::Vector3Stamped flow;
flow.header.frame_id = frame_id;

View File

@@ -210,7 +210,7 @@ def check_fcu():
is_clover_firmware = True
if not is_clover_firmware:
failure('not running Clover PX4 firmware, https://clever.coex.tech/firmware')
failure('not running Clover PX4 firmware, https://clover.coex.tech/firmware')
est = get_param('SYS_MC_EST_GROUP')
if est == 1:
@@ -250,11 +250,11 @@ def check_fcu():
try:
battery = rospy.wait_for_message('mavros/battery', BatteryState, timeout=3)
if not battery.cell_voltage:
failure('cell voltage is not available, https://clever.coex.tech/power')
failure('cell voltage is not available, https://clover.coex.tech/power')
else:
cell = battery.cell_voltage[0]
if cell > 4.3 or cell < 3.0:
failure('incorrect cell voltage: %.2f V, https://clever.coex.tech/power', cell)
failure('incorrect cell voltage: %.2f V, https://clover.coex.tech/power', cell)
elif cell < 3.7:
failure('critically low cell voltage: %.2f V, recharge battery', cell)
except rospy.ROSException:
@@ -701,7 +701,7 @@ def check_preflight_status():
@check('Network')
def check_network():
ros_hostname = os.environ.get('ROS_HOSTNAME').strip()
ros_hostname = os.environ.get('ROS_HOSTNAME', '').strip()
if not ros_hostname:
failure('no ROS_HOSTNAME is set')
@@ -718,7 +718,7 @@ def check_network():
if ros_hostname in parts:
break
else:
failure('not found %s in /etc/hosts, ROS will malfunction if network interfaces are down, https://clever.coex.tech/hostname', ros_hostname)
failure('not found %s in /etc/hosts, ROS will malfunction if network interfaces are down, https://clover.coex.tech/hostname', ros_hostname)
@check('RPi health')

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

0
clover/www/CATKIN_IGNORE Normal file
View File

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://clever.coex.tech">clever.coex.tech</a>)</li>
<li><a href="docs">View documentation</a> (snapshot of <a href="https://clover.coex.tech">clover.coex.tech</a>)</li>
<li><a href="" id="wvs">View image topics</a> (<code>web_video_server</code>)</li>
<li><a href="" id="butterfly">Open web terminal</a> (<code>Butterfly</code>)</li>
<li><a href="viz.html">View 3D visualization</a> (<code>ros3djs</code>)</li>
@@ -12,8 +12,8 @@
<script src="js/roslib.js"></script>
<script type="text/javascript">
document.querySelector("#wvs").href = location.origin + ':8080';
document.querySelector("#butterfly").href = location.origin + ':57575';
document.querySelector("#wvs").href = location.protocol + '//' + location.hostname + ':8080';
document.querySelector("#butterfly").href = location.protocol + '//' + location.hostname + ':57575';
// Determine image version
var ros = new ROSLIB.Ros({ url: 'ws://' + location.hostname + ':9090' });

59075
clover/www/js/ros3d.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

0
docs/CATKIN_IGNORE Normal file
View File

BIN
docs/assets/aruco.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

BIN
docs/assets/clover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

BIN
docs/assets/clover42.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

BIN
docs/assets/js-ros.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

BIN
docs/assets/p4df2_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
docs/assets/p4df2_2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
docs/assets/p4df2_3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

BIN
docs/assets/p4df2_4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

1
docs/assets/px4.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

134
docs/assets/ros.svg Normal file
View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg2"
version="1.1"
viewBox="0 0 387 103"
height="103pt"
width="387pt">
<metadata
id="metadata58">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4">
<clipPath
id="clip1">
<path
id="path7"
d="M 0.0585938 2 L 22 2 L 22 25 L 0.0585938 25 Z M 0.0585938 2 " />
</clipPath>
<clipPath
id="clip2">
<path
id="path10"
d="M 0.0585938 40 L 22 40 L 22 64 L 0.0585938 64 Z M 0.0585938 40 " />
</clipPath>
<clipPath
id="clip3">
<path
id="path13"
d="M 0.0585938 79 L 22 79 L 22 102 L 0.0585938 102 Z M 0.0585938 79 " />
</clipPath>
<clipPath
id="clip4">
<path
id="path16"
d="M 220 0.894531 L 302 0.894531 L 302 102.941406 L 220 102.941406 Z M 220 0.894531 " />
</clipPath>
<clipPath
id="clip5">
<path
id="path19"
d="M 316 0.894531 L 386.050781 0.894531 L 386.050781 102.941406 L 316 102.941406 Z M 316 0.894531 " />
</clipPath>
</defs>
<g
id="surface839">
<g
id="g22"
clip-rule="nonzero"
clip-path="url(#clip1)">
<path
id="path24"
d="M 21.839844 13.492188 C 21.839844 19.722656 16.949219 24.777344 10.921875 24.777344 C 4.890625 24.777344 0 19.722656 0 13.492188 C 0 7.257812 4.890625 2.207031 10.921875 2.207031 C 16.949219 2.207031 21.839844 7.257812 21.839844 13.492188 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
</g>
<g
id="g26"
clip-rule="nonzero"
clip-path="url(#clip2)">
<path
id="path28"
d="M 21.839844 51.949219 C 21.839844 58.179688 16.949219 63.234375 10.921875 63.234375 C 4.890625 63.234375 0 58.179688 0 51.949219 C 0 45.714844 4.890625 40.664062 10.921875 40.664062 C 16.949219 40.664062 21.839844 45.714844 21.839844 51.949219 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
</g>
<g
id="g30"
clip-rule="nonzero"
clip-path="url(#clip3)">
<path
id="path32"
d="M 21.839844 90.40625 C 21.839844 96.636719 16.949219 101.691406 10.921875 101.691406 C 4.890625 101.691406 0 96.636719 0 90.40625 C 0 84.175781 4.890625 79.121094 10.921875 79.121094 C 16.949219 79.121094 21.839844 84.175781 21.839844 90.40625 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
</g>
<path
id="path34"
d="M 59.945312 51.949219 C 59.945312 58.179688 55.058594 63.234375 49.027344 63.234375 C 42.996094 63.234375 38.105469 58.179688 38.105469 51.949219 C 38.105469 45.714844 42.996094 40.664062 49.027344 40.664062 C 55.058594 40.664062 59.945312 45.714844 59.945312 51.949219 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
<path
id="path36"
d="M 59.945312 13.492188 C 59.945312 19.722656 55.058594 24.777344 49.027344 24.777344 C 42.996094 24.777344 38.105469 19.722656 38.105469 13.492188 C 38.105469 7.257812 42.996094 2.207031 49.027344 2.207031 C 55.058594 2.207031 59.945312 7.257812 59.945312 13.492188 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
<path
id="path38"
d="M 98.054688 51.949219 C 98.054688 58.179688 93.164062 63.234375 87.132812 63.234375 C 81.101562 63.234375 76.214844 58.179688 76.214844 51.949219 C 76.214844 45.714844 81.101562 40.664062 87.132812 40.664062 C 93.164062 40.664062 98.054688 45.714844 98.054688 51.949219 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
<path
id="path40"
d="M 98.054688 13.492188 C 98.054688 19.722656 93.164062 24.777344 87.132812 24.777344 C 81.101562 24.777344 76.214844 19.722656 76.214844 13.492188 C 76.214844 7.257812 81.101562 2.207031 87.132812 2.207031 C 93.164062 2.207031 98.054688 7.257812 98.054688 13.492188 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
<path
id="path42"
d="M 98.054688 90.40625 C 98.054688 96.636719 93.164062 101.691406 87.132812 101.691406 C 81.101562 101.691406 76.214844 96.636719 76.214844 90.40625 C 76.214844 84.175781 81.101562 79.121094 87.132812 79.121094 C 93.164062 79.121094 98.054688 84.175781 98.054688 90.40625 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
<path
id="path44"
d="M 59.945312 90.40625 C 59.945312 96.636719 55.058594 101.691406 49.027344 101.691406 C 42.996094 101.691406 38.105469 96.636719 38.105469 90.40625 C 38.105469 84.175781 42.996094 79.121094 49.027344 79.121094 C 55.058594 79.121094 59.945312 84.175781 59.945312 90.40625 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
<path
id="path46"
d="M 171.613281 16.453125 L 143.695312 16.453125 L 143.695312 48.269531 L 171.613281 48.269531 C 181.191406 48.269531 187.894531 43.179688 187.894531 32.433594 C 187.894531 22.109375 181.328125 16.453125 171.613281 16.453125 Z M 181.328125 61 L 200.894531 101.445312 L 184.339844 101.445312 L 165.316406 62.273438 L 143.695312 62.273438 L 143.695312 101.445312 L 129.601562 101.445312 L 129.601562 2.449219 L 171.613281 2.449219 C 188.308594 2.449219 202.402344 11.644531 202.402344 32.007812 C 202.402344 47.847656 194.328125 57.605469 181.328125 61 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
<g
id="g48"
clip-rule="nonzero"
clip-path="url(#clip4)">
<path
id="path50"
d="M 260.5625 15.746094 C 243.867188 15.746094 234.699219 29.746094 234.699219 51.949219 C 234.699219 74.152344 243.867188 88.152344 260.5625 88.152344 C 277.394531 88.152344 286.5625 74.152344 286.5625 51.949219 C 286.5625 29.746094 277.394531 15.746094 260.5625 15.746094 Z M 260.5625 103 C 235.796875 103 220.058594 81.929688 220.058594 51.949219 C 220.058594 21.96875 235.796875 0.894531 260.5625 0.894531 C 285.46875 0.894531 301.203125 21.96875 301.203125 51.949219 C 301.203125 81.929688 285.46875 103 260.5625 103 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
</g>
<g
id="g52"
clip-rule="nonzero"
clip-path="url(#clip5)">
<path
id="path54"
d="M 350.609375 103 C 336.648438 103 324.609375 96.777344 316.535156 87.019531 L 326.796875 76.695312 C 333.230469 83.910156 342.671875 88.433594 351.703125 88.433594 C 365.113281 88.433594 371.542969 83.625 371.542969 74.007812 C 371.542969 66.371094 365.933594 62.554688 349.921875 57.605469 C 329.671875 51.382812 319.957031 46.148438 319.957031 28.472656 C 319.957031 11.359375 333.914062 0.894531 351.566406 0.894531 C 364.566406 0.894531 374.417969 5.847656 382.902344 14.332031 L 372.777344 24.9375 C 366.753906 18.574219 359.914062 15.460938 350.472656 15.460938 C 339.25 15.460938 334.460938 21.117188 334.460938 27.765625 C 334.460938 34.695312 338.839844 38.089844 355.398438 43.179688 C 374.28125 49.121094 386.050781 55.34375 386.050781 73.019531 C 386.050781 90.839844 375.101562 103 350.609375 103 "
style=" stroke:none;fill-rule:nonzero;fill:rgb(13.618469%,18.034363%,29.017639%);fill-opacity:1;" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.9 KiB

69
docs/assets/rpi.svg Normal file
View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 656.47998 825.76001"
height="825.76001"
width="656.47998"
xml:space="preserve"
id="svg2"
version="1.1"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs6" /><g
transform="matrix(1.3333333,0,0,-1.3333333,0,825.76)"
id="g10"><g
transform="scale(0.1)"
id="g12"><path
id="path14"
style="fill:#040606;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 1332.8,6193.06 c -31.79,-0.96 -66.04,-12.52 -104.87,-42.73 -95.16,36.15 -187.4,48.71 -269.879,-24.86 -127.371,16.28 -168.774,-17.31 -200.141,-56.51 -27.953,0.57 -209.25,28.3 -292.375,-93.84 -208.914,24.34 -274.953,-121.05 -200.14,-256.61 -42.661,-65.07 -86.86,-129.35 12.902,-253.37 -35.285,-69.08 -13.41,-144.01 69.746,-234.72 -21.949,-97.11 21.199,-165.62 98.555,-219.02 -14.481,-132.88 123.715,-210.15 164.984,-237.69 15.836,-77.42 48.871,-150.5 206.723,-190.89 26.019,-115.41 120.89,-135.33 212.755,-159.55 C 727.426,4249.43 467.074,4020.7 468.832,3459.5 L 424.34,3381.35 C 76.2109,3172.81 -237.016,2502.55 252.781,1957.78 284.773,1787.23 338.43,1664.75 386.207,1529.2 457.668,982.91 924.004,727.121 1047.01,696.859 1227.25,561.641 1419.2,433.332 1678.97,343.441 1923.85,94.6914 2189.13,-0.121094 2455.89,0.03125 c 3.91,0 7.89,-0.0507813 11.8,0 266.75,-0.160156 532.05,94.64065 776.91,343.40975 259.78,89.891 451.74,218.2 631.98,353.418 123,30.262 589.33,286.051 660.79,832.341 47.77,135.55 101.44,258.03 133.42,428.58 489.81,544.82 176.59,1215.13 -171.57,1423.67 l -44.53,78.13 c 1.76,561.15 -258.63,789.88 -562.24,963.77 91.87,24.21 186.73,44.14 212.76,159.53 157.86,40.42 190.88,113.49 206.71,190.91 41.28,27.52 179.47,104.8 164.99,237.7 77.36,53.39 120.5,121.91 98.57,219.01 83.14,90.7 105.03,165.63 69.73,234.71 99.8,123.99 55.51,188.26 12.91,253.33 74.75,135.56 8.79,280.94 -200.21,256.59 -83.11,122.15 -264.34,94.41 -292.36,93.85 -31.37,39.2 -72.74,72.79 -200.12,56.51 -82.48,73.57 -174.73,61.01 -269.87,24.87 -112.99,87.81 -187.74,17.43 -273.13,-9.18 -136.77,44.02 -168.05,-16.29 -235.24,-40.84 -149.18,31.05 -194.51,-36.54 -266.03,-107.9 l -83.19,1.62 c -224.98,-130.58 -336.74,-396.52 -376.36,-533.23 -39.64,136.74 -151.17,402.67 -376.1,533.23 l -83.18,-1.62 c -71.6,71.36 -116.94,138.95 -266.1,107.9 -67.2,24.55 -98.38,84.86 -235.25,40.84 -56.05,17.46 -107.61,53.77 -168.29,51.92 l 0.11,-0.04" /><path
id="path16"
style="fill:#63c54d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 889.32,5618.51 c 596.92,-303.11 943.94,-548.33 1134.04,-757.16 -97.35,-384.36 -605.24,-401.9 -790.94,-391.11 38.01,17.43 69.74,38.32 80.99,70.4 -46.59,32.6 -211.83,3.44 -327.176,67.27 44.296,9.05 65.036,17.84 85.746,50.06 -108.968,34.23 -226.367,63.74 -295.402,120.46 37.266,-0.47 72.035,-8.21 120.707,25.03 -97.629,51.82 -201.781,92.87 -282.707,172.08 50.457,1.2 104.875,0.5 120.695,18.77 -89.335,54.51 -164.726,115.15 -227.128,181.47 70.644,-8.4 100.464,-1.17 117.546,10.95 -67.539,68.12 -153.023,125.66 -193.773,209.63 52.445,-17.81 100.422,-24.63 135.016,1.56 -22.957,51.01 -121.286,81.08 -177.903,200.24 55.223,-5.26 113.774,-11.85 125.489,0 -25.637,102.83 -69.598,160.66 -112.727,220.55 118.152,1.72 297.172,-0.46 289.066,9.39 l -73.05,73.53 c 115.406,30.6 233.496,-4.92 319.238,-31.3 38.488,29.92 -0.684,67.76 -47.652,106.4 98.089,-12.92 186.715,-35.13 266.815,-65.73 42.82,38.08 -27.77,76.15 -61.94,114.21 151.54,-28.32 215.75,-68.1 279.54,-107.95 46.3,43.71 2.65,80.85 -28.59,118.89 114.26,-41.68 173.12,-95.49 235.07,-148.61 21.01,27.92 53.37,48.39 14.3,115.77 81.11,-46.06 142.2,-100.33 187.42,-161.13 50.19,31.47 29.9,74.53 30.17,114.2 84.3,-67.56 137.81,-139.44 203.31,-209.63 13.18,9.45 24.74,41.55 34.93,92.3 201.12,-192.2 485.32,-676.3 73.06,-868.24 -350.87,285.03 -769.91,492.21 -1234.281,647.62 l 0.121,0.08" /><path
id="path18"
style="fill:#63c54d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 4050.89,5618.51 c -596.87,-303.16 -943.87,-548.29 -1133.98,-757.16 97.36,-384.36 605.26,-401.9 790.96,-391.11 -38.03,17.43 -69.74,38.32 -80.99,70.4 46.6,32.6 211.83,3.44 327.18,67.27 -44.3,9.05 -65.04,17.84 -85.76,50.06 108.99,34.23 226.38,63.74 295.42,120.46 -37.26,-0.47 -72.06,-8.21 -120.71,25.03 97.61,51.82 201.78,92.87 282.7,172.08 -50.47,1.2 -104.87,0.5 -120.71,18.77 89.37,54.51 164.75,115.15 227.14,181.47 -70.63,-8.4 -100.45,-1.17 -117.54,10.95 67.55,68.12 153.02,125.66 193.78,209.63 -52.44,-17.81 -100.42,-24.63 -135.01,1.56 22.95,51.01 121.27,81.08 177.88,200.24 -55.21,-5.26 -113.75,-11.85 -125.47,0 25.67,102.88 69.65,160.7 112.76,220.6 -118.16,1.72 -297.16,-0.46 -289.08,9.38 l 73.09,73.52 c -115.43,30.61 -233.52,-4.9 -319.26,-31.28 -38.48,29.92 0.68,67.76 47.64,106.37 -98.08,-12.89 -186.71,-35.1 -266.82,-65.7 -42.8,38.06 27.79,76.13 61.94,114.2 -151.53,-28.32 -215.73,-68.11 -279.54,-107.94 -46.29,43.7 -2.63,80.85 28.6,118.88 -114.26,-41.67 -173.12,-95.48 -235.06,-148.6 -21.01,27.92 -53.36,48.38 -14.3,115.77 -81.13,-46.07 -142.21,-100.34 -187.41,-161.14 -50.2,31.48 -29.91,74.53 -30.19,114.19 -84.3,-67.54 -137.82,-139.43 -203.29,-209.62 -13.19,9.46 -24.74,41.56 -34.95,92.3 -201.13,-192.2 -485.34,-676.3 -73.05,-868.24 350.68,285.09 769.69,492.26 1234.1,647.66 h -0.07" /><path
id="path20"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 3192,1704.72 c 2.08,-358.64 -316.36,-650.93 -711.23,-652.82 -394.87,-1.89 -716.68,287.32 -718.76,645.98 0,2.28 0,4.56 0,6.84 -2.07,358.66 316.35,650.95 711.24,652.83 394.87,1.89 716.68,-287.31 718.75,-645.98 0.01,-2.29 0.01,-4.56 0,-6.85" /><path
id="path22"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 2077.17,3559.87 c 296.27,-191.17 349.68,-624.54 119.3,-967.92 -230.38,-343.39 -657.31,-466.8 -953.56,-275.62 v 0 c -296.265,191.19 -349.68,624.56 -119.29,967.96 230.38,343.38 657.3,466.78 953.55,275.58 v 0" /><path
id="path24"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 2876.82,3594.49 c -296.27,-191.18 -349.67,-624.56 -119.29,-967.93 230.39,-343.39 657.3,-466.8 953.56,-275.61 v 0 c 296.27,191.18 349.68,624.55 119.3,967.95 -230.38,343.39 -657.3,466.78 -953.57,275.59 v 0" /><path
id="path26"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 614.797,3245.31 C 934.641,3329.76 722.777,1941.9 462.535,2055.77 176.246,2282.58 84.0352,2946.78 614.797,3245.31" /><path
id="path28"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 4311.21,3262.62 c -319.88,84.42 -107.98,-1303.48 152.29,-1189.61 286.27,226.82 378.47,891.08 -152.29,1189.61 v 0" /><path
id="path30"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 3238.44,4298.12 c 551.99,91.81 1011.31,-231.21 992.77,-820.8 -18.15,-226.03 -1196.15,787.15 -992.77,820.8" /><path
id="path32"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 1713.29,4315.43 c -552.04,91.81 -1011.313,-231.29 -992.77,-820.82 18.136,-226.02 1196.14,787.16 992.77,820.82" /><path
id="path34"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 2473.78,4452.92 c -329.46,8.44 -645.64,-240.85 -646.41,-385.43 -0.92,-175.69 260.48,-355.58 648.65,-360.15 396.41,-2.79 649.34,143.99 650.62,325.31 1.46,205.43 -360.52,423.45 -652.86,420.29 v -0.02" /><path
id="path36"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 2499.23,850.172 c 287.23,12.359 672.67,-91.121 673.43,-228.391 4.77,-133.301 -349.56,-434.48 -692.48,-428.672 -355.16,-15.078 -703.39,286.551 -698.83,391.11 -5.32,153.301 432.44,272.98 717.88,265.953 v 0" /><path
id="path38"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 1436.19,1663.74 c 204.49,-242.69 297.72,-669.049 127.07,-794.72 -161.47,-95.961 -553.57,-56.45 -832.276,337.92 -187.925,330.88 -163.722,667.63 -31.746,766.53 197.344,118.42 502.252,-41.52 736.952,-309.73 v 0" /><path
id="path40"
style="fill:#c51850;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 3495.16,1740.65 c -221.27,-255.27 -344.49,-720.88 -183.07,-870.83 154.33,-116.488 568.64,-100.199 874.69,318.05 222.21,280.91 147.75,750.07 20.83,874.64 -188.58,143.66 -459.26,-40.19 -712.45,-321.78 v -0.08" /><path
id="path42"
style="fill:#171818;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 4594.78,4119.88 c -150.79,0 -273.01,122.19 -273.01,273.02 0,150.91 122.22,273.01 273.01,273.01 150.78,0 273.01,-122.1 273.01,-273.01 0,-150.83 -122.23,-273.02 -273.01,-273.02 z m 0,600.67 c -180.97,0 -327.6,-146.68 -327.6,-327.65 0,-180.88 146.63,-327.56 327.6,-327.56 180.96,0 327.6,146.68 327.6,327.56 0,180.97 -146.64,327.65 -327.6,327.65" /><path
id="path44"
style="fill:#171818;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 4533.92,4413.81 h 84.36 c 34.39,0 52.99,14.79 52.99,50.12 0,33.72 -18.6,48.51 -52.99,48.51 h -84.36 z m -77.02,158.46 h 188.88 c 62.84,0 102.55,-43.62 102.55,-96.47 0,-41.36 -16.67,-72.25 -55.44,-87.99 v -0.94 c 37.78,-9.8 48.52,-46.54 51.02,-81.96 1.46,-22.05 0.98,-63.21 14.74,-82.91 h -77.01 c -9.37,22.15 -8.39,55.87 -12.3,83.94 -5.37,36.83 -19.59,52.95 -58.36,52.95 h -77.06 V 4222 h -77.02 v 350.27" /></g></g></svg>

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
docs/assets/simulator.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

BIN
docs/assets/web-gcs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@@ -40,7 +40,7 @@ section ul li:before {
margin-bottom: 0.85em;
}
/* Main Clever image */
/* Main Clover 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 Clever 3 drone that's capable of autonomous flight and wrote a flight program.
We provided a Clover 3 drone that's capable of autonomous flight and wrote a flight program.
To make it all work we conducted many tests, made changes in the drone's design and tuned the drone properly.

View File

@@ -1,12 +1,12 @@
# COEX Clever
# COEX Clover
<img class="center bigclever zoom" src="../assets/clever4-front-white-large.png" width="80%" alt="COEX Clever 4">
<img class="center bigclever zoom" src="../assets/clever4-front-white-large.png" width="80%" alt="COEX Clover 4">
CLEVER (Russian: *"Клевер"*, meaning *"Clover"*) is an educational kit of a programmable quadcopter that consists of popular open source components, and a set of necessary documentation and libraries for working with it.
**Clover** is an educational kit of a programmable quadcopter that consists of popular open source components, and a set of necessary documentation and libraries for working with it.
The kit includes a Pixhawk/Pixracer flight controller with the PX4 flight stack, a [Raspberry Pi 3](raspberry.md) as a controlling onboard computer, and a [camera module](camera.md) for performing flights with the use of computer vision, as well as a set of various sensors and other peripherals.
The kit includes a Pixhawk/Pixracer flight controller with the PX4 flight stack, a [Raspberry Pi 4](raspberry.md) as a controlling onboard computer, and a [camera module](camera.md) for performing flights with the use of computer vision, as well as a set of various sensors and other peripherals.
The Clever platform contains a [pre-configured image for Raspberry Pi](image.md) with the full set of required software for working with peripheral devices and [programming autonomous flights](simple_offboard.md). The source code of the platform and of the documentation is open and [available on GitHub](https://github.com/CopterExpress/clever).
The Clover platform contains a [pre-configured image for Raspberry Pi](image.md) with the full set of required software for working with peripheral devices and [programming autonomous flights](simple_offboard.md). The source code of the platform and of the documentation is open and [available on GitHub](https://github.com/CopterExpress/clover).
If you have studied the documentation but have not found an answer to your question, join our support chat and our specialists will be happy to answer you: [@COEXHelpdesk](tg://resolve?domain=COEXHelpdesk).

View File

@@ -4,13 +4,14 @@
* [Glossary](gloss.md)
* [Safety tips](safety.md)
* Assembly
* [Clever 4 assembly](assemble_4.md)
* [Clever 3 assembly](assemble_3.md)
* [Clever 2 assembly](assemble_2.md)
* [Clover 4 assembly](assemble_4.md)
* [Clover 3 assembly](assemble_3.md)
* [Clover 2 assembly](assemble_2.md)
* Configuration
* [Initial setup](setup.md)
* [Sensor calibration](calibration.md)
* [RC setup](radio.md)
* [Using FS-A8S](rc_flysky_a8s.md)
* [Flight modes](modes.md)
* [Power setup](power.md)
* [Failsafe configuration](failsafe.md)
@@ -41,7 +42,8 @@
* [Interfacing with a sonar](sonar.md)
* [Computer vision basics](camera.md)
* [Using rviz and rqt](rviz.md)
* [Software autorun](autolaunch.md)
* [Software autorun](autolaunch.md)
* [Using JavaScript](javascript.md)
* [ROS](ros.md)
* [MAVROS](mavros.md)
* Supplementary materials
@@ -52,8 +54,9 @@
* [PID Setup](calibratePID.md)
* [Model files for parts](models.md)
* [ROS Melodic installation](ros-install.md)
* [Camera calibration](camera_calibration.md)
* [Quadcopter control with 4G communication](4g.md)
* [Clever and Jetson Nano](jetson_nano.md)
* [Clover and Jetson Nano](jetson_nano.md)
* [Remote control app](rc.md)
* [Wi-Fi Configuration](network.md)
* [UART settings](uart.md)
@@ -64,18 +67,20 @@
* [Multimeter usage](test_connection.md)
* [RC Troubleshooting](radioerrors.md)
* [Flashing ESCs](esc_firmware.md)
* [Camera calibration](camera_calibration.md)
* [Interfacing with Arduino](arduino.md)
* [Connecting GPS](gps.md)
* [Working with IR sensors on Raspberry Pi 3](ir_sensors.md)
* [FPV Setup](fpv.md)
* [Trainer mode](trainer_mode.md)
* [Tinning](tinning.md)
* [Types of power connectors](connectortypes.md)
* [Connecting 4 in 1 ESCs](4in1.md)
* [Soldering safety](tb.md)
* [LED strip (legacy)](leds_old.md)
* [Contribution Guidelines](contributing.md)
* Clever-based projects
* [Migration to v0.20](migrate20.md)
* Clover-based projects
* [Drone show](clever-show.md)
* [Copter spheric guard](shield.md)
* [Face recognition system](face_recognition.md)
* [Android RC app](android.md)
@@ -84,3 +89,5 @@
* [Copter Hack 2019](copterhack2019.md)
* [Copter Hack 2018](copterhack2018.md)
* [Copter Hack 2017](copterhack2017.md)
* [Robocross-2019](robocross2019.md)
* [Camera calibration (legacy)](camera_calib.md)

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/clever/tree/master/apps/android/app/src/main/assets), you can find *HTML*, *CSS* and *JavaScript* files, which make up the web page to be used for controlling the copter. To have this page displayed in our application, do the following:
Let's start with the simplest thing — the appearance of our application. At [**GitHub**](https://github.com/CopterExpress/clover/tree/master/apps/android/app/src/main/assets), you can find *HTML*, *CSS* and *JavaScript* files, which make up the web page to be used for controlling the copter. To have this page displayed in our application, do the following:
1. Create folder **assets** in the main folder of the app named **app**
2. Add to it all files from [here](https://github.com/CopterExpress/clever/tree/master/apps/android/app/src/main/assets)
2. Add to it all files from [here](https://github.com/CopterExpress/clover/tree/master/apps/android/app/src/main/assets)
If you reached this stage, you already have the web page you want, congratulations! Now we have to display it somehow in the app. To do this, in class *activity* in method **onCreate**, write the following code:

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 Clever and connected via a USB port.
Arudino is to be installed on Clover and connected via a USB port.
## Configuring Arduino IDE
@@ -21,19 +21,19 @@ The obtained folder `ros_lib` is to be copied to `<sketches folder>/libraries` o
To run the program on Arduino once, you can use command:
```(bash)
roslaunch clever arduino.launch
roslaunch clover arduino.launch
```
To start the link with Arduino at the startup automatically, set argument `arudino` in the Clever launch file (`~/catkin_ws/src/clever/clever/launch/clever.launch`):
To start the link with Arduino at the startup automatically, set argument `arudino` in the Clover launch file (`~/catkin_ws/src/clover/clover/launch/clover.launch`):
```xml
<arg name="arduino" default="true"/>
```
After the launch file is edited, restart package `clever`:
After the launch file is edited, restart the `clover` service:
```(bash)
sudo systemctl restart clever
sudo systemctl restart clover
```
## Delays
@@ -59,7 +59,7 @@ for(int i=0; i<8; i++) {
}
```
## Working with Clever
## Working with Clover
The set of services and topics is similar to the regular set in [simple_offboard](simple_offboard.md) and [mavros](mavros.md).
@@ -69,11 +69,11 @@ An example of a program that controls the copter by position using the `navigate
// Connecting libraries for working with rosseral
#include <ros.h>
// Connecting Clever and MAVROS package message header files
#include <clever/Navigate.h>
// Connecting Clover and MAVROS package message header files
#include <clover/Navigate.h>
#include <mavros_msgs/SetMode.h>
using namespace clever;
using namespace clover;
using namespace mavros_msgs;
ros::NodeHandle nh;
@@ -174,7 +174,7 @@ With Arduino, you can use the [`get_telemetry` service](simple_offboard.md). To
// ...
#include <clever/GetTelemetry.h>
#include <clover/GetTelemetry.h>
// ...

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/clever/blob/v0.15.1/docs/ru/aruco.md).
> **Note** The following applies to [image versions](image.md) **0.16** and up. Older documentation is still available for [for version **0.15.1**](https://github.com/CopterExpress/clover/blob/v0.15.1/docs/en/aruco.md).
[ArUco markers](https://docs.opencv.org/3.2.0/d5/dae/tutorial_aruco_detection.html) are commonly used for vision-based position estimation.
@@ -12,13 +12,13 @@ Examples of ArUco markers:
For rapid generation of markers for printing, you may use an online tool: http://chev.me/arucogen/.
[Clever Raspberry Pi image](image.md) contains a pre-installed `aruco_pose` ROS package, which can be used for marker detection.
[Clover Raspberry Pi image](image.md) contains a pre-installed `aruco_pose` ROS package, which can be used for marker detection.
## Modes of operation
There are several preconfigured modes of operation for ArUco markers on the Clever drone:
There are several preconfigured modes of operation for ArUco markers on the Clover drone:
* [single marker detection and navigation](aruco_marker.md);
* [map-based navigation](aruco_map.md).
> **Info** Additional documentation for the `aruco_pose` ROS package is available [on GitHub](https://github.com/CopterExpress/clever/blob/master/aruco_pose/README.md).
> **Info** Additional documentation for the `aruco_pose` ROS package is available [on GitHub](https://github.com/CopterExpress/clover/blob/master/aruco_pose/README.md).

View File

@@ -10,13 +10,13 @@
## Configuration
Set the `aruco` argument in `~/catkin_ws/src/clever/clever/launch/clever.launch` to `true`:
Set the `aruco` argument in `~/catkin_ws/src/clover/clover/launch/clover.launch` to `true`:
```xml
<arg name="aruco" default="true"/>
```
In order to enable map detection set `aruco_map` and `aruco_detect` arguments to `true` in `~/catkin_ws/src/clever/clever/launch/aruco.launch`:
In order to enable map detection set `aruco_map` and `aruco_detect` arguments to `true` in `~/catkin_ws/src/clover/clover/launch/aruco.launch`:
```xml
<arg name="aruco_detect" default="true"/>
@@ -45,12 +45,12 @@ Map path is defined in the `map` parameter:
<param name="map" value="$(find aruco_pose)/map/map.txt"/>
```
Some map examples are provided in [`~/catkin_ws/src/clever/aruco_pose/map`](https://github.com/CopterExpress/clever/tree/master/aruco_pose/map).
Some map examples are provided in [`~/catkin_ws/src/clover/aruco_pose/map`](https://github.com/CopterExpress/clover/tree/master/aruco_pose/map).
Grid maps may be generated using the `genmap.py` script:
```bash
rosrun aruco_pose genmap.py length x y dist_x dist_y first > ~/catkin_ws/src/clever/aruco_pose/map/test_map.txt
rosrun aruco_pose genmap.py length x y dist_x dist_y first > ~/catkin_ws/src/clover/aruco_pose/map/test_map.txt
```
`length` is the size of each marker, `x` is the marker count along the *x* axis, `y` is the marker count along the *y* axis, `dist_x` is the distance between the centers of adjacent markers along the *x* axis, `dist_y` is the distance between the centers of the *y* axis, `first` is the ID of the first marker (top left marker, unless `--bottom-left` is specified), `test_map.txt` is the name of the generated map file. The optional `--bottom-left` parameter changes the numbering of markers, making the bottom left marker the first one.
@@ -58,7 +58,7 @@ rosrun aruco_pose genmap.py length x y dist_x dist_y first > ~/catkin_ws/src/cle
Usage example:
```bash
rosrun aruco_pose genmap.py 0.33 2 4 1 1 0 > ~/catkin_ws/src/clever/aruco_pose/map/test_map.txt
rosrun aruco_pose genmap.py 0.33 2 4 1 1 0 > ~/catkin_ws/src/clover/aruco_pose/map/test_map.txt
```
Additional information on the utility can be obtained using `-h` key: `rosrun aruco_pose genmap.py -h`.
@@ -91,13 +91,6 @@ The marker map adheres to the [ROS coordinate system convention](http://www.ros.
In order to enable vision position estimation you should use the following [PX4 parameters](px4_parameters.md).
If you're using **EKF2** estimator (`SYS_MC_EST_GROUP` parameter is set to `ekf2`), make sure the following is set:
* `EKF2_AID_MASK` should have `vision position fusion` and `vision yaw fusion` flags set.
* Vision angle observations noise: `EKF2_EVA_NOISE` = 0.1 rad.
* Vision position observations noise: `EKF2_EVP_NOISE` = 0.1 m.
* `EKF2_EV_DELAY` = 0.
If you're using **LPE** (`SYS_MC_EST_GROUP` parameter is set to `local_position_estimator,attitude_estimator_q`):
* `LPE_FUSION` should have `vision position` and `land detector` flags set. We suggest unsetting the `baro` flag for indoor flights.
@@ -108,6 +101,13 @@ If you're using **LPE** (`SYS_MC_EST_GROUP` parameter is set to `local_position_
<!-- * Compass should not be fused: `ATT_W_MAG` = 0 -->
If you're using **EKF2** estimator (`SYS_MC_EST_GROUP` parameter is set to `ekf2`), make sure the following is set:
* `EKF2_AID_MASK` should have `vision position fusion` and `vision yaw fusion` flags set.
* Vision angle observations noise: `EKF2_EVA_NOISE` = 0.1 rad.
* Vision position observations noise: `EKF2_EVP_NOISE` = 0.1 m.
* `EKF2_EV_DELAY` = 0.
> **Hint** We recommend using **LPE** for marker-based navigation.
You may use [the `selfcheck.py` utility](selfcheck.md) to check your settings.
@@ -152,7 +152,7 @@ If the drone's altitude is not stable, try increasing the `MPC_Z_VEL_P` paramete
In order to navigate using markers on the ceiling, mount the onboard camera so that it points up and [adjust the camera frame accordingly](camera_setup.md).
You should also set the `known_tilt` parameter to `map_flipped` in both `aruco_detect` and `aruco_map` sections of `~/catkin_ws/src/clever/clever/launch/aruco.launch`:
You should also set the `known_tilt` parameter to `map_flipped` in both `aruco_detect` and `aruco_map` sections of `~/catkin_ws/src/clover/clover/launch/aruco.launch`:
```xml
<param name="known_tilt" value="map_flipped"/>

View File

@@ -10,13 +10,13 @@ Using this module along with [map-based navigation](aruco_map.md) is also possib
## Setup
Set the `aruco` argument in `~/catkin_ws/src/clever/clever/launch/clever.launch` to `true`:
Set the `aruco` argument in `~/catkin_ws/src/clover/clover/launch/clover.launch` to `true`:
```xml
<arg name="aruco" default="true"/>
```
For enabling detection set the `aruco_detect` argument in `~/catkin_ws/src/clever/clever/launch/aruco.launch` to `true`:
For enabling detection set the `aruco_detect` argument in `~/catkin_ws/src/clover/clover/launch/aruco.launch` to `true`:
```xml
<arg name="aruco_detect" default="true"/>

View File

@@ -1,7 +1,7 @@
Clever 2 construction kit assembly instruction
Clover 2 construction kit assembly instruction
============================================
![Clever](../assets/clever2.jpg)
![Clover](../assets/clever2.jpg)
## The constructor kit contents
@@ -78,7 +78,7 @@ Clever 2 construction kit assembly instruction
## Additional equipment
### This equipment is not part of the Clever 2 constructor kit, but it is required for the assembly process
### This equipment is not part of the Clover 2 constructor kit, but it is required for the assembly process
1. Soldering iron
2. Colophony/ Flux (neutral)

View File

@@ -1,8 +1,8 @@
# Assembly of Clever 3
# Assembly of Clover 3
This manual discusses the assembly of the COEX Clever 3 kit with a 4 in 1 EDC circuit-board.
This manual discusses the assembly of the COEX Clover 3 kit with a 4 in 1 EDC circuit-board.
![Clever 3](../assets/clever3_main.jpg)
![Clover 3](../assets/clever3_main.jpg)
> **Caution** Before using soldering equipment, be sure to read the [safety precautions when soldering](tb.md).

View File

@@ -1,4 +1,4 @@
# Clever 4 assembly
# Clover 4 assembly
<img src="../assets/assembling_clever4/clover_assembly.png" width=900 class="zoom center">

View File

@@ -1,4 +1,6 @@
# Step-by-step guide on autonomous flight with Clever 4
# Step-by-step guide on autonomous flight with Clover 4
> **Note** The following applies to [image version](image.md) **0.20** and up. See [previous version of the article](https://github.com/CopterExpress/clover/blob/v0.19/docs/en/auto_setup.md) for older images.
This manual contains links to other articles in which each of the topics addressed is discussed in more detail. If you encounter difficulties while reading one of these articles, it is recommended that you return to this manual, since many operations here are described step by step and some unnecessary steps are skipped.
@@ -15,9 +17,9 @@ This manual contains links to other articles in which each of the topics address
- Connect to Wi-Fi and open the web interface ([this article](wifi.md)).
   After the first power-up, the network appears with a delay. You need to wait until the system is fully loaded. If the Clever network does not appear in the list of networks for a long time, reopen the window with the network selection. Then the list of networks will be updated.
   After the first power-up, the network appears with a delay. You need to wait until the system is fully loaded. If the Clover network does not appear in the list of networks for a long time, reopen the window with the network selection. Then the list of networks will be updated.
> **Hint** Now if you have connected to the Clever's Wi-Fi network, it is recommended to open the [local version of this guide](http://192.168.11.1/docs/ru/auto_setup.html), otherwise the links will not work.
> **Hint** Now if you have connected to the Clover's Wi-Fi network, it is recommended to open the [local version of this guide](http://192.168.11.1/docs/ru/auto_setup.html), otherwise the links will not work.
- Connect to Raspberry Pi via SSH.
@@ -47,7 +49,7 @@ This manual contains links to other articles in which each of the topics address
## Basic commands
You will need the basic Linux commands, as well as special Clever commands, to work efficiently in the system.
You will need the basic Linux commands, as well as special Clover commands, to work efficiently in the system.
Show list of files and folders:
@@ -55,10 +57,10 @@ Show list of files and folders:
ls
```
Go to certain directory by entering the path too it (catkin_ws/src/clever/clever/launch/):
Go to certain directory by entering the path too it (catkin_ws/src/clover/clover/launch/):
```bash
cd catkin_ws/src/clever/clever/launch/
cd catkin_ws/src/clover/clover/launch/
```
Go to home directory:
@@ -73,10 +75,10 @@ Open the file `file.py`:
nano file.py
```
Open the file clever.launch by entering the full path to it (it works even if you're in a different directory):
Open the file clover.launch by entering the full path to it (it works even if you're in a different directory):
```bash
nano ~/catkin_ws/src/clever/clever/launch/clever.launch
nano ~/catkin_ws/src/clover/clover/launch/clover.launch
```
Save file (press sequentially):
@@ -103,16 +105,16 @@ Raspberry Pi complete reboot:
sudo reboot
```
Reboot only Clever package:
Reboot only the `clover` service:
```bash
sudo systemctl restart clever
sudo systemctl restart clover
```
Perform selfcheck:
```bash
rosrun clever selfcheck.py
rosrun clover selfcheck.py
```
Stop a program:
@@ -127,10 +129,10 @@ Start a program `myprogram.py` using Python:
python myprogram.py
```
Journal of the events related to Clever package. Scroll the list by pressing Enter or Ctrl+V (scrolls faster):
Journal of the events related to `clover` package. Scroll the list by pressing Enter or Ctrl+V (scrolls faster):
```bash
journalctl -u clever
journalctl -u clover
```
Open the sudoers file with super user rights (this particular file doesn't open without sudo. You can use sudo to open other locked files or run programs that require super user rights):
@@ -141,45 +143,45 @@ sudo nano /etc/sudoers
## Setting Raspberry Pi for autonomous flight
Most of the parameters for autonomous flight are located in the following directory: `~/catkin_ws/src/clever/clever/launch/`.
Most of the parameters for autonomous flight are located in the following directory: `~/catkin_ws/src/clover/clover/launch/`.
- Enter the directory:
```bash
cd ~/catkin_ws/src/clever/clever/launch/
cd ~/catkin_ws/src/clover/clover/launch/
```
The `~` symbol stands for home directory of your user. If you are already in the directory, you can go with just the command:
```bash
cd catkin_ws/src/clever/clever/launch/
cd catkin_ws/src/clover/clover/launch/
```
> **Hint** Tab can automatically complete the names of files, folders or commands. You need to start entering the desired name and press Tab. If there are no conflicts, the name will be auto completed. For example, to quickly enter the path to the `catkin_ws/src/clever/clever/launch/` directory, after entering `cd`, you can start typing the following key combination:`c-Tab-s-Tab-c-Tab-c-Tab-l-Tab`. This way you can save a lot of time when writing a long command, and also avoid possible mistakes in writing the path.
> **Hint** Tab can automatically complete the names of files, folders or commands. You need to start entering the desired name and press Tab. If there are no conflicts, the name will be auto completed. For example, to quickly enter the path to the `catkin_ws/src/clover/clover/launch/` directory, after entering `cd`, you can start typing the following key combination:`c-Tab-s-Tab-c-Tab-c-Tab-l-Tab`. This way you can save a lot of time when writing a long command, and also avoid possible mistakes in writing the path.
- In this folder you need to configure three files:
- `clever.launch`
- `clover.launch`
- `aruco.launch`
- `main_camera.launch`
- Open the file `clever.launch`:
- Open the file `clover.launch`:
```bash
nano clever.launch
nano clover.launch
```
You must be in the directory in which the file is located. If you are in other directory, you can open the file by writing the full path to it:
```bash
nano ~/catkin_ws/src/clever/clever/launch/clever.launch
nano ~/catkin_ws/src/clover/clover/launch/clover.launch
```
If two users are editing a file at the same time, or if previously the file was closed incorrectly, nano will not display the file contents, it will ask for permission to display the file. To grant permission, press Y.
  If the content of a file is still empty, you may have entered the file name incorrectly. You need to pay attention to the extension. If you entered a wrong name or extension, nano will create a new empty file named this way, which is undesirable. Such file should be deleted.
- Find the following line in clever.launch file:
- Find the following line in clover.launch file:
```xml
<arg name="aruco" default="false"/>
@@ -222,7 +224,7 @@ Most of the parameters for autonomous flight are located in the following direct
- the marker map numbering is from the top left corner (key `--top-left`)
```bash
rosrun aruco_pose genmap.py 0.335 10 10 1 1 0 > ~/catkin_ws/src/clever/aruco_pose/map/map.txt --top-left
rosrun aruco_pose genmap.py 0.335 10 10 1 1 0 > ~/catkin_ws/src/clover/aruco_pose/map/map.txt --top-left
```
In most maps, numbering starts with a zero marker. Also, in most cases, numbering starts from the upper left corner, so when generating, it is very important to enter the key `--top-left`.
@@ -269,10 +271,10 @@ and replace map.txt with your map name.
Ctrl+x; y; Enter
```
- Restart the `clever` service:
- Restart the `clover` service:
```bash
sudo systemctl restart clever
sudo systemctl restart clover
```
## Setting the flight controller
@@ -289,7 +291,7 @@ and replace map.txt with your map name.
- Connect remotely to the flight controller through QGroundControl.
All the necessary settings for that are already set in Clever. Now you need to create a new connection in QGroundControl. Use the settings from [this article](gcs_bridge.md).
All the necessary settings for that are already set in Clover. Now you need to create a new connection in QGroundControl. Use the settings from [this article](gcs_bridge.md).
## Remote controller setup
@@ -297,14 +299,14 @@ and replace map.txt with your map name.
Set channel 5 to SwC switch; channel 5 to SwA switch. Or you can use any other switches you like.
## Clever selfcheck
## Clover selfcheck
Perform selfcheck when you have set up your drone or when you have faced problems. The selfcheck process is described in the article "[Automated self checks](selfcheck.md)"
- Run the command:
```bash
rosrun clever selfcheck.py
rosrun clover selfcheck.py
```
## Writing a program
@@ -368,7 +370,7 @@ The article "[Simple OFFBOARD](simple_offboard.md)" describes working with `simp
## Writing the program to the drone
The easiest way to send the program is to copy the content of the program, create a new file on the Clever command line and paste the program text into the file.
The easiest way to send the program is to copy the content of the program, create a new file in the command line and paste the program text into the file.
- To create the file `myprogram.py`, run the command:

View File

@@ -1,36 +1,38 @@
Software autorun
===
> **Note** In the image version **0.20** `clever` package and service was renamed to `clover`. See [previous version of the article](https://github.com/CopterExpress/clover/blob/v0.19/docs/en/autolaunch.md) for older images.
systemd
---
Main documentation: [https://wiki.archlinux.org/index.php/Systemd_(Russian)](https://wiki.archlinux.org/index.php/Systemd_(Russian)).
All automatically started Clever software is launched as a `clever.service` systemd service.
All automatically started Clover software is launched as a `clover.service` systemd service.
The service may be restarted by the `systemctl` command:
```(bash)
sudo systemctl restart clever
sudo systemctl restart clover
```
Text output of the software can be viewed using the `journalctl` command:
```(bash)
journalctl -u clever
journalctl -u clover
```
To run Clever software directly in the current console session, you can use the `roslaunch` command:
To run Clover software directly in the current console session, you can use the `roslaunch` command:
```(bash)
sudo systemctl restart clever
roslaunch clever clever.launch
sudo systemctl restart clover
roslaunch clover clover.launch
```
You can disable Clever software autolaunch using the `disable` command:
You can disable Clover software autolaunch using the `disable` command:
```(bash)
sudo systemctl disable clever
sudo systemctl disable clover
```
roslaunch
@@ -38,12 +40,12 @@ roslaunch
Main documentation: http://wiki.ros.org/roslaunch.
The list of nodes / programs declared for running is specified in file `/home/pi/catkin_ws/src/clever/clever/launch/clever.launch`.
The list of nodes / programs declared for running is specified in file `/home/pi/catkin_ws/src/clover/clover/launch/clover.launch`.
You can add your own node to the list of automatically launched ones. To do this, place your executable file (e.g. `my_program.py`) into folder `/home/pi/catkin_ws/src/clever/clever/src`. Then add the start of your node to `clever.launch`, for example:
You can add your own node to the list of automatically launched ones. To do this, place your executable file (e.g. `my_program.py`) into folder `/home/pi/catkin_ws/src/clover/clover/src`. Then add the start of your node to `clover.launch`, for example:
```xml
<node name="my_program" pkg="clever" type="my_program.py" output="screen"/>
<node name="my_program" pkg="clover" type="my_program.py" output="screen"/>
```
The started file must have *permission* to run:

View File

@@ -1,6 +1,8 @@
# Working with the camera
Make sure the camera is enabled in the `~/catkin_ws/src/clever/clever/launch/clever.launch` file:
> **Note** In the image version **0.20** `clever` package was renamed to `clover`. See [previous version of the article](https://github.com/CopterExpress/clover/blob/v0.19/docs/en/camera.md) for older images.
Make sure the camera is enabled in the `~/catkin_ws/src/clover/clover/launch/clover.launch` file:
```xml
<arg name="main_camera" default="true"/>
@@ -8,10 +10,10 @@ Make sure the camera is enabled in the `~/catkin_ws/src/clever/clever/launch/cle
Also make sure that [position and orientation of the camera](camera_setup.md) is correct.
The `clever` package must be restarted after the launch-file has been edited:
The `clover` service must be restarted after the launch-file has been edited:
```(bash)
sudo systemctl restart clever
sudo systemctl restart clover
```
You may use rqt or [web_video_server](web_video_server.md) to view the camera stream.
@@ -20,10 +22,10 @@ You may use rqt or [web_video_server](web_video_server.md) to view the camera st
If the camera stream is missing, try using the [`raspistill`](https://www.raspberrypi.org/documentation/usage/camera/raspicam/raspistill.md) utility to check whether the camera works.
First, stop the Clever service:
First, stop the `clover` service:
```bash
sudo systemctl stop clever
sudo systemctl stop clover
```
Then use `raspistill` to capture an image from the camera:
@@ -88,53 +90,66 @@ image_pub.publish(bridge.cv2_to_imgmsg(cv_image, 'bgr8'))
The obtained images can be viewed using [web_video_server](web_video_server.md).
#### Retrieving one frame
It's possibly to retrieve one camera frame at a time. This method works slower than normal topic subscribing and should not be used when it's necessary to process camera images continuously.
```python
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
rospy.init_node('computer_vision_sample')
bridge = CvBridge()
# ...
# Retrieve a frame:
img = bridge.imgmsg_to_cv2(rospy.wait_for_message('main_camera/image_raw', Image), 'bgr8')
```
### Examples
#### Working with QR codes
> **Hint** For high-speed recognition and positioning, it is better to use [ArUco markers](aruco.md).
To program actions of the copter upon detection of [QR codes](https://en.wikipedia.org/wiki/QR_code) you can use the [ZBar] library (http://zbar.sourceforge.net). It should be installed using pip:
```bash
sudo pip install zbar
```
To program actions of the copter for the detection of [QR codes](https://en.wikipedia.org/wiki/QR_code) you can use the [pyZBar](https://pypi.org/project/pyzbar/). This lib is installed in the last image for Raspberry Pi.
QR codes recognition in Python:
```python
import cv2
import zbar
import rospy
from pyzbar import pyzbar
from cv_bridge import CvBridge
from sensor_msgs.msg import Image
bridge = CvBridge()
scanner = zbar.ImageScanner()
scanner.parse_config('enable')
rospy.init_node('barcode_test')
# Image subscriber callback function
def image_callback(data):
cv_image = bridge.imgmsg_to_cv2(data, 'bgr8') # OpenCV image
gray = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY, dstCn=0)
pil = ImageZ.fromarray(gray)
raw = pil.tobytes()
image = zbar.Image(320, 240, 'Y800', raw) # Image params
scanner.scan(image)
for symbol in image:
# print detected QR code
print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data
barcodes = pyzbar.decode(cv_image)
for barcode in barcodes:
b_data = barcode.data.encode("utf-8")
b_type = barcode.type
(x, y, w, h) = barcode.rect
xc = x + w/2
yc = y + h/2
print ("Found {} with data {} with center at x={}, y={}".format(b_type, b_data, xc, yc))
image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback, queue_size=1)
rospy.spin()
```
The script will take up to 100% CPU capacity. To slow down the script artificially, you can use [throttling](http://wiki.ros.org/topic_tools/throttle) of frames from the camera, for example, at 5 Hz (`main_camera.launch`):
```xml
<node pkg="topic_tools" name="cam_throttle" type="throttle"
args="messages main_camera/image_raw 5.0 main_camera/image_raw/throttled"/>
args="messages main_camera/image_raw 5.0 main_camera/image_raw_throttled"/>
```
The topic for the subscriber in this case should be changed for `main_camera/image_raw/throttled`.
The topic for the subscriber in this case should be changed for `main_camera/image_raw_throttled`.

228
docs/en/camera_calib.md Normal file
View File

@@ -0,0 +1,228 @@
# Camera calibration
Computer vision is becoming more and more widespread. Often, computer vision algorithms are not precise and obtain distorted images from the camera, which is especially true for fisheye cameras.
![img](../assets/img1.jpg)
> The image is "rounded" closer to the edge.
Any computer vision algorithm will perceive the picture incorrectly. To remove such distortion, the camera that receives the image is to be calibrated in accordance with its own peculiarities.
## Script installation
First, you have to install the necessary libraries:
```
pip install numpy
pip install opencv-python
pip install glob
pip install pyyaml
pip install urllib.request
```
Then download the script from the repository:
```(bash)
git clone https://github.com/tinderad/clever_cam_calibration.git
```
Go to the downloaded folder and install the script:
```(bash)
cd clever_cam_calibration
sudo python setup.py build
sudo python setup.py install
```
If you are using Windows, download the archive from the [repository](https://github.com/tinderad/clever_cam_calibration/archive/master.zip), unzip it and install:
```(bash)
cd path\to\archive\clever_cam_calibration\
python setup.py build
python setup.py install
```
> path\to\archive path to unpacked archive.
## Preparing for calibration
You will have to prepare a calibration target. It looks like a chessboard. The file is available for downloading [here](https://www.oreilly.com/library/view/learning-opencv-3/9781491937983/assets/lcv3_ac01.png).
Glue a printed target to any solid surface. Count the number of intersections on the board lengthwise and widthwise, measure the size of a cell (mm).
![img](../assets/chessboard.jpg)
Turn on Clover and connect to its Wi-Fi.
> Navigate to 192.168.11.1:8080 and check whether the computer receives images from the image_raw topic.
## Calibration
Run script ***calibrate_cam***:
**Windows:**
```(bash)
>path\to\python\Scripts\calibrate_cam.exe
```
> path\to\Python path to the Python folder
**Linux:**
```(bash)
>calibrate_cam
```
Specify board parameters:
```(bash)
>calibrate_cam
Chessboard width: # Intersections widthwise
Chessboard height: # Intersections heightwise
Square size: # Length of cell edge (mm)
Saving mode (YES - on): # Save mode
```
> Save mode: if enabled, all received pictures will be saved in the current folder.
The script will start running:
```
Calibration started!
Commands:
help, catch (key: Enter), delete, restart, stop, finish
```
To calibrate the camera, make at least 25 photos of the chessboard at various angles.
![img](../assets/calibration.jpg)
To make a photo, enter command ***catch***.
```(bash)
>catch
```
The program will inform you about the calibration status.
```(bash)
...
Chessboard not found, now 0 (25 required)
> # Enter
---
Image added, now 1 (25 required)
```
> Instead of entering command ***catch*** each time, you can just press ***Enter*** (enter a blank line).
After you have made a sufficient number of images, enter command ***finish***.
```(bash)
...
>finish
Calibration successful!
```
### Calibration by the existing images
If you already have images, you can calibrate the camera by them with the help of script ***calibrate_cam_ex***.
```(bash)
>calibrate_cam_ex
```
Specify target characteristics and the path to the folder with images:
```(bash)
>calibrate_cam_ex
Chessboard width: # Intersections widthwise
Chessboard height: # Intersections heightwise
Square size: # Length of cell edge (mm)
Path: # Path to the folder with images
```
Apart from that, this script works similarly to ***calibrate_cam***.
The program will process all received pictures, and create file ***camera_info.yaml*** in the current folder. Using this file, you can equalize distortions in the images obtained from this camera.
> If you change the resolution of the received image, you will have to re-calibrate the camera.
## Correcting distortions
Function ***get_undistorted_image(cv2_image, camera_info)*** is responsible for obtaining a corrected image:
* ***cv2_image***: An image encoded into a cv2 array.
* ***camera_info***: The path to the calibration file.¬
The function returns a cv2 array, into which the corrected image is coded.
> If you are using a fisheye camera provided with Clover, for processing images with resolution 320x240 or 640x480, you can use the existing calibration settings. To do this, pass parameters ***clever_cam_calibration.clevercamcalib.CLEVER_FISHEYE_CAM_320*** or ***clever_cam_calibration.clevercamcalib.CLEVER_FISHEYE_CAM_640*** as argument ***camera_info***, respectively.
## Examples of operation
Source images:
![img](../assets/img1.jpg)
![img](../assets/img2.jpg)
Corrected images:
![img](../assets/calibresult.jpg)
![img](../assets/calibresult1.jpg)
## An example of usage
**Processing image stream from the camera**.
This program receives images from the camera on Clover and displays them on the screen in corrected for, using the existing calibration file.
```python
import clevercamcalib.clevercamcalib as ccc
import cv2
import urllib.request
import numpy as np
while True:
req = urllib.request.urlopen('http://192.168.11.1:8080/snapshot?topic=/main_camera/image_raw')
arr = np.asarray(bytearray(req.read()), dtype=np.uint8)
image = cv2.imdecode(arr, -1)
undistorted_img = ccc.get_undistorted_image(image, ccc.CLEVER_FISHEYE_CAM_640)
cv2.imshow("undistort", undistorted_img)
cv2.waitKey(33)
cv2.destroyAllWindows()
```
## The usage for ArUco
To apply the calibration parameters to the ArUco navigation system, move the calibration .yaml file to Raspberry Pi of Clover, and initialize it.
> Don't forget to connect to Wi-Fi of Clover.
The SFTP protocol is used for transferring the file. This example, WinSCP program is used.
Connect to Raspberry Pi via SFTP:
> Password: ***raspberry***
![img](../assets/wcp1.png)
Press “Enter”. Go to ***/home/pi/catkin_ws/src/clever/clever/camera_info/***, and copy the calibration .yaml file to this folder:
![img](../assets/wcp2.jpg)
Now we have to select this file in ArUco configuration. Connection via SSH is used for this purpose. This example, PuTTY program is used.
Connect to Raspberry Pi via SSH:
![img](../assets/pty1.jpg)
Log in with username ***pi*** and password ***raspberry***, go to directory ***/home/pi/catkin_ws/src/clever/clever/launch*** and start editing configuration ***main_camera.launch***:
![img](../assets/pty2.jpg)
In line ***camera node***, change parameter ***camera_info*** to ***camera_info.yaml***:
![img](../assets/pty3.jpg)
> Don't forget to change camera resolution.

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