EN articles update

8 new English articles
This commit is contained in:
Konstantin Eliseev
2019-02-05 14:20:11 +03:00
committed by GitHub
parent dffd818a42
commit 232401e730
9 changed files with 1084 additions and 7 deletions

View File

@@ -30,10 +30,11 @@
* [ROS](ros.md)
* [MAVROS](mavros.md)
* [Simple offboard](simple_offboard.md)
* [Navigation using ArUco markers](aruco.md)
* [Automatic check](selfcheck.md)
* [Code examples](snippets.md)
* [Adjusting the position of the main camera](camera_frame.md)
* [Working with the camera](camera.md)
* [Working with a LED strip on Raspberry 3](leds.md)
* [Using rviz and rqt](rviz.md)
* [Working with the ultrasonic distance gage](sonar.md)

171
docs/en/aruco.md Normal file
View File

@@ -0,0 +1,171 @@
# Navigation using ArUco markers
> **Note** Documentation for the versions [of image](microsd_images.md), starting with **0.15**. For earlier versions, see [documentation for version **0.14**](https://github.com/CopterExpress/clever/blob/v0.14/docs/ru/aruco.md).
[ArUco-Markers] (https://docs.opencv.org/3.2.0/d5/dae/tutorial_aruco_detection.html) is a popular technology for positioning
robotic systems using computer vision.
Examples of ArUco markers:
![ArUco markers](../assets/markers.jpg)
> **Hint** Use the most matte paper for printing visual markers. Glossy paper may glitter in the light, severely deteriorating the quality of recognition.
For rapid generation of markers for printing, you may use an online tool: http://chev.me/arucogen/.
## aruco\_pose
The `aruco_pose` module allows restoring the position of the copter relative to the map of ArUco markers and communicating it to the flight controller using the [Vision Position Estimation] mechanism (https://dev.px4.io/en/ros/external_position_estimation.html).
If the source of the copter position by the markers is available, the option appears for precise autonomous indoor navigation by the positions using the [simple\_offboard] module (simple_offboard.md).
### Turning on
Make sure that in the clever launch file \(`~/catkin_ws/src/clever/clever/launch/clever.launch`\), the start of aruco\_pose and [computer vision cameras] is turned on(camera.md):
```xml
<arg name="main_camera" default="true"/>
```
```xml
<arg name="aruco" default="true"/>
```
After the launch-file is edited, restart package `clever`:
```(bash)
sudo systemctl restart clever
```
### Calibrating the ArUco marker map.
An automatically generated [ArUco-board] may be used as a map of marks (https://docs.opencv.org/trunk/db/da9/tutorial_aruco_board_detection.html).
The map of marks is adjusted using file `~/catkin_ws/src/clever/clever/launch/aruco.launch`. To use ArUco-board, enter its parameters:
```xml
<node pkg="nodelet" type="nodelet" name="aruco_pose" args="load aruco_pose/aruco_pose nodelet_manager">
<param name="frame_id" value="aruco_map_raw"/>
<!-- the type of the marker field -->
<param name="type" value="gridboard"/>
<!-- the number of markets along x -->
<param name="markers_x" value="1"/>
<!-- the number of markers along y -->
<param name="markers_y" value="6"/>
<!-- ID of the first marker (left top) -->
<param name="first_marker" value="240"/>
<!-- the length of the marker side in meters -->
<param name="markers_side" value="0.3362"/>
<!-- distance between the murders -->
<param name="markers_sep" value="0.46"/>
</node>
```
The vertical and horizontal distance between the markers may be set separately:
```xml
<!-- the horizontal distance between the markers -->
<param name="markers_sep_x" value="0.97"/>
<!-- the vertical distance between the marker -->
<param name="markers_sep_y" value="1.435"/>
```
If a map with a custom order of marker IDs is used, parameter `marker_ids` may be used:
```xml
<rosparam param="marker_ids">[5, 7, 9, 11, 13, 15]</rosparam>
```
The markers are numbered from the top left corner of the field.
For monitoring the map that is currently used by the copter for navigation, one can watch the content of topic `aruco_pose/map_image`. In a browser, it may be viewed with [web\_video\_server](web_video_server.md) by following the link [http://192.168.11.1:8080/snapshot?topic=/aruco\_pose/map\_image](http://192.168.11.1:8080/snapshot?topic=/aruco_pose/map_image):
![](../../assets/Снимок экрана 2017-11-27 в 23.20.49.png)
When flying, make sure that the markers glued to the floor correspond to the map.
In topic `aruco_pose/debug` \([http://192.168.11.1:8080/snapshot?topic=/aruco\_pose/debug](http://192.168.11.1:8080/snapshot?topic=/aruco_pose/debug)\) the current result of markers recognitions is available:
TODO
### The system of coordinates
According to [agreement](http://www.ros.org/reps/rep-0103.html), the standard ENU system of coordinates is used in the marker field:
* x — rightward \(conditional East\);
* y — forward \(conditional North\);
* z — upward.
_Note_: the definition above is provided for a situation when the marker field is on the floor.
First, the zero is the bottom left point of the marker field. The yaw angle is considered zero when the copter is faced rightward\(along the x-axis\).
![The system of markers coordinates](../assets/aruco-frame.png)
### Configuring the flight controller
Correct Vision Position Estimation requires making sure \(via [QGroundControl](gcs_bridge.md)\) that:
* **For Pixhawk**: Firmware with LPE \(local position estimator\) is installed. For Pixhawk [download firmware `px4fmu-v2_lpe.px4`](https://github.com/PX4/Firmware/releases).
**For Pixracer**: parameter `SYS_MC_EST_GROUP` should be set to`local_position_estimator, attitude_estimator_q`.
> **Note** After changing the value of parameter `SYS_MC_EST_GROUP` restart the flight controller.
* In parameter `LPE_FUSION` **only** flags `vision position`, `land detector` are enabled. The final value _20_.
* Compass disabled: `ATT_W_MAG` = 0
* Complimentary filter external heading weight: `ATT_W_EXT_HDG` = 0.5
* Orientation by yaw by vision enabled: `ATT_EXT_HDG_M` = 2 `MOCAP`.
* VPE settings: `LPE_VIS_DELAY` = 0 sec, `LPE_VIS_XY` = 0.1 m, `LPE_VIS_Z` = 0.15 m.
* Recommended settings for land detector:
* `COM_DISARM_LAND` = 1 s
* `LNDMC_ROT_MAX` = 45 deg
* `LNDMC_THR_RANGE` = 0.5
* `LNDMC_Z_VEL_MAX` = 1 m/s
<!--
For the ease of configuring, you may use a ready settings file for [Clever 2](https://github.com/CopterExpress/clever/blob/master/docs/assets/Clever2LPE_160118.params) or for [Clever 3](https://github.com/CopterExpress/clever/blob/master/docs/assets/Clever3_LPE_020218.params) and upload it to the controller using menu Tools - Load from file in tab Parameters in QGroundControl.
![](../assets/Screenshot from 2018-02-27 22-30-50.png)
-->
### Flight
A properly configured copter starts holding position by VPE \(in [modes](modes.md) `POSCTL` or `OFFBOARD`\) automatically.
For [autonomous flights](simple_offboard.md) do you will be able to use functions `navigate`, `set_position`, `set_velocity`. For flying to specific coordinates of the marker field, use frame `aruco_map`:
```python
# First, the copter has to take off to see the map of marks
# and for frame aruco_map to appear:
navigate(0, 0, 2, frame_id='body', speed=0.5, auto_arm=True) # take off to the altitude of 2 meters
time.sleep(5)
# Flying to coordinate 2:2 of the marker field at the altitude of 2 meters
navigate(2, 2, 2, speed=1, frame_id='aruco_map') # flying to coordinate 2:2 at the altitude of 3 meters
```
See [other functions](simple_offboard.md) simple_offboard.
### Location of markers on the ceiling
![Markers on the ceiling](../assets/IMG_4175.JPG)
To navigate by the markers placed on the ceiling, you need to set the main camera facing up and [set the corresponding frame of the camera](camera_frame.md).
To set the map of markers in a "turned over" system of coordinates, change parameter `aruco_orientation` in file `~/catkin_ws/src/clever/clever/aruco.launch`:
```xml
<param name="aruco_orientation" value="map_upside_down"/>
```
When this parameter is set, frame aruco\_map will also be "turned over". Thus, to fly at the altitude of 2 meters below the ceiling, argument `z` should be set to 2:
```python
navigate(x=1, y=2, z=1.1, speed=0.5, frame_id='aruco_map')

110
docs/en/camera.md Normal file
View File

@@ -0,0 +1,110 @@
# Working with the camera
To work with the main camera, make sure it is enabled in file `~/catkin_ws/src/clever/clever/launch/clever.launch`:
```xml
<arg name="main_camera" default="true"/>
```
Also make sure that [correct position and orientation are indicated] for the camera (camera_frame.md).
The `clever` package must be restarted after the launch-file has been edited:
```(bash)
sudo systemctl restart clever
```
For monitoring images from the camera, you may use rqt or [web_video_server](web_video_server.md).
## Computer vision
For implementation of the computer vision algorithms, it is recommended to use the [OpenCV] library that is pre-installed in [the SD card image] (microsd_images.md) (https://opencv.org).
### Python
Main article: http://wiki.ros.org/cv_bridge/Tutorials/ConvertingBetweenROSImagesAndOpenCVImagesPython.
An example of creating a subscriber for a topic with an image from the main camera for processing with OpenCV:
```python
import rospy
import cv2
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
rospy.init_node('computer_vision_sample')
bridge = CvBridge()
def image_callback(data):
cv_image = bridge.imgmsg_to_cv2(data, 'bgr8') # OpenCV image
# Do any image processing with cv2...
image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback)
rospy.spin()
```
To debug image processing, you can publish a separate topic with the processed image:
```python
image_pub = rospy.Publisher('~debug', Image)
```
Publishing the processed image (at the end of the image_callback function):
```python
image_pub.publish(bridge.cv2_to_imgmsg(cv_image, 'bgr8'))
```
The obtained images can be viewed using [web_video_server](web_video_server.md).
### 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://ru.wikipedia.org/wiki/QR-код) you can use the [ZBar] library (http://zbar.sourceforge.net). It should be installed using pip:
```(bash)
sudo pip install zbar
```
Recognizing QR codes in Python:
```python
import cv2
import zbar
from cv_bridge import CvBridge
from sensor_msgs.msg import Image
bridge = CvBridge()
scanner = zbar.ImageScanner()
scanner.parse_config('enable')
# 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
image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback, queue_size=1)
```
The script will take up to 100% CPU capacity. To slow down the script artificially, you can run [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"/>
```
The topic for the subscriber in this case should be changed for `main_camera/image_raw/throttled`.

63
docs/en/camera_frame.md Normal file
View File

@@ -0,0 +1,63 @@
# Adjusting the position of the main camera
> **Note** Documentation for the versions [of image](microsd_images.md), starting with **0.15**. For earlier versions, see [documentation for version **0.14**](https://github.com/CopterExpress/clever/blob/v0.14/docs/ru/camera_frame.md).
Position and orientation of the main camera is determined in file `~/catkin_ws/src/clever/clever/launch/main_camera.launch`:
```xml
<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/>
```
This line sets static transformation between frame `base_link` ([corresponds to the flight controller housing](frames.md)) and the camera (`main_camera_optical`) in format:
```txt
shift_x shift_y shift_z yaw_angle pitch_angle roll_angle
```
The frame of the camera is set so that:
* **<font color=red>x</font>** points to the right in the picture;
* **<font color=green>y</font>** points down in the picture;
* **<font color=blue>z</font>** points away from the camera matrix plane.
Shifts are set in meters, angles — in radians. Correctness of the transformation set may be checked using [rviz](rviz.md).
## Settings for Clever
The first image — how a copter model looks in rviz with these settings, the second image — how Clever looks with the same settings.
### 1. The camera is facing downward, the flat cable — backward
```xml
<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/>
```
<img src="../assets/camera_option_1_rviz.png" width=400>
<img src="../assets/camera_option_1_clever.jpg" width=400>
### 2. The camera is facing downwards, the flat cable — forward
```xml
<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 1.5707963 0 3.1415926 base_link main_camera_optical"/>
```
<img src="../assets/camera_option_2_rviz.png" width=400>
<img src="../assets/camera_option_2_clever.jpg" width=400>
### 3. The camera is facing upward, the flat cable — backward
```xml
<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 0.07 1.5707963 0 0 base_link main_camera_optical"/>
```
<img src="../assets/camera_option_3_rviz.png" width=400>
<img src="../assets/camera_option_3_clever.jpg" width=400>
### 4. The camera is facing upward, the flat cable — forward
```xml
<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 0.07 -1.5707963 0 0 base_link main_camera_optical"/>
```
<img src="../assets/camera_option_4_rviz.png" width=400>
<img src="../assets/camera_option_4_clever.jpg" width=400>

233
docs/en/leds.md Normal file
View File

@@ -0,0 +1,233 @@
# Working with a LED strip on Raspberry 3
## Connecting and determining the type of the strip
There are two main types of addressed LEDs: WS2812B and WS2812. The control principle is the same, but the timings are different. Locate a LED chip on the strip, and determine how many pins it has: 6 or 4. If it has 6 pins, it is WS2812; if 4, it is WS2812B or its analog SK6812.
<img src="../assets/timing_with_thumbs.png" height="400px" alt="leds">
Since the control principle is the same, the strips are connected the same way:
| strip | Raspberry Pi |
| :---: | :---: |
| GND | GND |
| 5V | 5V |
| DIN | GPIO21 or GPIO31 |
strip types for denoting the strip in the code are described in [file](https://github.com/jgarff/rpi_ws281x/blob/master/ws2811.h). The main strip types are WS2812\_STRIP \(for WS2812\) and SK6812\_STRIP \(for WS2812B or SK6812\).
## Installing a library for working with the LED strip
Define the folder that will contain files of the library, and open the path to this folder in the terminal. By default, you can use the home folder, to move to it, run command:
```(bash)
cd ~
```
Clone the repository of library for working with LED strips on Raspberry Pi:
```(bash)
git clone https://github.com/jgarff/rpi_ws281x.git
```
Install [Scons](https://ru.wikipedia.org/wiki/SCons) and [Swig](https://ru.wikipedia.org/wiki/SWIG):
```(bash)
sudo apt-get install scons python-dev swig
```
Compile the library using Scons \(the command is to be run inside the folder with the source code of the library\):
```(bash)
cd rpi_ws281x
scons
```
Compile the Python wrapper for the library using Swig, and set it for using in your Python scripts.
```(bash)
cd python
sudo python ./setup.py build
sudo python ./setup.py install
```
## Sample program for a LED bang on RPI3
In a text editor, open file `strandtest.py` from folder `python/examples` \(located in the folder with the library\):
```(bash)
nano strandtest.py
```
Locate the part of the code with strip settings:
```(bash)
# LED strip configuration:
LED_COUNT = 16 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!).
#LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
LED_STRIP = ws.WS2811_STRIP_GRB # Strip type and color ordering
```
Adjust the settings for working with the strip, and save the file. To avoid interference of the use of the strip with the operation of other devices on Raspberry Pi, it is recommended to use the following settings \(the settings are for a strip together with Clever 3\):
```(bash)
# LED strip configuration:
LED_COUNT = 30 # Number of LED pixels.
LED_PIN = 21 # GPIO pin connected to the pixels.
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
LED_STRIP = ws.SK6812_STRIP # Strip type and color ordering
```
Run the test program from root:
```(bash)
sudo python strandtest.py
```
The root privileges are required for executing the script, since without them there is no access to the interrupt functions used by the library to work with the strip.
## Compatibility with ROS and Python
When the program is run using sudo, the user environment changes, and errors of library import appear, since required paths are missing in the environment. To add paths to Python libraries and ROS packages to the environment, add the following lines to file `/etc/sudoers` :
```(bash)
Defaults env_keep += "PYTHONPATH"
Defaults env_keep += "PATH"
Defaults env_keep += "ROS_ROOT"
Defaults env_keep += "ROS_MASTER_URI"
Defaults env_keep += "ROS_PACKAGE_PATH"
Defaults env_keep += "ROS_LOCATIONS"
Defaults env_keep += "ROS_HOME"
Defaults env_keep += "ROS_LOG_DIR"
```
## Functions for working with the LED strip
To connect the library and its correct operation, engage the following modules: neopixel - for strip operation, time for delay management, and sys and signal for interruptions and forming the control signal.
```python
from neopixel import *
import time
import signal
import sys
```
To work with the strip, create an object of type **Adafruit_NeoPixel**, and initialize the library:
```python
# Creating a NeoPixel object with specifies configuration
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT)
# Initialization of the library, to be run before other functions
strip.begin()
```
The main functions that are used to control the strip:
* `numPixels()` - returns the number of pixels in the strip. It is convenient for cyclical control of the entire strip.
* `setPixelColor(pos, color)` sets pixel color to position `pos`, to color `color`. The color should be a 24 bit value, where the first 8 bits are red color \(red\), the next 8 bits — green \(green\), and the last 8 bits — blue \(blue\). To get the `color` value, you can use function `Color(red, green, blue)`, which composes this value of 3 components. Each component should be in the range 0 255, where 0 is no color, and 255 — the highest brightness of the component available in the LED module.
* `setPixelColorRGB(pos, red, green, blue)` sets the pixel color at position pos to the color that consists of components `red`, `green`, `blue`. Each component should be in the range 0 255, where 0 is no color, and 255 — the highest brightness of the component available in the LED module.
* `show()` updates the state of the strip. It is only after using it that all software changes are moved to the LED strip.
Other functions may be detected by running command
```(bash)
pydoc neopixel
```
The result of the command:
```(bash)
Help on module neopixel:
NAME
neopixel
DESCRIPTION
# Adafruit NeoPixel library port to the rpi_ws281x library.
# Author: Tony DiCola (tony@tonydicola.com)
CLASSES
__builtin__.object
Adafruit_NeoPixel
class Adafruit_NeoPixel(__builtin__.object)
| Methods defined here:
|
| __del__(self)
|
| __init__(self, num, pin, freq_hz=800000, dma=5, invert=False)
| Class to represent a NeoPixel/WS281x LED display. Num should be the
| number of pixels in the display, and pin should be the GPIO pin connected
| to the display signal line (must be a PWM pin like 18!). Optional
| parameters are freq, the frequency of the display signal in hertz (default
| 800khz), dma, the DMA channel to use (default 5), and invert, a boolean
| specifying if the signal line should be inverted (default False).
|
| begin(self)
| Initialize library, must be called once before other functions are
| called.
|
| getPixelColor(self, n)
| Get the 24-bit RGB color value for the LED at position n.
|
| getPixels(self)
| Return an object which allows access to the LED display data as if
| it were a sequence of 24-bit RGB values.
|
| numPixels(self)
| Return the number of pixels in the display.
|
| setBrightness(self, brightness)
| Scale each LED in the buffer by the provided brightness. The brightness
| of 0 is the darkest and 255 is the brightest. Note that scaling can have
| quantization issues (i.e. blowing out to white or black) if used repeatedly!
|
| setPixelColor(self, n, color)
| Set LED at position n to the provided 24-bit color value (in RGB order).
|
| setPixelColorRGB(self, n, red, green, blue)
| Set LED at position n to the provided red, green, and blue color.
| Each color component should be a value from 0 to 255 (where 0 is the
| lowest intensity and 255 is the highest intensity).
|
| show(self)
| Update the display with the data from the LED buffer.
|
FUNCTIONS
Color(red, green, blue)
Convert the provided red, green, blue color to a 24-bit color value.
Each color component should be a value 0-255 where 0 is the lowest intensity
and 255 is the highest intensity.
```
## Why exactly so, and is there a different way?
The main types of strips used for Clever 3 are WS2812, WS2812B and SK6812 \(analog to WS2812B\). They are controlled according to the same principle: for a massif of LEDs in the strip, a data packet at the rate of 24 bits per LED; each led reads the first 24 bits of received data, and sets the corresponding color, the rest of the data are sent to the next LED in the strip. Zeros and ones are determined by different combinations of the durations of high and low level in the pulse.
All these strips are supported for library management [rpi_ws281x](https://github.com/jgarff/rpi_ws281x), with that, the DMA module\(direct memory access \) of the Raspberri processor, and one of the data channels re used for control: PWM, PCM, or SPI, which guarantees absence of delays in control \(and everything is controlled from a multitasking OS, it's important\).
There are some peculiarities of working with channels, for example, when transmitting data using PWM \\ (PWM \\), the built-in audio system stops working, when transmitting data via PCM, the use of connected digital audio devices is blocked\\ (with that, the built-in system keeps working \\), and when using SPI \(by the way, special adjustment of buffer size and Raspberry GPU frequency is required for proper operation\) the LED strip blocks all other devices connected to that channel.
There are some peculiarities of DMA channel selection to control the strip: some channels are used by the system, so using them may lead to unpleasant consequences; for example, using channel 5 destroys the Raspberry file system, since this channel is used for reading / writing to the SD card. Secure channel is No. 10, it is set by default in the library above.
Therefore, the scenarios of using the LED strip are the following:
1. If performance of embedded audio on Raspberry is not important \(and we don't use it, since the audio and the strip will produce nonsense in this case\), it is possible to use the PWM channel \(for this purpose, you have to connect strip inputs to one of the following Raspberry GPIO ports: 12, 18, 40, or 52 for PWM0 channel and 13, 19, 41, 45, or 53 for PWM1 channel\).
2. If presence of other devices on the SPI bus is not important, you can control the strip via the SPI \(GPIO on Raspberry 10 or 38\) channel.
Here the following settings are required \(only for Raspberry Pi 3\):
* increase the size of the data transfer buffer to support long strips, by adding line `spidev.bufsiz=32768` to file `/boot/cmdline.txt`;
* set the GPU frequency for proper the frequency of SPI, by adding line `core_freq=250` to file `/boot/config.txt`.
3. If both audio operation and connection of SPI devices in addition to the LED strip is important, the strip may be controlled via the PCM channel \(GPIO 21 or 31\). With that, no further manipulations with Raspberry is required.
Based on the above methods of controlling the strip, the best variant that allows controlling the strip, preserve operability of the built-in audio system, and the possibility of connecting all sorts of devices and sensors via the SPI is the controlling via the PCM \(GPIO 21\) channel using the 10 DMA channel.

75
docs/en/rviz.md Normal file
View File

@@ -0,0 +1,75 @@
Using rviz and rqt
===
![rviz](../assets/rviz.png)
The [rviz] tool(http://wiki.ros.org/rviz) allows real-time visualization of all components of the robotic system —the system of coordinates, moving parts, sensors, camera images — on the 3D stage.
[rqt](http://wiki.ros.org/rqt) is a set of GUI for analyzing and controlling ROS systems. For example, `rqt_image_view` allows viewing topics with images, `rqt_multiplot` allows plot charts by the values in topics, etc.
To use rviz and rqt, a PC running Ubuntu Linux (or a virtual machine such as [Parallels Desktop Lite] (https://itunes.apple.com/ru/app/parallels-desktop-lite/id1085114709?mt=12) or [VirtualBox] (https://www.virtualbox.org)) is required.
Install package `ros-kinetic-desktop-full` or `ros-kinetic-desktop` using the [installation documentation](http://wiki.ros.org/kinetic/Installation/Ubuntu).
Start rviz
---
To start еру visualization of the state of Clever in real time, connect to it via Wi-Fi (`CLEVER-xxx`) and run rviz, specifying an appropriate ROS_MASTER_URI:
```(bash)
ROS_MASTER_URI=http://192.168.11.1:11311 rviz
```
If connection is not established, make sure the `.bashrc` of Clever contains line:
```(bash)
export ROS_IP=192.168.11.1
```
Using rviz
---
### Visualization of the copter position
It is recommended to set the `map` frame as a reference frame. To visualize the copter, add visualization markers from topic `/vehicle_markers`. To visualize the camera of the copter, add visualization markers from topic `/main_camera/camera_markers`.
The result of copter and camera visualization is shown below:
![rviz](../assets/copter_visualization.png)
### Visualization of the environment
You can view a picture with augmented reality from the topic of the main camera `/main_camera/image_raw`.
Axis or Grid configured to frame `aruco_map` will visualize the location [on the map of ArUco marks](aruco.md).
### jsk_rviz_plugins
It is also recommended to install additional useful plugins for rviz [jsk_rviz_plugins](https://jsk-docs.readthedocs.io/en/latest/jsk_visualization/doc/jsk_rviz_plugins/index.html). This kit allows visualizing topics like `TwistStamped` (velocity) `CameraInfo`, `PolygonArray`, and many more. To install, use command:
```(bash)
sudo apt-get install ros-kinetic-jsk-visualization
```
Starting the rqt toolkit
---
![rqt](../assets/rqt.png)
To start rqt for monitoring Clever status, use command:
```(bash)
ROS_MASTER_URI=http://192.168.11.1:11311 rqt
```
An example of starting a specific plugin (`rqt_image_view`):
```(bash)
ROS_MASTER_URI=http://192.168.11.1:11311 rqt_image_view
```
Brief description of useful rqt plugins:
* `rqt_image_view` viewing images from topics like `sensor_msgs/Image`;
* `rqt_multiplot` Building charts from the data from of arbitrary topics (installation: `sudo apt-get install ros-kinetic-rqt-multiplot`);
* Bag working with [Bag-files](http://wiki.ros.org/rosbag).

32
docs/en/selfcheck.md Normal file
View File

@@ -0,0 +1,32 @@
# Automatic check
Before flying (especially autonomous), you can use several methods of automatic self-testing of the quadcopter subsystems.
## <span>selfcheck</span>.py
Utility `selfcheck.py` is part of `clever` package, and automatically tests the main aspects of the ROS platform and the PX4. The utility is pre-installed on [the Raspberry Pi image](microsd_images.md).
To initiate it, type in [the Raspberry Pi console](ssh.md):
```(bash)
rosrun clever selfcheck.py
```
<img src="../assets/selfcheck.png">
Description of some checks:
* FCU checking proper connection with the flight controller;
* IMU checking correctness of the data from IMU;
* Local position presence of the local position of the drone;
* Velocity estimation drone velocity estimation (**if this check fails, never take off offline!**);
* Global position (GPS) — presence of the global position (GPS required);
* Camera — proper operation of the Raspberry camera.
## commander check
To check the main sub systems of PX4 and the possibility of arming at the moment, you can perform command `commander check` in the MAVLink console.
<img src="../assets/commander-check.png">
When using SITL instead of the MAVLink console, use a terminal with SITL running.

259
docs/en/snippets.md Normal file
View File

@@ -0,0 +1,259 @@
Code examples
===
Python
---
> **Note** If Cyrillic characters in the UTF-8 charset are used, specify the charset at the beginning of the program:
> ```python
> # -*- coding: utf-8 -*-
> ```
### # {#distance}
The function of determining the distance between two points (**important**: the points are to be in the same [system of coordinates](frames.md)):
```python
def get_distance(x1, y1, z1, x2, y2, z2):
return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2)
```
### # {#distance-global}
A function for approximate determination of the distance (in meters) between two global coordinates (latitude/longitude):
```python
def get_distance_global(lat1, lon1, lat2, lon2):
return math.hypot(lat1 - lat2, lon1 - lon2) * 1.113195e5
```
### # {#block-takeoff}
Takeoff and waiting for the end of takeoff:
```python
z = 2 # altitude
tolerance = 0.2 # precision of altitude check (m)
# Remembering the initial point
start = get_telemetry()
# Take off to the altitude of 2 m
print navigate(z=z, speed=0.5, frame_id='body', auto_arm=True)
# Waiting for takeoff
while True:
# Checking current altitude
if get_telemetry().z - start.z + z < tolerance:
# Takeoff complete
break
rospy.sleep(0.2)
```
### # {#block-nav}
Flying to a point and waiting for the copter to arrive at it:
```python
tolerance = 0.2 # precision of arrival check (m)
frame_id='aruco_map'
# Flying to point 1:2:3 in the field of ArUco markers
print navigate(frame_id=frame_id, x=1, y=2, z=3, speed=0.5)
# Wait for the copter to arrive at the requested point
while True:
telem = get_telemetry(frame_id=frame_id)
# Calculating the distance to the requested point
if get_distance(1, 2, 3, telem.x, telem.y, telem.z) < tolerance:
# Arrived at the requested point
break
rospy.sleep(0.2)
```
### # {#disarm}
Quadcopter disarm (disabling propellers **the copter will fall down**):
```python
# Declaring a proxy:
from mavros_msgs.srv import CommandBool
arming = rospy.ServiceProxy('mavros/cmd/arming', CommandBool)
# ...
arming(False) # дизарм
```
### # {#transform}
Transforming the position (`PoseStamped`) from one system of coordinates ([of frame](frames.md)) to another one using [tf2] (http://wiki.ros.org/tf2):
```python
import tf2_ros
import tf2_geometry_msgs
tf_buffer = tf2_ros.Buffer()
tf_listener = tf2_ros.TransformListener(tf_buffer)
# ...
# Creating as PoseStamped object (or getting it from the topic):
pose = PoseStamped()
pose.header.frame_id = 'map' # frame, which is the position is specified
pose.header.stamp = rospy.get_rostime() # the moment for which the position is specified (current time)
pose.pose.position.x = 1
pose.pose.position.y = 2
pose.pose.position.z = 3
pose.pose.orientation.w = 1
frame_id = 'base_link' # target frame
transform_timeout = rospy.Duration(0.2) # wait for transformation timeout
# Transforming the position from the old frame to the new one:
new_pose = tf_buffer.transform(pose, frame_id, transform_timeout)
```
### # {#upside-down}
Determining whether the copter is turned over:
```python
PI_2 = math.pi / 2
telem = get_telemetry()
flipped = not -PI_2 <= telem.pitch <= PI_2 or not -PI_2 <= telem.roll <= PI_2
```
### # {#angle-hor}
Calculating the copter total angle to the horizon:
```python
PI_2 = math.pi / 2
telem = get_telemetry()
flipped = not -PI_2 <= telem.pitch <= PI_2 or not -PI_2 <= telem.roll <= PI_2
angle_to_horizon = math.atan(math.hypot(math.tan(telem.pitch), math.tan(telem.roll)))
if flipped:
angle_to_horizon = math.pi - angle_to_horizon
```
### # {#circle}
Flying along a circular path:
```python
RADIUS = 0.6 # m
SPEED = 0.3 # rad / s
start = get_telemetry()
start_stamp = rospy.get_rostime()
r = rospy.Rate(10)
while not rospy.is_shutdown():
angle = (rospy.get_rostime() - start_stamp).to_sec() * SPEED
x = start.x + math.sin(angle) * RADIUS
y = start.y + math.cos(angle) * RADIUS
set_position(x=x, y=y, z=start.z)
r.sleep()
```
### # {#rate}
repeating an action with the frequency of 10 Hz:
```python
r = rospy.Rate(10)
while not rospy.is_shutdown():
# Do anything
r.sleep()
```
### # {#mavros-sub}
An example of subscription to a topic from MAVROS
```python
from geometry_msgs.msg import PoseStamped, TwistStamped
from sensor_msgs.msg import BatteryState
from mavros_msgs.msg import RCIn
# ...
def state_update(pose):
# Processing new data about the copter position
pass
# Other handler functions
# ...
rospy.Subscriber('/mavros/local_position/pose', PoseStamped, pose_update)
rospy.Subscriber('/mavros/local_position/velocity', TwistStamped, velocity_update)
rospy.Subscriber('/mavros/battery', BatteryState, battery_update)
rospy.Subscriber('mavros/rc/in', RCIn, rc_callback)
```
Information about MAVROS topics us available at [the link](mavros.md).
<!-- markdownlint-disable MD044 -->
### # {#mavlink}
<!-- markdownlint-enable MD044 -->
An example of sending an arbitrary [MAVLink message](mavlink.md) to the copter:
```python
# ...
from mavros_msgs.msg import Mavlink
from mavros import mavlink
from pymavlink import mavutil
# ...
mavlink_pub = rospy.Publisher('mavlink/to', Mavlink, queue_size=1)
# Sending a HEARTBEAT message:
msg = mavutil.mavlink.MAVLink_heartbeat_message(mavutil.mavlink.MAV_TYPE_GCS, 0, 0, 0, 0, 0)
msg.pack(mavutil.mavlink.MAVLink('', 2, 1))
ros_msg = mavlink.convert_to_rosmsg(msg)
mavlink_pub.publish(ros_msg)
```
### # {#rc-sub}
Reaction to switching the mode on the transmitter (may be used for starting an offline flight, see [example](https://gist.github.com/okalachev/b709f04522d2f9af97e835baedeb806b)):
```python
from mavros_msgs.msg import RCIn
# Called when new data are received from the transmitter
def rc_callback(data):
# Arbitrary reaction to switching the toggle switch on the transmitter
if data.channels[5] < 1100:
# ...
pass
elif data.channels[5] > 1900:
# ...
pass
else:
# ...
pass
# Creating a subscriber for the topic with the data from the transmitter
rospy.Subscriber('mavros/rc/in', RCIn, rc_callback)
rospy.spin()
```
### # {#flip}
Flip:
TODO

133
docs/en/sonar.md Normal file
View File

@@ -0,0 +1,133 @@
# Working with the ultrasonic distance gage
Ultrasonic distance gage (*"sonar"*) is a distance gage based on the principle of measuring the time of a sound wave (about 40 kHz) propagation to the obstacle and back. The sonar can measure the distance up to 1.5 3 m with the accuracy of several centimeters.
## Distance gage HC-SR04
<img src="../assets/hc-sr04.jpg" alt="hc-sr04" width=200>
## Installation
The distance gage is attached to the body using double-sided tape. For obtaining acceptable results, the use of vibro-insulation is required. A piece of PU foam may be used for vibro-insulation.
### Connection
Connect HC-SR04 to Raspberry Pi according to the connection diagram. Use 1.0 and 2.2 kΩ resistors and any free GPIO pins, e.g., 23 and 24:
<img src="../assets/raspberry-hc-sr04.png" alt="Connecting HC-SR04" height=600>
> **Hint** Instead of a 2.2 kΩ resistor, you can use two 1 kΩ resistors connected in series.
<!-- -->
> **Hint** There are several interchangeable pins **GND** and **VCC 5V** on Raspberry Pi. Use the [pinout] (https://pinout.xyz) to find them.
### Reading the data
To read the data from distance gage HC-SR04 library for working with <abbr title="General-Purpose Input/Output">GPIO</abbr> is used [`pigpio`](http://abyz.me.uk/rpi/pigpio/index.html). This library is pre-installed in the [Clever image](microsd_images.md), starting with version **v0.14**. For older versions of the image, use [an installation guide](http://abyz.me.uk/rpi/pigpio/download.html).
To work with `pigpio`, start appropriate daemon:
```(bash)
sudo systemctl start pigpiod.service
```
You can also enable `pigpiod` auto launch on system startup:
```(bash)
sudo systemctl enable pigpiod.service
```
Thus, it becomes possible to interact with the `pigpiod` daemon from Python:
```python
import pigpio
pi = pigpio.pi()
```
> **Hint** See detailed description of Python API in [`pigpio` documentation](http://abyz.me.uk/rpi/pigpio/python.html).
An example of the code for reading data from HC-SR04:
```python
import time
import threading
import pigpio
TRIG = 23 is the No. of the pin connected to the Trig contact of the distance gage
TRIG = 24 is the No. of the pin connected to the Echo contact of the distance gage
pi = pigpio.pi()
done = threading.Event()
def rise(gpio, level, tick):
global high
high = tick
def fall(gpio, level, tick):
global low
low = tick - high
done.set()
def read_distance():
done.clear()
pi.gpio_trigger(TRIG, 50, 1)
done.wait(timeout=5)
return low / 58.0 / 100.0
pi.set_mode(TRIG, pigpio.OUTPUT)
pi.set_mode(ECHO, pigpio.INPUT)
pi.callback(ECHO, pigpio.RISING_EDGE, rise)
pi.callback(ECHO, pigpio.FALLING_EDGE, fall)
while True:
# Reading the distance:
print read_distance()
```
### Filtering the data
To filter (smooth out) the data and delete [emission](https://ru.wikipedia.org/wiki/Outbreak_%28statistics%29) [Kalman filter] (https://ru.wikipedia.org/wiki/Фильтр_Калмана) or a simple [median filter](https://ru.wikipedia.org/wiki/Median_filter) can be used. An example of median filtering implementation:
```python
import collections
import numpy
# ...
history = collections.deque(maxlen=10) # 10 - количество сэмплов для усреднения
def read_distance_filtered():
history.append(read_distance())
return numpy.median(history)
while True:
print read_distance_filtered()
```
An example of charts of initial and filtered data:
<img src="../assets/sonar-filtered.png">
The source code of the ROS-node used for building the chart can be found [on Gist](https://gist.github.com/okalachev/feb2d7235f5c9636802c3cda43add253).
## Distance gage RCW-0001
<img src="../assets/rcw-0001.jpg" width=200>
Ultrasonic distance gage RCW-0001 is compatible with distance gage HC-SR04. Use the instruction above to connect and work with it.
## Flight
An example of a flight program with the use of [simple_offboard](simple_offboard.md), which makes the copter fly forward until the connected ultrasonic distance gage detects an obstacle:
```python
set_velocity(x=0.5, frame_id='body', auto_arm=True) # flying forward at the velocity of 0.5 mps
while True:
if read_distance_filtered() < 1:
# if the obstacle is closer than 1 m, hanging on the spot
set_position(x=0, y=0, z=0, frame_id='body')
rospy.sleep(0.1)
```