Compare commits

..

103 Commits

Author SHA1 Message Date
Yinglei Zhu
492430e994 docs: fix placeholder links and docs workflow deprecations (#515) 2026-04-14 17:31:20 +03:00
Oleg Kalachev
924a6c60da Change documentation domain 2026-04-07 15:43:10 +03:00
Oleg Kalachev
8ca24ea293 Update deprecated actions 2025-06-19 12:13:25 +03:00
Oleg Kalachev
c4e6280ea9 docs: bring back a hidden article (request from the authors)
The article was hidden in commit dcecb03
2025-06-19 11:51:04 +03:00
Oleg Kalachev
d46bfabb65 docs: fix simple offboard article versions note 2025-01-20 09:45:35 +03:00
Oleg Kalachev
66dd9e61c6 Fix markdownlint 2024-11-04 14:11:42 +03:00
Oleg Kalachev
dcecb03cd5 docs: temporary hide a contributed article at the request of the authors 2024-11-04 14:04:33 +03:00
Oleg Kalachev
687041d571 docs: fix to simulation installation article 2024-10-10 21:31:42 +03:00
Oleg Kalachev
449364bffb docs: some fixes to simulation installation articles 2024-10-10 21:25:37 +03:00
Oleg Kalachev
1b313b4c5d docs: add PX4 parameters in degrees 2024-09-23 14:06:37 +03:00
belyaev-dev
58ec56895f docs: add solution for HTTP/2 network errors on px4-autopilot clone (#509)
* docs(ru): add solution for HTTP/2 network errors on px4-autopilot clone

* docs(en): add solution for HTTP/2 network errors on px4-autopilot clone

* docs(ru): fix typo in px4-autopilot clone note

* docs(ru): fix markdownlint

* docs(en): fix markdownlint

* Fix markdownlint

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2024-09-06 18:31:39 +03:00
Oleg Kalachev
28e89704e6 Update changelog and versions in package.xml 2024-08-08 04:42:35 +03:00
Oleg Kalachev
23da41247f Use pip installer for Python 3.7 2024-08-04 09:18:16 +03:00
Oleg Kalachev
1e45ec143c Add angles package 2024-08-04 07:41:07 +03:00
Oleg Kalachev
26ec42f1e6 Add vision_msgs package 2024-06-18 04:24:24 +03:00
Oleg Kalachev
3edb2f48e0 Add missing stereo_msgs presence test 2024-06-18 04:24:02 +03:00
Oleg Kalachev
3a08085c69 Add width and indent parameters for topic viewer 2024-06-17 05:03:18 +03:00
Oleg Kalachev
4e4dfc1f07 Update checkout action to v4
checkout@v2 is deprecated
2024-06-12 03:37:28 +03:00
Oleg Kalachev
6b0ed144e3 Update editorconfig exceptions 2024-06-09 21:49:41 +03:00
Oleg Kalachev
91bb9d6e38 Change the library for YAML encode in topic viewer
To support displaying newlines in long strings
2024-06-09 21:35:17 +03:00
Oleg Kalachev
e1ff92ee1f Change the recommended directory for autolaunch scripts
Workaround to the issue with importing clover.srv inside the clover/src
directory, as it attempts to import from clover/srv/clover/__init__.py.
2024-06-09 16:16:34 +03:00
Oleg Kalachev
4d2b685b06 blocks: allow using numbers in programs name
Additionally increase maximum program name size
2024-05-25 08:07:56 +03:00
Oleg Kalachev
14c41b21b6 docs: add EKF2_RNG_CTRL parameter value 2024-05-17 23:03:48 +03:00
Oleg Kalachev
70439f172d selfcheck.py: address situation when individual cells voltage is unknown
When length of cell_voltage array is 1, it means that cell voltage is
unknown and overall voltage is reported instead. Consider this situation
gathering the number of cells from PX4 parameters.
2024-04-25 22:20:01 +03:00
Oleg Kalachev
dacaa8ebde docs: minor fixes 2024-04-25 11:12:29 +03:00
Oleg Kalachev
a5309765f1 Some changes to markdownlint config 2024-04-25 11:04:55 +03:00
Oleg Kalachev
2e86ed199a Implement possibility to upload image from repo not named clover 2024-04-25 10:50:02 +03:00
Oleg Kalachev
ad14822684 Fix running aruco_detect without aruco_map enabled
use_map_markers parameter blocked aruco_detect from running
2024-04-25 10:48:20 +03:00
Oleg Kalachev
936efa985d Make clover rosdep file more priority to fix build 2024-04-13 21:32:55 +03:00
Oleg Kalachev
c55e0cb7e1 Fix geographiclib dependency 2024-04-13 19:06:44 +03:00
Oleg Kalachev
b8344dbb84 Add dictionary parameter to aruco.launch 2024-04-13 16:57:29 +03:00
Qandra Si
3b7242f3d6 docs: Add advanced SSH article (SSH keys) (#503)
---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2024-03-12 19:33:55 +03:00
Oleg Kalachev
cfeff0c74d Use installed GeographicLib CMake file
As it's done in mavros https://github.com/mavlink/mavros/pull/1775
2024-03-08 02:45:28 +03:00
Qandra Si
7d022a5af1 docs: improve UART connection to FC section (#502)
* добавил схему подключения fc-uart-rpi, дополнил и уточнил настройки для старой версии px4 (в списке рекомендуемых всё ещё 1.8.2), поправил мелкие опечатки и формулировки в eng-версии, вставил (для общности) изображение не только для fc-uart-rpi, но и для fc-usb-rpi, проверил работоспособность инструкции на своём комплекте с PX4 и прошивкой v1.8.2 (работает с rpi v2.22, и v2.23, и последней v2.24)

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2024-03-04 19:42:04 +03:00
Oleg Kalachev
ebd9c03251 docs: fix broken image in Flysky RC article 2024-02-23 23:17:10 +03:00
Oleg Kalachev
5755300d3a Install image_geometry and dynamic_reconfigure as clover dependencies 2024-02-21 15:04:56 +03:00
Oleg Kalachev
8c5551b00b docs: fix anchor link in snippets 2024-02-13 19:22:02 +03:00
Oleg Kalachev
42c26aa645 docs: add a snippet for moving objects in Gazebo 2024-02-13 15:45:27 +03:00
Qandra Si
f91dc4df71 docs: warnings about usage of v1.10- firmwares and QGC (#500)
* сведения о совместимости QGC v4.2.0 / v4.3.0 и прошивок до /после v1.8, v1.0 и готовящейся к выпуску v1.15

* Remove unintended change

* Edit and shorten warnings

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2024-02-08 19:15:03 +03:00
Oleg Kalachev
e31b69a790 Add possibility to trigger workflows manually 2024-01-22 01:35:52 +03:00
Oleg Kalachev
7251a76315 image: symlink assets instead of copying in documentation to save space 2023-11-04 01:28:00 +03:00
Oleg Kalachev
921e09c392 docs: minor fixes 2023-11-02 17:27:06 +03:00
Oleg Kalachev
9e69bdb01b docs: fix building by new assets size excludes 2023-11-02 06:57:02 +03:00
Oleg Kalachev
50495a9de9 docs: publish mechanical gripper model 2023-11-02 06:52:18 +03:00
Oleg Kalachev
12ccd919a2 docs: fix camera orientation setup example 2023-10-29 14:51:39 +03:00
Oleg Kalachev
f0eacfc0f7 aruco_pose: make dynamic reconfigure generator work with newer versions of OpenCV (#495) 2023-10-14 17:28:37 +03:00
Oleg Kalachev
742d0535c3 docs: add information about EKF2 parameter in PX4 1.14+ 2023-10-11 10:27:05 +03:00
Oleg Kalachev
af1b993e64 led_effect: add led parameter to specify led namespace
When using ROS namespace, subscription to mavros topics is broken
2023-10-11 10:06:18 +03:00
Oleg Kalachev
d3bda9df48 docs: add some additional tests to testing list 2023-10-11 08:30:00 +03:00
Oleg Kalachev
939086362a Run rectify nodelet in tests 2023-10-11 06:40:50 +03:00
Oleg Kalachev
7cf14373b0 main_camera.launch: argument for running image rectification nodelet 2023-10-11 00:51:02 +03:00
Oleg Kalachev
f428dfdb50 image: install stereo-msgs package 2023-10-10 08:46:03 +03:00
Oleg Kalachev
76982dc198 image: install nodelet-topic-tools package 2023-10-10 08:43:20 +03:00
Oleg Kalachev
29f01c25e0 selfcheck.py: support PX4 v1.14 EKF2 aiding parameters change
EKF2_AID_MASK has been split (EKF2_EV_CTRL, EKF2_GPS_CTRL, EKF2_OF_CTRL)
EKF2_HGT_MODE renamed to EKF2_HGT_REF
EKF2_RNG_AID is removed
2023-10-10 08:25:27 +03:00
Oleg Kalachev
7ca0ede1d7 selfcheck.py: cast parameter to int when performing bitwise operations 2023-10-10 07:47:52 +03:00
Oleg Kalachev
c3d87b1608 Update udev rules using data from PX4 sources
Adding Cube Orange, Holybro 6X and many more popular boards
2023-10-10 07:35:42 +03:00
Oleg Kalachev
47901dcff2 selfcheck.py: check udev rules presence and give more useful hint if no mavros state 2023-10-10 06:45:47 +03:00
Oleg Kalachev
9404d4be6d Use image_geometry library in red circle following example 2023-09-20 02:44:26 +03:00
Oleg Kalachev
ad51d86464 docs: add terrain frame to frames list 2023-09-19 15:54:20 +03:00
Oleg Kalachev
9a713057b6 image: add image_geometry package 2023-08-15 17:49:55 +07:00
Oleg Kalachev
7b591d350c aruco_map: fix publishing detected markers count 2023-08-01 17:09:10 +07:00
Oleg Kalachev
2f8915ce31 aruco_map: add ability to pass number of detected markers to Pose covariance field 2023-07-30 14:04:59 +07:00
Oleg Kalachev
6fb84ae584 Remove unneeded line 2023-07-22 13:36:14 +03:00
Oleg Kalachev
bf4f680164 aruco_detect: don't convert image to bgr8 as this is not needed 2023-07-18 17:47:13 +03:00
Oleg Kalachev
c0baf30c96 Move rangefinder frame node out of mavros.launch 2023-07-15 22:05:24 +03:00
Oleg Kalachev
8f2c3b2e55 vpe_publisher: fix code aligning 2023-07-15 20:04:27 +03:00
Oleg Kalachev
6423eb91a2 vpe_publisher: fix calculating the offset in topic mode 2023-07-15 19:15:31 +03:00
Oleg Kalachev
22d7236a47 docs: publish CopterHack-2023 results 2023-05-28 10:05:04 +03:00
Oleg Kalachev
91d33a5961 docs: minor fixes 2023-05-28 09:59:27 +03:00
Oleg Kalachev
2997951371 docs: fix Atena article links to gitbook 2023-05-27 06:26:27 +03:00
Oleg Kalachev
a2ffcf381c docs: workaround for inter-lingual links inarticle 2023-05-27 05:46:49 +03:00
Oleg Kalachev
9aab324f60 docs: enable markdownlint for Atena CopterHack-2023 article 2023-05-23 00:28:54 +03:00
José Carlos Andrade do Nascimento
984fb39b85 docs: Swarm in Blocks 2 (Atena) (CopterHack 2023) (#471)
* Create swarm_in_blocks2.md

* Delete swarm_in_blocks2.md

* Create swarm_in_blocks_2.md

* markdown fixed

* Update swarm_in_blocks_2.md

* markdown first version

* Update swarm_in_blocks_2.md

* markdown fixed

* changing images

* Update swarm_in_blocks_2.md

* Lowercase asset file extension

* Some editing

* linking asstes

* docs: team image link fixed

* removing raw assets from pr

* docs: removing all unused assets

* docs: doc checking unused files

* Reduce logo image size

* Lowercase logo image file

* Rename logo directory

* Fix external images urls, some fix to whitespace

* Add link to CopterHack page in the header

* Add article to summary and CopterHack page

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2023-05-22 23:55:28 +03:00
Oleg Kalachev
3a1a9d486c docs: fix some issues with CopterHack-2023 articles 2023-05-20 08:26:40 +03:00
Oleg Kalachev
55297696d6 docs: add CopterHack articles to summary 2023-05-20 07:49:46 +03:00
Oleg Kalachev
371f244228 docs: update CopterHack teams table 2023-05-20 07:16:49 +03:00
Juli-Shvetsova
ab3e7ac951 docs: CH2023 - Liceu128 (CopterHack-2023) (#473)
* Create liceu128.md

* Update liceu128.md

* Update liceu128.md

* Update liceu128.md

* Edit article

* final liceu128.md

* Edit article

---------

Co-authored-by: микемка <mikemka@vk.com>
Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2023-05-20 07:05:52 +03:00
Max
cdd6195f0b docs: Advanced clover simulation platform (CopterHack-2023) (#472)
* Create advanced_clover_simulator_platform.md

* Write better description

* AdvancedClover article finished

* Some editing

* Reduce images size

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2023-05-20 07:04:55 +03:00
ssmith-81
c9b015148f docs: MoCap-Clover (CopterHack-2023) (#470)
* Create MoCap-Clover

* Rename MoCap-Clover to mocap_clover.md

* Create mocap_logo

* Add files via upload

* Update mocap_clover.md

* Update mocap_clover.md

update

* Update mocap_clover.md

* Update mocap_clover.md

* Add files via upload

* Update mocap_clover.md

* Update mocap_clover.md

* Add files via upload

* Update mocap_clover.md

* Update mocap_clover.md

* Update mocap_clover.md

* Update mocap_clover.md

* Add files via upload

* Update mocap_clover.md

* Add files via upload

* Update mocap_clover.md

* Add files via upload

* Update mocap_clover.md

* Update mocap_clover.md

* Update mocap_clover.md

* Edit article

* Remove unneeded asset

* Reduce sizes of some assets

* Update mocap_clover.md

* Update mocap_clover.md

* Delete docs/assets/mocap_clover directory

* Fix again headers anchors

* Create test

* Add files via upload

* Update mocap_clover.md

* Add files via upload

* Delete test

* Update mocap_clover.md

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2023-05-20 07:00:39 +03:00
Lukerrr
2054472c23 docs: C305: Radio-Navigation System (CopterHack-2023) (#468)
* Create nav-beacon

* Update and rename article

* Fixed article issues

* Update nav-beacon.md

* Update nav-beacon.md

* Update nav-beacon.md

* Update nav-beacon.md

* Update nav-beacon.md

* Update nav-beacon.md

* Edit article

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2023-05-20 06:58:51 +03:00
DJS Phoenix
b1084f99b9 docs: DJS PHOENIX (CopterHack-2023) (#462)
* Create djs_phoenix_chetak.md

* Update djs_phoenix_chetak.md

* Update djs_phoenix_chetak.md

* Update djs_phoenix_chetak.md

* Edit article

* Move English article to en/ subfolder

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2023-05-20 06:58:11 +03:00
Mikhail Kuznetsov
c5f405c4d9 docs: Clover Cloud Platform CopterHack 2023 (#455)
* Create clover-cloud-platform.md

* md fix

* fix link to repositories

* Update clover-cloud-platform.md

* Editing

---------

Co-authored-by: Oleg Kalachev <okalachev@gmail.com>
2023-05-20 06:57:23 +03:00
Oleg Kalachev
099d39d42d docs: some updates to version warnings 2023-05-20 04:43:32 +03:00
Oleg Kalachev
c9035790f2 image: loose required Python libraries versions, add missing validation 2023-04-17 22:54:18 +03:00
Oleg Kalachev
95da57fea1 docs: fix obsolete link to Ubuntu Focal desktop image 2023-04-12 21:32:38 +03:00
Oleg Kalachev
ad0138cd26 Merge pull request #488 from CopterExpress/v0.24-release
V0.24 release changes
2023-04-12 02:04:59 +03:00
Oleg Kalachev
d6101dc0a3 ci: add secret variable to temporarily freeze updating docs website 2023-04-12 01:34:34 +03:00
Oleg Kalachev
cbba62d165 blocks: add block for reading RC values 2023-04-11 19:35:00 +03:00
Oleg Kalachev
28ddbbcdf9 docs: add version warnings to camera articles 2023-04-11 19:21:53 +03:00
Oleg Kalachev
cac6b59a56 Set the version to 0.24.0 in ROS packages 2023-04-11 15:28:38 +03:00
Oleg Kalachev
c82490a0c1 Set terrain_frame_mode to range by default addressing CopterExpress/clover_vm#14 2023-04-11 15:27:39 +03:00
Oleg Kalachev
808726b4b7 Try to tix the build 2023-04-11 13:33:35 +03:00
Oleg Kalachev
19fde7095f simple_offboard: add test for land service 2023-04-11 01:40:58 +03:00
Oleg Kalachev
5e9f442996 simple_offboard: add terrain_frame_mode parameter, CopterExpress/clover_vm#14
`altitude` mode takes the current altitude from the estimator
`range` mode takes the current altitude from a simple range topic
2023-04-11 01:28:38 +03:00
Oleg Kalachev
68903373b0 simple_offboard: reset stored setpoint on auto_arm only if needed to be armed
CopterExpress/clover_vm#13
2023-04-11 00:57:43 +03:00
Oleg Kalachev
ae05710a37 blocks: fix set_yaw block implementation (#487) 2023-03-27 19:18:21 +03:00
Oleg Kalachev
4c576ba5d4 builder: print largest installed packages 2023-02-22 00:42:06 +03:00
Oleg Kalachev
ffd8b98e53 Merge branch 'master' into v0.24-release 2023-02-07 10:06:27 +03:00
Oleg Kalachev
69deeae32f blocks: document ~print topic of the main node 2023-02-07 10:06:09 +03:00
Oleg Kalachev
df66deb32c docs: add running flight autotests to testing plan 2023-02-07 10:03:41 +03:00
Oleg Kalachev
87a51221bc docs: update documentation for autonomous flights 2023-02-07 10:02:02 +03:00
Oleg Kalachev
08bda736e9 aruco_detect: fix drawing markers axis 2023-01-26 18:16:24 +03:00
Oleg Kalachev
cb2850b1d4 docs: update CopterHack-2023 project link 2023-01-12 00:45:27 +03:00
145 changed files with 2878 additions and 590 deletions

View File

@@ -7,23 +7,24 @@ on:
branches: [ master ] branches: [ master ]
release: release:
types: [ created ] types: [ created ]
workflow_dispatch:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Build image - name: Build image
run: | run: |
docker run --privileged --rm -v /dev:/dev -v $(pwd):/builder/repo -e TRAVIS_TAG="${{ github.event.release.tag_name }}" sfalexrog/img-tool:qemu-update docker run --privileged --rm -v /dev:/dev -v $(pwd):/builder/repo -e TRAVIS_TAG="${{ github.event.release.tag_name }}" sfalexrog/img-tool:qemu-update
- name: Compress image - name: Compress image
run: | run: |
cd images && sudo chmod -R 777 . && zip -9 $(echo clover_*).zip clover_* && ls -l . && unzip -l clover_*.zip cd images && sudo chmod -R 777 . && zip -9 $(echo *_*).zip *_* && ls -l . && unzip -l *_*.zip
- name: Upload image - name: Upload image
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}
with: with:
files: images/clover_*.zip files: images/*_*.zip
prerelease: true prerelease: true
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -5,12 +5,13 @@ on:
branches: [ '*' ] branches: [ '*' ]
pull_request: pull_request:
branches: [ master ] branches: [ master ]
workflow_dispatch:
jobs: jobs:
# melodic: # melodic:
# runs-on: ubuntu-latest # runs-on: ubuntu-latest
# steps: # steps:
# - uses: actions/checkout@v2 # - uses: actions/checkout@v4
# - name: Native Melodic build # - name: Native Melodic build
# run: | # run: |
# docker run --rm -v $(pwd):/root/catkin_ws/src/clover ros:melodic-ros-base /root/catkin_ws/src/clover/builder/standalone-install.sh # docker run --rm -v $(pwd):/root/catkin_ws/src/clover ros:melodic-ros-base /root/catkin_ws/src/clover/builder/standalone-install.sh
@@ -22,7 +23,7 @@ jobs:
working-directory: catkin_ws working-directory: catkin_ws
shell: bash shell: bash
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with: with:
path: catkin_ws/src/clover path: catkin_ws/src/clover
- name: Install requirements - name: Install requirements
@@ -44,7 +45,7 @@ jobs:
fakeroot debian/rules binary fakeroot debian/rules binary
cd - cd -
done done
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
with: with:
name: debian-packages name: debian-packages
path: catkin_ws/src/clover/*.deb path: catkin_ws/src/clover/*.deb

View File

@@ -5,6 +5,7 @@ on:
branches: [ '*' ] branches: [ '*' ]
pull_request: pull_request:
branches: [ '*' ] branches: [ '*' ]
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@@ -19,9 +20,9 @@ jobs:
docs: docs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v1 uses: actions/setup-node@v4
with: { node-version: '10' } with: { node-version: '10' }
- name: Setup tools - name: Setup tools
run: | run: |
@@ -56,16 +57,16 @@ jobs:
rm _book/clover_ru.pdf && mv _book/clover_ru_compressed.pdf _book/clover_ru.pdf rm _book/clover_ru.pdf && mv _book/clover_ru_compressed.pdf _book/clover_ru.pdf
rm _book/clover_en.pdf && mv _book/clover_en_compressed.pdf _book/clover_en.pdf rm _book/clover_en.pdf && mv _book/clover_en_compressed.pdf _book/clover_en.pdf
ls -lah _book/clover*.pdf ls -lah _book/clover*.pdf
echo '::set-output name=GITBOOK_PDF_OK::1' echo 'GITBOOK_PDF_OK=1' >> "$GITHUB_OUTPUT"
- name: Download older PDFs - name: Download older PDFs
if: ${{ !steps.generate-pdf.outputs.GITBOOK_PDF_OK }} if: ${{ !steps.generate-pdf.outputs.GITBOOK_PDF_OK }}
run: | run: |
rm -f _book/clover*.pdf rm -f _book/clover*.pdf
wget --no-verbose https://clover.coex.tech/clover_ru.pdf -P _book/ wget --no-verbose https://clovercoex.tech/clover_ru.pdf -P _book/
wget --no-verbose https://clover.coex.tech/clover_en.pdf -P _book/ wget --no-verbose https://clovercoex.tech/clover_en.pdf -P _book/
- name: Upload artifact - name: Upload artifact
# if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} # if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
uses: actions/upload-pages-artifact@v1 uses: actions/upload-pages-artifact@v3
with: with:
path: _book path: _book
@@ -81,5 +82,8 @@ jobs:
needs: docs needs: docs
steps: steps:
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
env:
FREEZE_DOCS: ${{ secrets.FREEZE_DOCS }}
if: ${{ !env.FREEZE_DOCS }}
id: deployment id: deployment
uses: actions/deploy-pages@v1 uses: actions/deploy-pages@v4

View File

@@ -5,14 +5,15 @@ on:
branches: [ '*' ] branches: [ '*' ]
pull_request: pull_request:
branches: [ master ] branches: [ master ]
workflow_dispatch:
jobs: jobs:
editorconfig: editorconfig:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: .editorconfig Linter - name: .editorconfig Linter
run: | run: |
wget --no-verbose https://github.com/okalachev/editorconfig-checker/releases/download/1.2.1-disable-spaces-amount/ec-linux-amd64 wget --no-verbose https://github.com/okalachev/editorconfig-checker/releases/download/1.2.1-disable-spaces-amount/ec-linux-amd64
chmod +x ec-linux-amd64 chmod +x ec-linux-amd64
./ec-linux-amd64 -spaces-after-tabs -e "roslib.js|ros3d.js|eventemitter2.js|json-to-pretty-yaml.js|draw.cpp|BinUtils.swift|\.idea|apps/android/app|blockly/|clover_blocks/programs/|highlight/|python.js|Assets.xcassets|test_parser_pass.txt|test_node_failure.txt|aruco_pose/vendor|\.stl|\.dxf|\.dae|\.material" ./ec-linux-amd64 -spaces-after-tabs -e "roslib.js|ros3d.js|eventemitter2.js|yaml.js|draw.cpp|BinUtils.swift|\.idea|apps/android/app|blockly/|clover_blocks/programs/|highlight/|python.js|Assets.xcassets|test_parser_pass.txt|test_node_failure.txt|aruco_pose/vendor|\.stl|\.dxf|\.dae|\.material"

View File

@@ -113,7 +113,9 @@
"VMware", "VMware",
"DuoCam" "DuoCam"
], ],
"code_blocks": false "code_blocks": false,
"html_elements": false
}, },
"MD045": false "MD045": false,
"MD051": false
} }

View File

@@ -6,7 +6,7 @@ Clover is an open source [ROS](https://www.ros.org)-based framework, providing u
COEX Clover Drone is an educational programmable drone kit, suited perfectly for running clover software. The kit is shipped unassembled and includes Pixracer-compatible autopilot running PX4 firmware, Raspberry Pi 4 as a companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices. Batteries included. COEX Clover Drone is an educational programmable drone kit, suited perfectly for running clover software. The kit is shipped unassembled and includes Pixracer-compatible autopilot running PX4 firmware, Raspberry Pi 4 as a companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices. Batteries included.
The main documentation is available at [https://clover.coex.tech](https://clover.coex.tech/). Official website: [coex.tech/clover](https://coex.tech/clover). The main documentation is available at [https://clovercoex.tech](https://clovercoex.tech/).
[__Support us on Kickstarter!__](https://www.kickstarter.com/projects/copterexpress/cloverdrone) [__Support us on Kickstarter!__](https://www.kickstarter.com/projects/copterexpress/cloverdrone)
@@ -30,11 +30,11 @@ Image features:
* Configured networking * Configured networking
* OpenCV * OpenCV
* [`mavros`](http://wiki.ros.org/mavros) * [`mavros`](http://wiki.ros.org/mavros)
* Periphery drivers for ROS ([GPIO](https://clover.coex.tech/en/gpio.html), [LED strip](https://clover.coex.tech/en/leds.html), etc) * Periphery drivers for ROS ([GPIO](https://clovercoex.tech/en/gpio.html), [LED strip](https://clovercoex.tech/en/leds.html), etc)
* `aruco_pose` package for marker-assisted navigation * `aruco_pose` package for marker-assisted navigation
* `clover` package for autonomous drone control * `clover` package for autonomous drone control
API description for autonomous flights is available [on GitBook](https://clover.coex.tech/en/simple_offboard.html). API description for autonomous flights is available [on GitBook](https://clovercoex.tech/en/simple_offboard.html).
For manual package installation and running see [`clover` package documentation](clover/README.md). For manual package installation and running see [`clover` package documentation](clover/README.md).

View File

@@ -4,7 +4,10 @@ PACKAGE = "aruco_pose"
from dynamic_reconfigure.parameter_generator_catkin import * from dynamic_reconfigure.parameter_generator_catkin import *
import cv2.aruco import cv2.aruco
p = cv2.aruco.DetectorParameters_create() try:
p = cv2.aruco.DetectorParameters_create()
except AttributeError:
p = cv2.aruco.DetectorParameters()
gen = ParameterGenerator() gen = ParameterGenerator()

View File

@@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<package format="3"> <package format="3">
<name>aruco_pose</name> <name>aruco_pose</name>
<version>0.23.0</version> <version>0.25.0</version>
<description>Positioning with ArUco markers</description> <description>Positioning with ArUco markers</description>
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer> <maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>

View File

@@ -50,6 +50,7 @@
#include <aruco_pose/DetectorConfig.h> #include <aruco_pose/DetectorConfig.h>
#include <aruco_pose/SetMarkers.h> #include <aruco_pose/SetMarkers.h>
#include "draw.h"
#include "utils.h" #include "utils.h"
#include <memory> #include <memory>
#include <functional> #include <functional>
@@ -139,7 +140,7 @@ private:
if (!enabled_) return; if (!enabled_) return;
if (waiting_for_map_) return; if (waiting_for_map_) return;
Mat image = cv_bridge::toCvShare(msg, "bgr8")->image; Mat image = cv_bridge::toCvShare(msg)->image;
vector<int> ids; vector<int> ids;
vector<vector<cv::Point2f>> corners, rejected; vector<vector<cv::Point2f>> corners, rejected;
@@ -264,8 +265,7 @@ private:
cv::aruco::drawDetectedMarkers(debug, corners, ids); // draw markers cv::aruco::drawDetectedMarkers(debug, corners, ids); // draw markers
if (estimate_poses_) if (estimate_poses_)
for (unsigned int i = 0; i < ids.size(); i++) for (unsigned int i = 0; i < ids.size(); i++)
cv::aruco::drawAxis(debug, camera_matrix_, dist_coeffs_, _drawAxis(debug, camera_matrix_, dist_coeffs_, rvecs[i], tvecs[i], getMarkerLength(ids[i]));
rvecs[i], tvecs[i], getMarkerLength(ids[i]));
cv_bridge::CvImage out_msg; cv_bridge::CvImage out_msg;
out_msg.header.frame_id = msg->header.frame_id; out_msg.header.frame_id = msg->header.frame_id;

View File

@@ -83,7 +83,7 @@ private:
visualization_msgs::MarkerArray vis_array_; visualization_msgs::MarkerArray vis_array_;
std::string known_vertical_, map_, markers_frame_, markers_parent_frame_; std::string known_vertical_, map_, markers_frame_, markers_parent_frame_;
int image_width_, image_height_, image_margin_; int image_width_, image_height_, image_margin_;
bool flip_vertical_, auto_flip_, image_axis_; bool flip_vertical_, auto_flip_, image_axis_, put_markers_count_to_covariance_;
public: public:
virtual void onInit() virtual void onInit()
@@ -111,6 +111,7 @@ public:
image_height_ = nh_priv_.param("image_height", 2000); image_height_ = nh_priv_.param("image_height", 2000);
image_margin_ = nh_priv_.param("image_margin", 200); image_margin_ = nh_priv_.param("image_margin", 200);
image_axis_ = nh_priv_.param("image_axis", true); image_axis_ = nh_priv_.param("image_axis", true);
put_markers_count_to_covariance_ = nh_priv_.param("put_markers_count_to_covariance", false);
markers_parent_frame_ = nh_priv_.param<std::string>("markers/frame_id", transform_.child_frame_id); 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", ""); markers_frame_ = nh_priv_.param<std::string>("markers/child_frame_id_prefix", "");
@@ -178,6 +179,20 @@ public:
corners.push_back(marker_corners); corners.push_back(marker_corners);
} }
if (put_markers_count_to_covariance_) {
// HACK: pass markers count using covariance field
int valid_markers = 0;
for (auto const &marker : markers->markers) {
for (auto const &board_marker : board_->ids) {
if (board_marker == marker.id) {
valid_markers++;
break;
}
}
}
pose_.pose.covariance[0] = valid_markers;
}
if (known_vertical_.empty()) { if (known_vertical_.empty()) {
// simple estimation // simple estimation
valid = cv::aruco::estimatePoseBoard(corners, ids, board_, camera_matrix_, dist_coeffs_, valid = cv::aruco::estimatePoseBoard(corners, ids, board_, camera_matrix_, dist_coeffs_,

View File

@@ -29,7 +29,7 @@
"blank": true "blank": true
}, },
"sitemap": { "sitemap": {
"hostname": "https://clover.coex.tech" "hostname": "https://clovercoex.tech"
}, },
"toolbar": { "toolbar": {
"buttons": "buttons":

View File

@@ -16,3 +16,726 @@ web_video_server:
ws281x: ws281x:
debian: debian:
buster: [ros-noetic-ws281x] buster: [ros-noetic-ws281x]
catkin:
debian:
buster: [ros-noetic-catkin]
genmsg:
debian:
buster: [ros-noetic-genmsg]
gencpp:
debian:
buster: [ros-noetic-gencpp]
geneus:
debian:
buster: [ros-noetic-geneus]
genlisp:
debian:
buster: [ros-noetic-genlisp]
gennodejs:
debian:
buster: [ros-noetic-gennodejs]
genpy:
debian:
buster: [ros-noetic-genpy]
bond_core:
debian:
buster: [ros-noetic-bond-core]
cmake_modules:
debian:
buster: [ros-noetic-cmake-modules]
class_loader:
debian:
buster: [ros-noetic-class-loader]
common_msgs:
debian:
buster: [ros-noetic-common-msgs]
common_tutorials:
debian:
buster: [ros-noetic-common-tutorials]
cpp_common:
debian:
buster: [ros-noetic-cpp-common]
desktop:
debian:
buster: [ros-noetic-desktop]
diagnostics:
debian:
buster: [ros-noetic-diagnostics]
executive_smach:
debian:
buster: [ros-noetic-executive-smach]
geometry:
debian:
buster: [ros-noetic-geometry]
geometry_tutorials:
debian:
buster: [ros-noetic-geometry-tutorials]
gl_dependency:
debian:
buster: [ros-noetic-gl-dependency]
image_common:
debian:
buster: [ros-noetic-image-common]
image_pipeline:
debian:
buster: [ros-noetic-image-pipeline]
image_transport_plugins:
debian:
buster: [ros-noetic-image-transport-plugins]
laser_pipeline:
debian:
buster: [ros-noetic-laser-pipeline]
mavlink:
debian:
buster: [ros-noetic-mavlink]
media_export:
debian:
buster: [ros-noetic-media-export]
message_generation:
debian:
buster: [ros-noetic-message-generation]
message_runtime:
debian:
buster: [ros-noetic-message-runtime]
mk:
debian:
buster: [ros-noetic-mk]
nodelet_core:
debian:
buster: [ros-noetic-nodelet-core]
orocos_kdl:
debian:
buster: [ros-noetic-orocos-kdl]
perception:
debian:
buster: [ros-noetic-perception]
perception_pcl:
debian:
buster: [ros-noetic-perception-pcl]
python_orocos_kdl:
debian:
buster: [ros-noetic-python-orocos-kdl]
qt_dotgraph:
debian:
buster: [ros-noetic-qt-dotgraph]
qt_gui:
debian:
buster: [ros-noetic-qt-gui]
qt_gui_py_common:
debian:
buster: [ros-noetic-qt-gui-py-common]
qwt_dependency:
debian:
buster: [ros-noetic-qwt-dependency]
robot:
debian:
buster: [ros-noetic-robot]
ros:
debian:
buster: [ros-noetic-ros]
ros_base:
debian:
buster: [ros-noetic-ros-base]
ros_comm:
debian:
buster: [ros-noetic-ros-comm]
ros_core:
debian:
buster: [ros-noetic-ros-core]
ros_environment:
debian:
buster: [ros-noetic-ros-environment]
ros_tutorials:
debian:
buster: [ros-noetic-ros-tutorials]
rosapi:
debian:
buster: [ros-noetic-rosapi]
rosbag_migration_rule:
debian:
buster: [ros-noetic-rosbag-migration-rule]
rosbash:
debian:
buster: [ros-noetic-rosbash]
rosboost_cfg:
debian:
buster: [ros-noetic-rosboost-cfg]
rosbridge_server:
debian:
buster: [ros-noetic-rosbridge-server]
rosbridge_suite:
debian:
buster: [ros-noetic-rosbridge-suite]
rosbuild:
debian:
buster: [ros-noetic-rosbuild]
rosclean:
debian:
buster: [ros-noetic-rosclean]
roscpp_core:
debian:
buster: [ros-noetic-roscpp-core]
roscpp_traits:
debian:
buster: [ros-noetic-roscpp-traits]
roscreate:
debian:
buster: [ros-noetic-roscreate]
rosgraph:
debian:
buster: [ros-noetic-rosgraph]
roslang:
debian:
buster: [ros-noetic-roslang]
roslint:
debian:
buster: [ros-noetic-roslint]
roslisp:
debian:
buster: [ros-noetic-roslisp]
rosmake:
debian:
buster: [ros-noetic-rosmake]
rosmaster:
debian:
buster: [ros-noetic-rosmaster]
rospack:
debian:
buster: [ros-noetic-rospack]
roslib:
debian:
buster: [ros-noetic-roslib]
rosparam:
debian:
buster: [ros-noetic-rosparam]
rospy:
debian:
buster: [ros-noetic-rospy]
rosserial:
debian:
buster: [ros-noetic-rosserial]
rosserial_msgs:
debian:
buster: [ros-noetic-rosserial-msgs]
rosserial_python:
debian:
buster: [ros-noetic-rosserial-python]
rosservice:
debian:
buster: [ros-noetic-rosservice]
rostime:
debian:
buster: [ros-noetic-rostime]
roscpp_serialization:
debian:
buster: [ros-noetic-roscpp-serialization]
python_qt_binding:
debian:
buster: [ros-noetic-python-qt-binding]
roslaunch:
debian:
buster: [ros-noetic-roslaunch]
rosunit:
debian:
buster: [ros-noetic-rosunit]
angles:
debian:
buster: [ros-noetic-angles]
libmavconn:
debian:
buster: [ros-noetic-libmavconn]
rosconsole:
debian:
buster: [ros-noetic-rosconsole]
pluginlib:
debian:
buster: [ros-noetic-pluginlib]
qt_gui_cpp:
debian:
buster: [ros-noetic-qt-gui-cpp]
resource_retriever:
debian:
buster: [ros-noetic-resource-retriever]
rosconsole_bridge:
debian:
buster: [ros-noetic-rosconsole-bridge]
roslz4:
debian:
buster: [ros-noetic-roslz4]
rosserial_client:
debian:
buster: [ros-noetic-rosserial-client]
rostest:
debian:
buster: [ros-noetic-rostest]
rqt_action:
debian:
buster: [ros-noetic-rqt-action]
rqt_bag:
debian:
buster: [ros-noetic-rqt-bag]
rqt_bag_plugins:
debian:
buster: [ros-noetic-rqt-bag-plugins]
rqt_common_plugins:
debian:
buster: [ros-noetic-rqt-common-plugins]
rqt_console:
debian:
buster: [ros-noetic-rqt-console]
rqt_dep:
debian:
buster: [ros-noetic-rqt-dep]
rqt_graph:
debian:
buster: [ros-noetic-rqt-graph]
rqt_gui:
debian:
buster: [ros-noetic-rqt-gui]
rqt_logger_level:
debian:
buster: [ros-noetic-rqt-logger-level]
rqt_moveit:
debian:
buster: [ros-noetic-rqt-moveit]
rqt_msg:
debian:
buster: [ros-noetic-rqt-msg]
rqt_nav_view:
debian:
buster: [ros-noetic-rqt-nav-view]
rqt_plot:
debian:
buster: [ros-noetic-rqt-plot]
rqt_pose_view:
debian:
buster: [ros-noetic-rqt-pose-view]
rqt_publisher:
debian:
buster: [ros-noetic-rqt-publisher]
rqt_py_console:
debian:
buster: [ros-noetic-rqt-py-console]
rqt_reconfigure:
debian:
buster: [ros-noetic-rqt-reconfigure]
rqt_robot_dashboard:
debian:
buster: [ros-noetic-rqt-robot-dashboard]
rqt_robot_monitor:
debian:
buster: [ros-noetic-rqt-robot-monitor]
rqt_robot_plugins:
debian:
buster: [ros-noetic-rqt-robot-plugins]
rqt_robot_steering:
debian:
buster: [ros-noetic-rqt-robot-steering]
rqt_runtime_monitor:
debian:
buster: [ros-noetic-rqt-runtime-monitor]
rqt_service_caller:
debian:
buster: [ros-noetic-rqt-service-caller]
rqt_shell:
debian:
buster: [ros-noetic-rqt-shell]
rqt_srv:
debian:
buster: [ros-noetic-rqt-srv]
rqt_tf_tree:
debian:
buster: [ros-noetic-rqt-tf-tree]
rqt_top:
debian:
buster: [ros-noetic-rqt-top]
rqt_topic:
debian:
buster: [ros-noetic-rqt-topic]
rqt_web:
debian:
buster: [ros-noetic-rqt-web]
smach:
debian:
buster: [ros-noetic-smach]
smclib:
debian:
buster: [ros-noetic-smclib]
std_msgs:
debian:
buster: [ros-noetic-std-msgs]
actionlib_msgs:
debian:
buster: [ros-noetic-actionlib-msgs]
bond:
debian:
buster: [ros-noetic-bond]
diagnostic_msgs:
debian:
buster: [ros-noetic-diagnostic-msgs]
geometry_msgs:
debian:
buster: [ros-noetic-geometry-msgs]
eigen_conversions:
debian:
buster: [ros-noetic-eigen-conversions]
kdl_conversions:
debian:
buster: [ros-noetic-kdl-conversions]
nav_msgs:
debian:
buster: [ros-noetic-nav-msgs]
rosbridge_msgs:
debian:
buster: [ros-noetic-rosbridge-msgs]
rosgraph_msgs:
debian:
buster: [ros-noetic-rosgraph-msgs]
rosmsg:
debian:
buster: [ros-noetic-rosmsg]
rqt_py_common:
debian:
buster: [ros-noetic-rqt-py-common]
shape_msgs:
debian:
buster: [ros-noetic-shape-msgs]
smach_msgs:
debian:
buster: [ros-noetic-smach-msgs]
std_srvs:
debian:
buster: [ros-noetic-std-srvs]
tf2_msgs:
debian:
buster: [ros-noetic-tf2-msgs]
tf2:
debian:
buster: [ros-noetic-tf2]
tf2_eigen:
debian:
buster: [ros-noetic-tf2-eigen]
trajectory_msgs:
debian:
buster: [ros-noetic-trajectory-msgs]
control_msgs:
debian:
buster: [ros-noetic-control-msgs]
urdf_parser_plugin:
debian:
buster: [ros-noetic-urdf-parser-plugin]
urdfdom_py:
debian:
buster: [ros-noetic-urdfdom-py]
uuid_msgs:
debian:
buster: [ros-noetic-uuid-msgs]
geographic_msgs:
debian:
buster: [ros-noetic-geographic-msgs]
vision_opencv:
debian:
buster: [ros-noetic-vision-opencv]
visualization_msgs:
debian:
buster: [ros-noetic-visualization-msgs]
visualization_tutorials:
debian:
buster: [ros-noetic-visualization-tutorials]
viz:
debian:
buster: [ros-noetic-viz]
webkit_dependency:
debian:
buster: [ros-noetic-webkit-dependency]
xmlrpcpp:
debian:
buster: [ros-noetic-xmlrpcpp]
roscpp:
debian:
buster: [ros-noetic-roscpp]
bondcpp:
debian:
buster: [ros-noetic-bondcpp]
bondpy:
debian:
buster: [ros-noetic-bondpy]
nodelet:
debian:
buster: [ros-noetic-nodelet]
nodelet_tutorial_math:
debian:
buster: [ros-noetic-nodelet-tutorial-math]
pluginlib_tutorials:
debian:
buster: [ros-noetic-pluginlib-tutorials]
roscpp_tutorials:
debian:
buster: [ros-noetic-roscpp-tutorials]
rosout:
debian:
buster: [ros-noetic-rosout]
camera_calibration:
debian:
buster: [ros-noetic-camera-calibration]
diagnostic_aggregator:
debian:
buster: [ros-noetic-diagnostic-aggregator]
diagnostic_updater:
debian:
buster: [ros-noetic-diagnostic-updater]
diagnostic_common_diagnostics:
debian:
buster: [ros-noetic-diagnostic-common-diagnostics]
dynamic_reconfigure:
debian:
buster: [ros-noetic-dynamic-reconfigure]
filters:
debian:
buster: [ros-noetic-filters]
joint_state_publisher:
debian:
buster: [ros-noetic-joint-state-publisher]
message_filters:
debian:
buster: [ros-noetic-message-filters]
rosauth:
debian:
buster: [ros-noetic-rosauth]
rosbag_storage:
debian:
buster: [ros-noetic-rosbag-storage]
rosnode:
debian:
buster: [ros-noetic-rosnode]
rospy_tutorials:
debian:
buster: [ros-noetic-rospy-tutorials]
rosshow:
debian:
buster: [ros-noetic-rosshow]
rostopic:
debian:
buster: [ros-noetic-rostopic]
rqt_gui_cpp:
debian:
buster: [ros-noetic-rqt-gui-cpp]
rqt_gui_py:
debian:
buster: [ros-noetic-rqt-gui-py]
self_test:
debian:
buster: [ros-noetic-self-test]
smach_ros:
debian:
buster: [ros-noetic-smach-ros]
tf2_py:
debian:
buster: [ros-noetic-tf2-py]
topic_tools:
debian:
buster: [ros-noetic-topic-tools]
rosbag:
debian:
buster: [ros-noetic-rosbag]
actionlib:
debian:
buster: [ros-noetic-actionlib]
actionlib_tutorials:
debian:
buster: [ros-noetic-actionlib-tutorials]
diagnostic_analysis:
debian:
buster: [ros-noetic-diagnostic-analysis]
nodelet_topic_tools:
debian:
buster: [ros-noetic-nodelet-topic-tools]
roswtf:
debian:
buster: [ros-noetic-roswtf]
rqt_launch:
debian:
buster: [ros-noetic-rqt-launch]
sensor_msgs:
debian:
buster: [ros-noetic-sensor-msgs]
camera_calibration_parsers:
debian:
buster: [ros-noetic-camera-calibration-parsers]
cv_bridge:
debian:
buster: [ros-noetic-cv-bridge]
image_geometry:
debian:
buster: [ros-noetic-image-geometry]
image_transport:
debian:
buster: [ros-noetic-image-transport]
camera_info_manager:
debian:
buster: [ros-noetic-camera-info-manager]
compressed_depth_image_transport:
debian:
buster: [ros-noetic-compressed-depth-image-transport]
compressed_image_transport:
debian:
buster: [ros-noetic-compressed-image-transport]
cv_camera:
debian:
buster: [ros-noetic-cv-camera]
image_proc:
debian:
buster: [ros-noetic-image-proc]
image_publisher:
debian:
buster: [ros-noetic-image-publisher]
map_msgs:
debian:
buster: [ros-noetic-map-msgs]
mavros_msgs:
debian:
buster: [ros-noetic-mavros-msgs]
pcl_msgs:
debian:
buster: [ros-noetic-pcl-msgs]
pcl_conversions:
debian:
buster: [ros-noetic-pcl-conversions]
polled_camera:
debian:
buster: [ros-noetic-polled-camera]
rqt_image_view:
debian:
buster: [ros-noetic-rqt-image-view]
stereo_msgs:
debian:
buster: [ros-noetic-stereo-msgs]
image_view:
debian:
buster: [ros-noetic-image-view]
rosbridge_library:
debian:
buster: [ros-noetic-rosbridge-library]
stereo_image_proc:
debian:
buster: [ros-noetic-stereo-image-proc]
tf2_ros:
debian:
buster: [ros-noetic-tf2-ros]
depth_image_proc:
debian:
buster: [ros-noetic-depth-image-proc]
mavros:
debian:
buster: [ros-noetic-mavros]
tf:
debian:
buster: [ros-noetic-tf]
interactive_markers:
debian:
buster: [ros-noetic-interactive-markers]
interactive_marker_tutorials:
debian:
buster: [ros-noetic-interactive-marker-tutorials]
laser_geometry:
debian:
buster: [ros-noetic-laser-geometry]
laser_assembler:
debian:
buster: [ros-noetic-laser-assembler]
laser_filters:
debian:
buster: [ros-noetic-laser-filters]
pcl_ros:
debian:
buster: [ros-noetic-pcl-ros]
tf2_geometry_msgs:
debian:
buster: [ros-noetic-tf2-geometry-msgs]
image_rotate:
debian:
buster: [ros-noetic-image-rotate]
tf2_kdl:
debian:
buster: [ros-noetic-tf2-kdl]
tf2_web_republisher:
debian:
buster: [ros-noetic-tf2-web-republisher]
tf_conversions:
debian:
buster: [ros-noetic-tf-conversions]
theora_image_transport:
debian:
buster: [ros-noetic-theora-image-transport]
turtlesim:
debian:
buster: [ros-noetic-turtlesim]
turtle_actionlib:
debian:
buster: [ros-noetic-turtle-actionlib]
turtle_tf:
debian:
buster: [ros-noetic-turtle-tf]
turtle_tf2:
debian:
buster: [ros-noetic-turtle-tf2]
urdf:
debian:
buster: [ros-noetic-urdf]
kdl_parser:
debian:
buster: [ros-noetic-kdl-parser]
kdl_parser_py:
debian:
buster: [ros-noetic-kdl-parser-py]
mavros_extras:
debian:
buster: [ros-noetic-mavros-extras]
robot_state_publisher:
debian:
buster: [ros-noetic-robot-state-publisher]
rviz:
debian:
buster: [ros-noetic-rviz]
librviz_tutorial:
debian:
buster: [ros-noetic-librviz-tutorial]
rqt_rviz:
debian:
buster: [ros-noetic-rqt-rviz]
rviz_plugin_tutorials:
debian:
buster: [ros-noetic-rviz-plugin-tutorials]
rviz_python_tutorial:
debian:
buster: [ros-noetic-rviz-python-tutorial]
urdf_tutorial:
debian:
buster: [ros-noetic-urdf-tutorial]
usb_cam:
debian:
buster: [ros-noetic-usb-cam]
visualization_marker_tutorials:
debian:
buster: [ros-noetic-visualization-marker-tutorials]
vl53l1x:
debian:
buster: [ros-noetic-vl53l1x]
xacro:
debian:
buster: [ros-noetic-xacro]
ddynamic_reconfigure:
debian:
buster: [ros-noetic-ddynamic-reconfigure]
librealsense2:
debian:
buster: [ros-noetic-librealsense2]
realsense2_camera:
debian:
buster: [ros-noetic-realsense2-camera]
realsense2_description:
debian:
buster: [ros-noetic-realsense2-description]
geographiclib:
debian:
buster: [libgeographic-dev]

View File

@@ -49,7 +49,7 @@ echo_stamp() {
my_travis_retry() { my_travis_retry() {
local result=0 local result=0
local count=1 local count=1
local max_count=50 local max_count=5
while [ $count -le $max_count ]; do while [ $count -le $max_count ]; do
[ $result -ne 0 ] && { [ $result -ne 0 ] && {
echo -e "\nThe command \"$@\" failed. Retrying, $count of $max_count.\n" >&2 echo -e "\nThe command \"$@\" failed. Retrying, $count of $max_count.\n" >&2
@@ -72,7 +72,7 @@ my_travis_retry() {
echo_stamp "Init rosdep" echo_stamp "Init rosdep"
my_travis_retry rosdep init my_travis_retry rosdep init
# FIXME: Re-add this after missing packages are built # FIXME: Re-add this after missing packages are built
echo "yaml file:///etc/ros/rosdep/${ROS_DISTRO}-rosdep-clover.yaml" >> /etc/ros/rosdep/sources.list.d/20-default.list echo "yaml file:///etc/ros/rosdep/${ROS_DISTRO}-rosdep-clover.yaml" >> /etc/ros/rosdep/sources.list.d/10-clover.list
my_travis_retry rosdep update my_travis_retry rosdep update
echo_stamp "Populate rosdep for ROS user" echo_stamp "Populate rosdep for ROS user"
@@ -125,11 +125,12 @@ cd /home/pi/catkin_ws/src/clover
builder/assets/install_gitbook.sh builder/assets/install_gitbook.sh
gitbook install gitbook install
gitbook build gitbook build
# replace assets copy to assets symlink to save space
rm -rf _book/assets && ln -s ../docs/assets _book/assets
touch node_modules/CATKIN_IGNORE docs/CATKIN_IGNORE _book/CATKIN_IGNORE clover/www/CATKIN_IGNORE apps/CATKIN_IGNORE # ignore documentation files by catkin touch node_modules/CATKIN_IGNORE docs/CATKIN_IGNORE _book/CATKIN_IGNORE clover/www/CATKIN_IGNORE apps/CATKIN_IGNORE # ignore documentation files by catkin
echo_stamp "Installing additional ROS packages" echo_stamp "Installing additional ROS packages"
my_travis_retry apt-get install -y --no-install-recommends \ my_travis_retry apt-get install -y --no-install-recommends \
ros-${ROS_DISTRO}-dynamic-reconfigure \
ros-${ROS_DISTRO}-rosbridge-suite \ ros-${ROS_DISTRO}-rosbridge-suite \
ros-${ROS_DISTRO}-rosserial \ ros-${ROS_DISTRO}-rosserial \
ros-${ROS_DISTRO}-usb-cam \ ros-${ROS_DISTRO}-usb-cam \
@@ -137,7 +138,11 @@ my_travis_retry apt-get install -y --no-install-recommends \
ros-${ROS_DISTRO}-ws281x \ ros-${ROS_DISTRO}-ws281x \
ros-${ROS_DISTRO}-rosshow \ ros-${ROS_DISTRO}-rosshow \
ros-${ROS_DISTRO}-cmake-modules \ ros-${ROS_DISTRO}-cmake-modules \
ros-${ROS_DISTRO}-image-view ros-${ROS_DISTRO}-image-view \
ros-${ROS_DISTRO}-nodelet-topic-tools \
ros-${ROS_DISTRO}-stereo-msgs \
ros-${ROS_DISTRO}-vision-msgs \
ros-${ROS_DISTRO}-angles
# TODO move GeographicLib datasets to Mavros debian package # TODO move GeographicLib datasets to Mavros debian package
echo_stamp "Install GeographicLib datasets (needed for mavros)" \ echo_stamp "Install GeographicLib datasets (needed for mavros)" \

View File

@@ -122,7 +122,7 @@ sed -i "s/updates_available//" /usr/share/byobu/status/status
# sed -i "s/updates_available//" /home/pi/.byobu/status # sed -i "s/updates_available//" /home/pi/.byobu/status
echo_stamp "Installing pip" echo_stamp "Installing pip"
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py curl https://bootstrap.pypa.io/pip/3.7/get-pip.py -o get-pip.py
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip2.py curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip2.py
python3 get-pip.py python3 get-pip.py
python get-pip2.py python get-pip2.py

View File

@@ -37,3 +37,7 @@ apt-cache show openvpn
echo "Move /etc/ld.so.preload back to its original position" echo "Move /etc/ld.so.preload back to its original position"
mv /etc/ld.so.preload.disabled-for-build /etc/ld.so.preload mv /etc/ld.so.preload.disabled-for-build /etc/ld.so.preload
echo "Largest packages installed"
sudo -E sh -c 'apt-get install -y debian-goodies'
dpigs -H -n 100

View File

@@ -6,6 +6,10 @@ import os
import rospy import rospy
from geometry_msgs.msg import PoseStamped from geometry_msgs.msg import PoseStamped
from sensor_msgs.msg import Range, BatteryState from sensor_msgs.msg import Range, BatteryState
from vision_msgs.msg import BoundingBox2D, BoundingBox2DArray, BoundingBox3D, BoundingBox3DArray, \
Classification2D, Classification3D, Detection2D, Detection2DArray, Detection3D, Detection3DArray, \
ObjectHypothesis, ObjectHypothesisWithPose, VisionInfo
import angles
import cv2 import cv2
import cv2.aruco import cv2.aruco
@@ -33,9 +37,12 @@ import tf2_geometry_msgs
import VL53L1X import VL53L1X
import pymavlink import pymavlink
from pymavlink import mavutil from pymavlink import mavutil
from image_geometry import PinholeCameraModel, StereoCameraModel
# from espeak import espeak # from espeak import espeak
from pyzbar import pyzbar from pyzbar import pyzbar
import docopt import docopt
import geopy
import flask
print(cv2.getBuildInformation()) print(cv2.getBuildInformation())

View File

@@ -60,6 +60,9 @@ rosversion cv_camera
rosversion web_video_server rosversion web_video_server
rosversion nodelet rosversion nodelet
rosversion image_view rosversion image_view
rosversion stereo_msgs
rosversion vision_msgs
rosversion angles
[[ $(rosversion ws281x) == "0.0.13" ]] [[ $(rosversion ws281x) == "0.0.13" ]]

View File

@@ -18,7 +18,7 @@ EXCLUDE = 'rviz.png', 'ssid.png', 'sitl_docker_demo.png', 'qgc-params.png', 'but
'qgc-battery.png', 'qgc-radio.png', 'qgc-cal-acc.png', 'qgc-esc.png', 'qgc-cal-compass.png', \ 'qgc-battery.png', 'qgc-radio.png', 'qgc-cal-acc.png', 'qgc-esc.png', 'qgc-cal-compass.png', \
'qgc.png', 'qgc-parameters.png', 'clever4-front-white-large.png', 'qgc-modes.png', \ 'qgc.png', 'qgc-parameters.png', 'clever4-front-white-large.png', 'qgc-modes.png', \
'qgc-requires-setup.png', 'clever4-front-white.png', 'clever4-kit-white.png', '26_1.png', 'battery_holder.stl', \ 'qgc-requires-setup.png', 'clever4-front-white.png', 'clever4-kit-white.png', '26_1.png', 'battery_holder.stl', \
'camera_case.stl', 'camera_mount.stl' 'camera_case.stl', 'camera_mount.stl', 'grip_right.stl', 'grip_left.stl'
code = 0 code = 0

View File

@@ -2,6 +2,52 @@
Changelog for package clover Changelog for package clover
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0.25 (2024-07-28)
-----------------
* Optimize displaying newlines in the topic viewer, add width and indent parameters.
* Link assets instead of copying in documentation to save space.
* Install image_geometry and dynamic_reconfigure as clover dependencies.
* Add dictionary parameter to aruco.launch.
* Solve the issue with aruco_detect not running when aruco_map is not enabled.
* Documentation improvements.
* Rest changes.
0.24 (2023-10-11)
-----------------
* Significant update to autonomous flights API.
* Updates to selfcheck.py.
* Support PX4 v1.14 parameters.
* Added scripts for automatic testing of autonomous flights.
* Added new examples for working with the camera, including a red circle model and its recognition and following.
* Implemented long_callback Python decorator to address the issue #218.
* Implemented optical_flow/enabled dynamic parameter.
* Updated LED strip native library to support RPi 4 rev. 1.5.
* Show number of messages received in web topic viewer.
* Run main_camera/image_raw_throttled topic by default.
* Added rectify argument to main_camera.launch
* Added udev rules for all supported autopilots by PX4.
* Various changes.
0.23 (2022-02-10)
-----------------
* Web tool for topics monitoring.
* Publish optical flow when local position is not available.
* Force estimator init.
* Web viewer for Clover logs.
* selfcheck.py improvements.
* Various changes.
0.22 (2021-06-07)
-----------------
* Move to ROS Noetic and Python 3.
* aruco.launch: add placement, length and map arguments.
* Web: add link for viewing the error log.
* LED: add error/ignore parameter to not flash on some errors.
* Wait for FC and camera devices before launching mavros and camera driver.
* clover.launch: disable rc node by default.
* optical_flow: publish debug image even when calc_flow_gyro failed.
* Various changes.
0.21.1 (2020-11-17) 0.21.1 (2020-11-17)
------------------- -------------------
* First release of clover package to ROS * First release of clover package to ROS

View File

@@ -30,6 +30,8 @@ find_package(catkin REQUIRED COMPONENTS
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
# https://github.com/mavlink/mavros/blob/7f1a8/mavros/CMakeLists.txt#L42
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};/usr/share/cmake/geographiclib")
find_package(GeographicLib REQUIRED) find_package(GeographicLib REQUIRED)
# Workaround for OpenCV 3/4 support # Workaround for OpenCV 3/4 support

View File

@@ -50,6 +50,6 @@ To start connection to the flight controller, use:
roslaunch clover clover.launch roslaunch clover clover.launch
``` ```
For the simulation information see the [corresponding article](https://clover.coex.tech/en/simulation.html). For the simulation information see the [corresponding article](https://clovercoex.tech/en/simulation.html).
> 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`. > 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`.

View File

@@ -1,18 +0,0 @@
# taken from: https://github.com/mavlink/mavros/blob/master/libmavconn/cmake/Modules/FindGeographicLib.cmake
# Look for GeographicLib
#
# Set
# GEOGRAPHICLIB_FOUND = TRUE
# GeographicLib_INCLUDE_DIRS = /usr/local/include
# GeographicLib_LIBRARIES = /usr/local/lib/libGeographic.so
# GeographicLib_LIBRARY_DIRS = /usr/local/lib
find_path (GeographicLib_INCLUDE_DIRS NAMES GeographicLib/Config.h)
find_library (GeographicLib_LIBRARIES NAMES Geographic)
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (GeographicLib DEFAULT_MSG
GeographicLib_LIBRARIES GeographicLib_INCLUDE_DIRS)
mark_as_advanced (GeographicLib_LIBRARIES GeographicLib_INCLUDE_DIRS)

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/camera # Information: https://clovercoex.tech/camera
# Example on basic working with the camera and image processing: # Example on basic working with the camera and image processing:

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/programming # Information: https://clovercoex.tech/programming
import rospy import rospy
from clover import srv from clover import srv

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/aruco # Information: https://clovercoex.tech/aruco
import rospy import rospy
from clover import srv from clover import srv

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/en/simple_offboard.html#gettelemetry # Information: https://clovercoex.tech/en/simple_offboard.html#gettelemetry
import rospy import rospy
from clover import srv from clover import srv

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/en/simple_offboard.html#navigateglobal # Information: https://clovercoex.tech/en/simple_offboard.html#navigateglobal
import rospy import rospy
from clover import srv from clover import srv
@@ -16,7 +16,7 @@ set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)
set_rates = rospy.ServiceProxy('set_rates', srv.SetRates) set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)
land = rospy.ServiceProxy('land', Trigger) land = rospy.ServiceProxy('land', Trigger)
# https://clover.coex.tech/en/snippets.html#wait_arrival # https://clovercoex.tech/en/snippets.html#wait_arrival
def wait_arrival(tolerance=0.2): def wait_arrival(tolerance=0.2):
while not rospy.is_shutdown(): while not rospy.is_shutdown():
telem = get_telemetry(frame_id='navigate_target') telem = get_telemetry(frame_id='navigate_target')
@@ -27,7 +27,7 @@ def wait_arrival(tolerance=0.2):
start = get_telemetry() start = get_telemetry()
if math.isnan(start.lat): if math.isnan(start.lat):
raise Exception('No global position, install and configure GPS sensor: https://clover.coex.tech/gps') raise Exception('No global position, install and configure GPS sensor: https://clovercoex.tech/gps')
print('Start point global position: lat={}, lon={}'.format(start.lat, start.lon)) print('Start point global position: lat={}, lon={}'.format(start.lat, start.lon))

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/led # Information: https://clovercoex.tech/led
import rospy import rospy
from clover.srv import SetLEDEffect from clover.srv import SetLEDEffect

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/en/snippets.html#navigate_wait # Information: https://clovercoex.tech/en/snippets.html#navigate_wait
import math import math
import rospy import rospy

View File

@@ -1,6 +1,6 @@
# This example makes the drone find and follow the red circle. # This example makes the drone find and follow the red circle.
# To test in the simulator, place 'Red Circle' model on the floor. # To test in the simulator, place 'Red Circle' model on the floor.
# More information: https://clover.coex.tech/red_circle # More information: https://clovercoex.tech/red_circle
# Input topic: main_camera/image_raw (camera image) # Input topic: main_camera/image_raw (camera image)
# Output topics: # Output topics:
@@ -17,6 +17,7 @@ from cv_bridge import CvBridge
from clover import long_callback, srv from clover import long_callback, srv
import tf2_ros import tf2_ros
import tf2_geometry_msgs import tf2_geometry_msgs
import image_geometry
rospy.init_node('cv', disable_signals=True) # disable signals to allow interrupting with ctrl+c rospy.init_node('cv', disable_signals=True) # disable signals to allow interrupting with ctrl+c
@@ -32,21 +33,14 @@ mask_pub = rospy.Publisher('~mask', Image, queue_size=1)
point_pub = rospy.Publisher('~red_circle', PointStamped, queue_size=1) point_pub = rospy.Publisher('~red_circle', PointStamped, queue_size=1)
# read camera info # read camera info
camera_info = rospy.wait_for_message('main_camera/camera_info', CameraInfo) camera_model = image_geometry.PinholeCameraModel()
camera_matrix = np.float64(camera_info.K).reshape(3, 3) camera_model.fromCameraInfo(rospy.wait_for_message('main_camera/camera_info', CameraInfo))
distortion = np.float64(camera_info.D).flatten()
def img_xy_to_point(xy, dist): def img_xy_to_point(xy, dist):
xy = cv2.undistortPoints(xy, camera_matrix, distortion, P=camera_matrix)[0][0] xy_rect = camera_model.rectifyPoint(xy)
ray = camera_model.projectPixelTo3dRay(xy_rect)
# Shift points to center return Point(x=ray[0] * dist, y=ray[1] * dist, z=dist)
xy -= camera_info.width // 2, camera_info.height // 2
fx = camera_matrix[0, 0]
fy = camera_matrix[1, 1]
return Point(x=xy[0] * dist / fx, y=xy[1] * dist / fy, z=dist)
def get_center_of_mass(mask): def get_center_of_mass(mask):
M = cv2.moments(mask) M = cv2.moments(mask)

View File

@@ -1,4 +1,4 @@
# Information: https://clover.coex.tech/en/laser.html # Information: https://clovercoex.tech/en/laser.html
import rospy import rospy
from sensor_msgs.msg import Range from sensor_msgs.msg import Range

View File

@@ -6,7 +6,7 @@
<arg name="length" default="0.22"/> <!-- not-in-map markers length, m --> <arg name="length" default="0.22"/> <!-- not-in-map markers length, m -->
<arg name="map" default="map.txt"/> <!-- markers map file name --> <arg name="map" default="map.txt"/> <!-- markers map file name -->
<!-- For additional help go to https://clover.coex.tech/aruco --> <!-- For additional help go to https://clovercoex.tech/aruco -->
<arg name="force_init" default="false"/> <arg name="force_init" default="false"/>
<arg name="disable" default="false"/> <!-- only force init --> <arg name="disable" default="false"/> <!-- only force init -->
@@ -16,9 +16,10 @@
<remap from="image_raw" to="main_camera/image_raw"/> <remap from="image_raw" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/> <remap from="camera_info" to="main_camera/camera_info"/>
<remap from="map_markers" to="aruco_map/map"/> <remap from="map_markers" to="aruco_map/map"/>
<param name="dictionary" value="2"/> <!-- DICT_4X4_250 -->
<param name="estimate_poses" value="true"/> <param name="estimate_poses" value="true"/>
<param name="send_tf" value="true"/> <param name="send_tf" value="true"/>
<param name="use_map_markers" value="true"/> <param name="use_map_markers" value="$(arg aruco_map)"/>
<param name="known_vertical" value="map" if="$(eval placement == 'floor' or placement == 'ceiling')"/> <param name="known_vertical" value="map" if="$(eval placement == 'floor' or placement == 'ceiling')"/>
<param name="flip_vertical" value="true" if="$(eval placement == 'ceiling')"/> <param name="flip_vertical" value="true" if="$(eval placement == 'ceiling')"/>
<param name="length" value="$(arg length)"/> <param name="length" value="$(arg length)"/>

View File

@@ -51,6 +51,7 @@
<!-- simplified offboard control --> <!-- simplified offboard control -->
<node name="simple_offboard" pkg="clover" type="simple_offboard" output="screen" clear_params="true"> <node name="simple_offboard" pkg="clover" type="simple_offboard" output="screen" clear_params="true">
<param name="reference_frames/main_camera_optical" value="map"/> <param name="reference_frames/main_camera_optical" value="map"/>
<param name="terrain_frame_mode" value="range"/>
</node> </node>
<!-- main camera --> <!-- main camera -->
@@ -71,6 +72,9 @@
<param name="pass_statuses" type="yaml" value="[0, 6, 7, 11]"/> <param name="pass_statuses" type="yaml" value="[0, 6, 7, 11]"/>
</node> </node>
<!-- rangefinder's frame -->
<node pkg="tf2_ros" type="static_transform_publisher" name="rangefinder_frame" args="0 0 -0.05 0 1.5707963268 0 base_link rangefinder" if="$(arg rangefinder_vl53l1x)"/>
<!-- led strip --> <!-- led strip -->
<include file="$(find clover)/launch/led.launch" if="$(arg led)"> <include file="$(find clover)/launch/led.launch" if="$(arg led)">
<arg name="simulator" value="$(arg simulator)"/> <arg name="simulator" value="$(arg simulator)"/>

View File

@@ -7,7 +7,7 @@
<arg name="simulator" default="false"/> <arg name="simulator" default="false"/>
<!-- For additional help go to https://clover.coex.tech/led --> <!-- For additional help go to https://clovercoex.tech/led -->
<!-- ws281x led strip driver --> <!-- ws281x led strip driver -->
<node pkg="ws281x" name="led" type="ws281x_node" clear_params="true" output="screen" if="$(eval ws281x and not simulator)"> <node pkg="ws281x" name="led" type="ws281x_node" clear_params="true" output="screen" if="$(eval ws281x and not simulator)">
@@ -21,7 +21,8 @@
</node> </node>
<!-- high level led effects control, events notification with leds --> <!-- high level led effects control, events notification with leds -->
<node pkg="clover" name="led_effect" type="led" ns="led" clear_params="true" output="screen" if="$(arg led_effect)"> <node pkg="clover" name="led_effect" type="led" clear_params="true" output="screen" if="$(arg led_effect)">
<param name="led" value="led"/>
<param name="blink_rate" value="2"/> <param name="blink_rate" value="2"/>
<param name="fade_period" value="0.5"/> <param name="fade_period" value="0.5"/>
<param name="rainbow_period" value="5"/> <param name="rainbow_period" value="5"/>

View File

@@ -1,11 +1,12 @@
<launch> <launch>
<!-- article about camera setup: https://clover.coex.tech/camera_setup --> <!-- article about camera setup: https://clovercoex.tech/camera_setup -->
<arg name="direction_z" default="down"/> <!-- direction the camera points: down, up --> <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 --> <arg name="direction_y" default="backward"/> <!-- direction the camera cable points: backward, forward -->
<arg name="device" default="/dev/video0"/> <!-- v4l2 device --> <arg name="device" default="/dev/video0"/> <!-- v4l2 device -->
<arg name="throttled_topic" default="true"/> <!-- enable throttled image topic --> <arg name="throttled_topic" default="true"/> <!-- enable throttled image topic -->
<arg name="throttled_topic_rate" default="5.0"/> <!-- throttled image topic rate --> <arg name="throttled_topic_rate" default="5.0"/> <!-- throttled image topic rate -->
<arg name="rectify" default="false"/> <!-- enable rectification -->
<arg name="simulator" default="false"/> <arg name="simulator" default="false"/>
<node if="$(eval direction_z == 'down' and direction_y == 'backward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/> <node if="$(eval direction_z == 'down' and direction_y == 'backward')" 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"/>
@@ -49,4 +50,11 @@
<!-- image topic throttled --> <!-- image topic throttled -->
<node pkg="topic_tools" name="main_camera_throttle" type="throttle" ns="main_camera" <node pkg="topic_tools" name="main_camera_throttle" type="throttle" ns="main_camera"
args="messages image_raw $(arg throttled_topic_rate) image_raw_throttled" if="$(arg throttled_topic)"/> args="messages image_raw $(arg throttled_topic_rate) image_raw_throttled" if="$(arg throttled_topic)"/>
<!-- rectified image topic -->
<node pkg="nodelet" type="nodelet" name="rectify" args="load image_proc/rectify main_camera_nodelet_manager" if="$(arg rectify)">
<remap from="image_mono" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/>
<remap from="image_rect" to="main_camera/image_rect"/>
</node>
</launch> </launch>

View File

@@ -77,9 +77,6 @@
covariance: 1 # cm covariance: 1 # cm
</rosparam> </rosparam>
<!-- Rangefinders frame -->
<node pkg="tf2_ros" type="static_transform_publisher" name="rangefinder_frame" args="0 0 -0.05 0 1.5707963268 0 base_link rangefinder"/>
<!-- Copter visualization --> <!-- Copter visualization -->
<node name="visualization" pkg="mavros_extras" type="visualization" if="$(arg viz)"> <node name="visualization" pkg="mavros_extras" type="visualization" if="$(arg viz)">
<remap to="mavros/local_position/pose" from="local_position"/> <remap to="mavros/local_position/pose" from="local_position"/>

View File

@@ -1,13 +1,13 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<package format="3"> <package format="3">
<name>clover</name> <name>clover</name>
<version>0.23.0</version> <version>0.25.0</version>
<description>The Clover package</description> <description>The Clover package</description>
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer> <maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
<license>MIT</license> <license>MIT</license>
<url type="website">https://clover.coex.tech/</url> <url type="website">https://clovercoex.tech/</url>
<author email="okalachev@gmail.com">Oleg Kalachev</author> <author email="okalachev@gmail.com">Oleg Kalachev</author>
<author email="urpylka@gmail.com">Artem Smirnov</author> <author email="urpylka@gmail.com">Artem Smirnov</author>
@@ -42,6 +42,8 @@
<depend condition="$ROS_PYTHON_VERSION == 2">python-lxml</depend> <depend condition="$ROS_PYTHON_VERSION == 2">python-lxml</depend>
<depend condition="$ROS_PYTHON_VERSION == 3">python3-lxml</depend> <depend condition="$ROS_PYTHON_VERSION == 3">python3-lxml</depend>
<depend>dynamic_reconfigure</depend> <depend>dynamic_reconfigure</depend>
<depend>image_proc</depend>
<depend>image_geometry</depend>
<exec_depend>python-pymavlink</exec_depend> <exec_depend>python-pymavlink</exec_depend>
<test_depend>ros_pytest</test_depend> <test_depend>ros_pytest</test_depend>

View File

@@ -1,4 +1,4 @@
flask==1.1.1 flask
geopy==1.11.0 geopy
smbus2==0.3.0 smbus2
VL53L1X==0.0.5 VL53L1X

View File

@@ -309,15 +309,19 @@ int main(int argc, char **argv)
nh_priv.param("notify/low_battery/threshold", low_battery_threshold, 3.7); nh_priv.param("notify/low_battery/threshold", low_battery_threshold, 3.7);
nh_priv.param("notify/error/ignore", error_ignore, {}); nh_priv.param("notify/error/ignore", error_ignore, {});
ros::service::waitForService("set_leds"); // cannot work without set_leds service std::string led; // led namespace
set_leds_srv = nh.serviceClient<led_msgs::SetLEDs>("set_leds", true); nh_priv.param("led", led, std::string("led"));
if (!led.empty()) led += "/";
ros::service::waitForService(led + "set_leds"); // cannot work without set_leds service
set_leds_srv = nh.serviceClient<led_msgs::SetLEDs>(led + "set_leds", true);
// wait for leds count info // wait for leds count info
handleState(*ros::topic::waitForMessage<led_msgs::LEDStateArray>("state", nh)); handleState(*ros::topic::waitForMessage<led_msgs::LEDStateArray>(led + "state", nh));
auto state_sub = nh.subscribe("state", 1, &handleState); auto state_sub = nh.subscribe(led + "state", 1, &handleState);
auto set_effect = nh.advertiseService("set_effect", &setEffect); auto set_effect = nh.advertiseService(led + "set_effect", &setEffect);
auto mavros_state_sub = nh.subscribe("mavros/state", 1, &handleMavrosState); auto mavros_state_sub = nh.subscribe("mavros/state", 1, &handleMavrosState);
auto battery_sub = nh.subscribe("mavros/battery", 1, &handleBattery); auto battery_sub = nh.subscribe("mavros/battery", 1, &handleBattery);

View File

@@ -107,7 +107,7 @@ def ff(value, precision=2):
param_get = rospy.ServiceProxy('mavros/param/get', ParamGet) param_get = rospy.ServiceProxy('mavros/param/get', ParamGet)
def get_param(name, default=None): def get_param(name, default=None, strict=True):
try: try:
res = param_get(param_id=name) res = param_get(param_id=name)
except rospy.ServiceException as e: except rospy.ServiceException as e:
@@ -115,7 +115,8 @@ def get_param(name, default=None):
return None return None
if not res.success: if not res.success:
failure('unable to retrieve PX4 parameter %s', name) if strict:
failure('unable to retrieve PX4 parameter %s', name)
return default return default
else: else:
if res.value.integer != 0: if res.value.integer != 0:
@@ -258,12 +259,12 @@ def check_fcu():
info(line[len('HW arch: '):]) info(line[len('HW arch: '):])
if not clover_fw: if not clover_fw:
info('not Clover PX4 firmware, check https://clover.coex.tech/firmware') info('not Clover PX4 firmware, check https://clovercoex.tech/firmware')
est = get_param('SYS_MC_EST_GROUP') est = get_param('SYS_MC_EST_GROUP')
if est == 1: if est == 1:
info('selected estimator: LPE') info('selected estimator: LPE')
fuse = get_param('LPE_FUSION') fuse = int(get_param('LPE_FUSION'))
if fuse & (1 << 4): if fuse & (1 << 4):
info('LPE_FUSION: land detector fusion is enabled') info('LPE_FUSION: land detector fusion is enabled')
else: else:
@@ -299,11 +300,19 @@ def check_fcu():
try: try:
battery = rospy.wait_for_message('mavros/battery', BatteryState, timeout=3) battery = rospy.wait_for_message('mavros/battery', BatteryState, timeout=3)
if not battery.cell_voltage: if not battery.cell_voltage:
failure('cell voltage is not available, https://clover.coex.tech/power') failure('cell voltage is not available, https://clovercoex.tech/power')
else: else:
cell = battery.cell_voltage[0] cell = battery.cell_voltage[0]
# number of cells 1 means this is overall voltage
if len(battery.cell_voltage) == 1:
n_cells = get_param('BAT1_N_CELLS', strict=False)
if n_cells is None:
# older PX4
n_cells = get_param('BAT_N_CELLS', strict=True)
cell /= n_cells
if cell > 4.3 or cell < 3.0: if cell > 4.3 or cell < 3.0:
failure('incorrect cell voltage: %.2f V, https://clover.coex.tech/power', cell) failure('incorrect cell voltage: %.2f V, https://clovercoex.tech/power', cell)
elif cell < 3.7: elif cell < 3.7:
failure('critically low cell voltage: %.2f V, recharge battery', cell) failure('critically low cell voltage: %.2f V, recharge battery', cell)
except rospy.ROSException: except rospy.ROSException:
@@ -316,7 +325,13 @@ def check_fcu():
failure('cannot read time sync offset') failure('cannot read time sync offset')
except rospy.ROSException: except rospy.ROSException:
failure('no MAVROS state (check wiring)') failure('no MAVROS state')
fcu_url = rospy.get_param('mavros/fcu_url', '?')
if fcu_url == '/dev/px4fmu':
if not os.path.exists('/lib/udev/rules.d/99-px4fmu.rules'):
info('udev rules are not installed, install udev rules or change usb_device to /dev/ttyACM0 in mavros.launch')
else:
info('udev did\'t recognize px4fmu device, check wiring or change usb_device to /dev/ttyACM0 in mavros.launch')
info('fcu_url = %s', rospy.get_param('mavros/fcu_url', '?')) info('fcu_url = %s', rospy.get_param('mavros/fcu_url', '?'))
@@ -487,7 +502,7 @@ def check_vpe():
failure('vision yaw weight is zero, change ATT_W_EXT_HDG parameter') failure('vision yaw weight is zero, change ATT_W_EXT_HDG parameter')
else: else:
info('vision yaw weight: %s', ff(vision_yaw_w)) info('vision yaw weight: %s', ff(vision_yaw_w))
fuse = get_param('LPE_FUSION') fuse = int(get_param('LPE_FUSION'))
if not fuse & (1 << 2): if not fuse & (1 << 2):
failure('vision position fusion is disabled, change LPE_FUSION parameter') failure('vision position fusion is disabled, change LPE_FUSION parameter')
delay = get_param('LPE_VIS_DELAY') delay = get_param('LPE_VIS_DELAY')
@@ -495,11 +510,22 @@ def check_vpe():
failure('LPE_VIS_DELAY = %s, but it should be zero', delay) failure('LPE_VIS_DELAY = %s, but it should be zero', delay)
info('LPE_VIS_XY = %s m, LPE_VIS_Z = %s m', get_paramf('LPE_VIS_XY'), get_paramf('LPE_VIS_Z')) info('LPE_VIS_XY = %s m, LPE_VIS_Z = %s m', get_paramf('LPE_VIS_XY'), get_paramf('LPE_VIS_Z'))
elif est == 2: elif est == 2:
fuse = get_param('EKF2_AID_MASK') ev_ctrl = get_param('EKF2_EV_CTRL', strict=False)
if not fuse & (1 << 3): if ev_ctrl is not None: # PX4 after v1.14
failure('vision position fusion is disabled, change EKF2_AID_MASK parameter') ev_ctrl = int(ev_ctrl)
if not fuse & (1 << 4): if not ev_ctrl & (1 << 0):
failure('vision yaw fusion is disabled, change EKF2_AID_MASK parameter') failure('vision horizontal position fusion is disabled, change EKF2_EV_CTRL parameter')
if not ev_ctrl & (1 << 1):
failure('vision vertical position fusion is disabled, change EKF2_EV_CTRL parameter')
if not ev_ctrl & (1 << 3):
failure('vision yaw fusion is disabled, change EKF2_EV_CTRL parameter')
else: # PX4 before v1.14
fuse = int(get_param('EKF2_AID_MASK'))
if not fuse & (1 << 3):
failure('vision position fusion is disabled, change EKF2_AID_MASK parameter')
if not fuse & (1 << 4):
failure('vision yaw fusion is disabled, change EKF2_AID_MASK parameter')
delay = get_param('EKF2_EV_DELAY') delay = get_param('EKF2_EV_DELAY')
if delay != 0: if delay != 0:
failure('EKF2_EV_DELAY = %.2f, but it should be zero', delay) failure('EKF2_EV_DELAY = %.2f, but it should be zero', delay)
@@ -606,8 +632,14 @@ def check_global_position():
rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=0.8) rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=0.8)
except rospy.ROSException: except rospy.ROSException:
info('no global position') info('no global position')
if get_param('SYS_MC_EST_GROUP') == 2 and (get_param('EKF2_AID_MASK', 0) & (1 << 0)): if get_param('SYS_MC_EST_GROUP') == 2:
failure('enabled GPS fusion may suppress vision position aiding') gps_ctrl = get_param('EKF2_GPS_CTRL', strict=False)
if gps_ctrl is not None: # PX4 after v1.14
if int(gps_ctrl) & (1 << 0):
failure('GPS fusion enabled may suppress vision position aiding, change EKF2_GPS_CTRL')
else: # PX4 before v1.14
if int(get_param('EKF2_AID_MASK', 0)) & (1 << 0):
failure('GPS fusion enabled may suppress vision position aiding, change EKF2_AID_MASK')
@check('Optical flow') @check('Optical flow')
@@ -626,7 +658,7 @@ def check_optical_flow():
failure('SENS_FLOW_ROT = %s, but it should be zero', rot) failure('SENS_FLOW_ROT = %s, but it should be zero', rot)
est = get_param('SYS_MC_EST_GROUP') est = get_param('SYS_MC_EST_GROUP')
if est == 1: if est == 1:
fuse = get_param('LPE_FUSION') fuse = int(get_param('LPE_FUSION'))
if not fuse & (1 << 1): if not fuse & (1 << 1):
failure('optical flow fusion is disabled, change LPE_FUSION parameter') failure('optical flow fusion is disabled, change LPE_FUSION parameter')
if not fuse & (1 << 1): if not fuse & (1 << 1):
@@ -640,9 +672,14 @@ def check_optical_flow():
get_paramf('LPE_FLW_R', 4), get_paramf('LPE_FLW_R', 4),
get_paramf('LPE_FLW_RR', 4)) get_paramf('LPE_FLW_RR', 4))
elif est == 2: elif est == 2:
fuse = get_param('EKF2_AID_MASK', 0) of_ctrl = get_param('EKF2_OF_CTRL', strict=False)
if not fuse & (1 << 1): if of_ctrl is not None: # PX4 after v1.14
failure('optical flow fusion is disabled, change EKF2_AID_MASK parameter') if of_ctrl == 0:
failure('optical flow fusion is disabled, change EKF2_OF_CTRL')
else: # PX4 before v1.14
fuse = int(get_param('EKF2_AID_MASK', 0))
if not fuse & (1 << 1):
failure('optical flow fusion is disabled, change EKF2_AID_MASK parameter')
delay = get_param('EKF2_OF_DELAY', 0) delay = get_param('EKF2_OF_DELAY', 0)
if delay != 0: if delay != 0:
failure('EKF2_OF_DELAY = %.2f, but it should be zero', delay) failure('EKF2_OF_DELAY = %.2f, but it should be zero', delay)
@@ -684,23 +721,26 @@ def check_rangefinder():
est = get_param('SYS_MC_EST_GROUP') est = get_param('SYS_MC_EST_GROUP')
if est == 1: if est == 1:
fuse = get_param('LPE_FUSION', 0) fuse = int(get_param('LPE_FUSION', 0))
if not fuse & (1 << 5): if not fuse & (1 << 5):
info('"pub agl as lpos down" in LPE_FUSION is disabled, NOT operating over flat surface') info('"pub agl as lpos down" in LPE_FUSION is disabled, NOT operating over flat surface')
else: else:
info('"pub agl as lpos down" in LPE_FUSION is enabled, operating over flat surface') info('"pub agl as lpos down" in LPE_FUSION is enabled, operating over flat surface')
elif est == 2: elif est == 2:
hgt = get_param('EKF2_HGT_MODE') hgt = get_param('EKF2_HGT_REF', strict=False)
if hgt is None: # PX4 before v1.14
hgt = get_param('EKF2_HGT_MODE')
if hgt != 2: if hgt != 2:
info('EKF2_HGT_MODE != Range sensor, NOT operating over flat surface') info('EKF2_HGT_MODE != Range sensor, NOT operating over flat surface')
else: else:
info('EKF2_HGT_MODE = Range sensor, operating over flat surface') info('EKF2_HGT_MODE = Range sensor, operating over flat surface')
aid = get_param('EKF2_RNG_AID') aid = get_param('EKF2_RNG_AID', strict=False)
if aid != 1: if aid is not None: # PX4 before v1.14
info('EKF2_RNG_AID != 1, range sensor aiding disabled') if aid != 1:
else: info('EKF2_RNG_AID != 1, range sensor aiding disabled')
info('EKF2_RNG_AID = 1, range sensor aiding enabled') else:
info('EKF2_RNG_AID = 1, range sensor aiding enabled')
@check('Boot duration') @check('Boot duration')
@@ -841,7 +881,7 @@ def check_network():
if ros_hostname in parts: if ros_hostname in parts:
break break
else: else:
failure('not found %s in /etc/hosts, ROS will malfunction if network interfaces are down, https://clover.coex.tech/hostname', ros_hostname) failure('not found %s in /etc/hosts, ROS will malfunction if network interfaces are down, https://clovercoex.tech/hostname', ros_hostname)
@check('RPi health') @check('RPi health')

View File

@@ -30,6 +30,7 @@
#include <geometry_msgs/QuaternionStamped.h> #include <geometry_msgs/QuaternionStamped.h>
#include <sensor_msgs/NavSatFix.h> #include <sensor_msgs/NavSatFix.h>
#include <sensor_msgs/BatteryState.h> #include <sensor_msgs/BatteryState.h>
#include <sensor_msgs/Range.h>
#include <mavros_msgs/CommandBool.h> #include <mavros_msgs/CommandBool.h>
#include <mavros_msgs/SetMode.h> #include <mavros_msgs/SetMode.h>
#include <mavros_msgs/PositionTarget.h> #include <mavros_msgs/PositionTarget.h>
@@ -86,6 +87,7 @@ float default_speed;
bool auto_release; bool auto_release;
bool land_only_in_offboard, nav_from_sp, check_kill_switch; bool land_only_in_offboard, nav_from_sp, check_kill_switch;
std::map<string, string> reference_frames; std::map<string, string> reference_frames;
string terrain_frame_mode;
// Publishers // Publishers
ros::Publisher attitude_pub, attitude_raw_pub, position_pub, position_raw_pub, rates_pub, thrust_pub, state_pub; ros::Publisher attitude_pub, attitude_raw_pub, position_pub, position_raw_pub, rates_pub, thrust_pub, state_pub;
@@ -205,18 +207,27 @@ inline bool waitTransform(const string& target, const string& source,
return false; return false;
} }
void publishTerrain(const double distance, const ros::Time& stamp)
{
if (!waitTransform(local_frame, body.child_frame_id, stamp, ros::Duration(0.1))) return;
auto t = tf_buffer.lookupTransform(local_frame, body.child_frame_id, stamp);
t.child_frame_id = terrain.child_frame_id;
t.transform.translation.z -= distance;
static_transform_broadcaster->sendTransform(t);
}
void handleAltitude(const Altitude& alt) void handleAltitude(const Altitude& alt)
{ {
// publish terrain frame
if (!std::isfinite(alt.bottom_clearance)) return; if (!std::isfinite(alt.bottom_clearance)) return;
// terrain.header.stamp = alt.header.stamp; publishTerrain(alt.bottom_clearance, alt.header.stamp);
}
if (!waitTransform(local_frame, body.child_frame_id, alt.header.stamp, ros::Duration(0.1))) return; void handleRange(const Range& range)
{
auto t = tf_buffer.lookupTransform(local_frame, body.child_frame_id, alt.header.stamp); if (!std::isfinite(range.range)) return;
t.child_frame_id = terrain.child_frame_id; // TODO: check it's facing down
t.transform.translation.z -= alt.bottom_clearance; publishTerrain(range.range, range.header.stamp);
static_transform_broadcaster->sendTransform(t);
} }
#define TIMEOUT(msg, timeout) (msg.header.stamp.isZero() || (ros::Time::now() - msg.header.stamp > timeout)) #define TIMEOUT(msg, timeout) (msg.header.stamp.isZero() || (ros::Time::now() - msg.header.stamp > timeout))
@@ -635,7 +646,7 @@ inline void checkState()
throw std::runtime_error("State timeout, check mavros settings"); throw std::runtime_error("State timeout, check mavros settings");
if (!state.connected) if (!state.connected)
throw std::runtime_error("No connection to FCU, https://clover.coex.tech/connection"); throw std::runtime_error("No connection to FCU, https://clovercoex.tech/connection");
} }
void publishState() void publishState()
@@ -800,7 +811,8 @@ bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, fl
nav_from_sp_flag = false; nav_from_sp_flag = false;
} }
if (auto_arm || setpoint_type == VELOCITY || setpoint_type == ATTITUDE || setpoint_type == RATES) { bool to_auto_arm = auto_arm && (state.mode != "OFFBOARD" || !state.armed);
if (to_auto_arm || setpoint_type == VELOCITY || setpoint_type == ATTITUDE || setpoint_type == RATES) {
// invalidate position setpoint // invalidate position setpoint
setpoint_position.header.frame_id = ""; setpoint_position.header.frame_id = "";
setpoint_altitude.header.frame_id = ""; setpoint_altitude.header.frame_id = "";
@@ -1100,6 +1112,7 @@ int main(int argc, char **argv)
nh_priv.param("default_speed", default_speed, 0.5f); nh_priv.param("default_speed", default_speed, 0.5f);
nh_priv.param<string>("body_frame", body.child_frame_id, "body"); nh_priv.param<string>("body_frame", body.child_frame_id, "body");
nh_priv.param<string>("terrain_frame", terrain.child_frame_id, "terrain"); nh_priv.param<string>("terrain_frame", terrain.child_frame_id, "terrain");
nh_priv.param<string>("terrain_frame_mode", terrain_frame_mode, "altitude");
nh_priv.getParam("reference_frames", reference_frames); nh_priv.getParam("reference_frames", reference_frames);
// Default reference frames // Default reference frames
@@ -1138,7 +1151,15 @@ int main(int argc, char **argv)
ros::Subscriber altitude_sub; ros::Subscriber altitude_sub;
if (!body.child_frame_id.empty() && !terrain.child_frame_id.empty()) { if (!body.child_frame_id.empty() && !terrain.child_frame_id.empty()) {
terrain.header.frame_id = local_frame; terrain.header.frame_id = local_frame;
altitude_sub = nh.subscribe(mavros + "/altitude", 1, &handleAltitude); if (terrain_frame_mode == "altitude") {
altitude_sub = nh.subscribe(mavros + "/altitude", 1, &handleAltitude);
} else if (terrain_frame_mode == "range") {
string range_topic = nh_priv.param("range_topic", string("rangefinder/range"));
altitude_sub = nh.subscribe(range_topic, 1, &handleRange);
} else {
ROS_FATAL("Unknown terrain_frame_mode: %s, valid values: altitude, range", terrain_frame_mode.c_str());
ros::shutdown();
}
} }
// Setpoint publishers // Setpoint publishers

View File

@@ -11,12 +11,14 @@
#include <string> #include <string>
#include <ros/ros.h> #include <ros/ros.h>
#include <tf/transform_datatypes.h>
#include <tf2/transform_datatypes.h> #include <tf2/transform_datatypes.h>
#include <tf2_ros/buffer.h> #include <tf2_ros/buffer.h>
#include <tf2_ros/transform_listener.h> #include <tf2_ros/transform_listener.h>
#include <tf2_ros/static_transform_broadcaster.h> #include <tf2_ros/static_transform_broadcaster.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.h> #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
#include <geometry_msgs/TransformStamped.h> #include <geometry_msgs/TransformStamped.h>
#include <geometry_msgs/Quaternion.h>
#include <geometry_msgs/PoseStamped.h> #include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/PoseWithCovarianceStamped.h> #include <geometry_msgs/PoseWithCovarianceStamped.h>
#include <std_srvs/Trigger.h> #include <std_srvs/Trigger.h>
@@ -66,6 +68,13 @@ inline Pose getPose(const PoseStampedConstPtr& pose) { return pose->pose; }
inline Pose getPose(const PoseWithCovarianceStampedConstPtr& pose) { return pose->pose.pose; } inline Pose getPose(const PoseWithCovarianceStampedConstPtr& pose) { return pose->pose.pose; }
inline void keepYaw(Quaternion& quaternion)
{
tf::Quaternion q;
q.setRPY(0, 0, tf::getYaw(quaternion));
tf::quaternionTFToMsg(q, quaternion);
}
template <typename T> template <typename T>
void callback(const T& msg) void callback(const T& msg)
{ {
@@ -88,10 +97,29 @@ void callback(const T& msg)
if (!offset_frame_id.empty()) { if (!offset_frame_id.empty()) {
if (reset_flag || msg->header.stamp - vpe.header.stamp > offset_timeout) { if (reset_flag || msg->header.stamp - vpe.header.stamp > offset_timeout) {
// calculate the offset // calculate the offset
offset = tf_buffer.lookupTransform(local_frame_id, frame_id, if (!frame_id.empty()) {
msg->header.stamp, ros::Duration(0.02)); // calculate from TF
// offset.header.frame_id = vpe.header.frame_id; offset = tf_buffer.lookupTransform(local_frame_id, frame_id,
offset.child_frame_id = offset_frame_id; msg->header.stamp, ros::Duration(0.02));
// offset.header.frame_id = vpe.header.frame_id;
offset.child_frame_id = offset_frame_id;
} else {
// calculate transform between pose in vpe frame and pose in local frame
TransformStamped local_pose = tf_buffer.lookupTransform(local_frame_id, child_frame_id,
msg->header.stamp, ros::Duration(0.02));
keepYaw(local_pose.transform.rotation);
tf::Transform vpeTransform, poseTransform;
tf::poseMsgToTF(vpe.pose, vpeTransform);
tf::transformMsgToTF(local_pose.transform, poseTransform);
tf::Transform offset_tf = vpeTransform.inverseTimes(poseTransform);
tf::transformTFToMsg(offset_tf, offset.transform);
offset.header.frame_id = local_frame_id;
offset.header.stamp = msg->header.stamp;
offset.child_frame_id = offset_frame_id;
}
br.sendTransform(offset); br.sendTransform(offset);
reset_flag = false; reset_flag = false;
ROS_INFO("offset reset"); ROS_INFO("offset reset");
@@ -122,8 +150,9 @@ int main(int argc, char **argv) {
tf2_ros::TransformListener tf_listener(tf_buffer); tf2_ros::TransformListener tf_listener(tf_buffer);
nh_priv.param<string>("frame_id", frame_id, ""); nh_priv.param<string>("frame_id", frame_id, ""); // name for used visual pose frame
nh_priv.param<string>("offset_frame_id", offset_frame_id, ""); nh_priv.param<string>("offset_frame_id", offset_frame_id, ""); // name for published offset frame
nh.param<string>("mavros/local_position/frame_id", local_frame_id, "map"); nh.param<string>("mavros/local_position/frame_id", local_frame_id, "map");
nh.param<string>("mavros/local_position/tf/child_frame_id", child_frame_id, "base_link"); nh.param<string>("mavros/local_position/tf/child_frame_id", child_frame_id, "base_link");
offset_timeout = ros::Duration(nh_priv.param("offset_timeout", 3.0)); offset_timeout = ros::Duration(nh_priv.param("offset_timeout", 3.0));

View File

@@ -40,6 +40,16 @@
<node pkg="topic_tools" name="main_camera_throttle" type="throttle" ns="main_camera" <node pkg="topic_tools" name="main_camera_throttle" type="throttle" ns="main_camera"
args="messages image_raw 5.0 image_raw_throttled" required="true"/> args="messages image_raw 5.0 image_raw_throttled" required="true"/>
<node pkg="nodelet" type="nodelet" name="main_camera_nodelet_manager" args="manager" output="screen" required="true">
<param name="num_worker_threads" value="2"/>
</node>
<node pkg="nodelet" type="nodelet" name="rectify" args="load image_proc/rectify main_camera_nodelet_manager" required="true">
<remap from="image_mono" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/>
<remap from="image_rect" to="main_camera/image_rect"/>
</node>
<param name="test_module" value="$(find clover)/test/basic.py"/> <param name="test_module" value="$(find clover)/test/basic.py"/>
<test test-name="basic_test" pkg="ros_pytest" type="ros_pytest_runner"/> <test test-name="basic_test" pkg="ros_pytest" type="ros_pytest_runner"/>
</launch> </launch>

View File

@@ -3,9 +3,11 @@ import pytest
from pytest import approx from pytest import approx
import threading import threading
import mavros_msgs.msg import mavros_msgs.msg
from mavros_msgs.srv import SetMode
from geometry_msgs.msg import PoseStamped from geometry_msgs.msg import PoseStamped
from clover import srv from clover import srv
from clover.msg import State from clover.msg import State
from std_srvs.srv import Trigger
from math import nan, inf from math import nan, inf
import tf2_ros import tf2_ros
import tf2_geometry_msgs import tf2_geometry_msgs
@@ -38,6 +40,8 @@ def test_offboard(node, tf_buffer):
set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude) set_attitude = rospy.ServiceProxy('set_attitude', srv.SetAttitude)
set_rates = rospy.ServiceProxy('set_rates', srv.SetRates) set_rates = rospy.ServiceProxy('set_rates', srv.SetRates)
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry) get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
land = rospy.ServiceProxy('land', Trigger)
res = navigate() res = navigate()
assert res.success == False assert res.success == False
assert res.message.startswith('State timeout') assert res.message.startswith('State timeout')
@@ -45,6 +49,7 @@ def test_offboard(node, tf_buffer):
telem = get_telemetry() telem = get_telemetry()
assert telem.connected == False assert telem.connected == False
# mocked state publisher
state_pub = rospy.Publisher('/mavros/state', mavros_msgs.msg.State, latch=True, queue_size=1) state_pub = rospy.Publisher('/mavros/state', mavros_msgs.msg.State, latch=True, queue_size=1)
state_msg = mavros_msgs.msg.State(mode='OFFBOARD', armed=True) state_msg = mavros_msgs.msg.State(mode='OFFBOARD', armed=True)
@@ -59,6 +64,13 @@ def test_offboard(node, tf_buffer):
threading.Thread(target=publish_state, daemon=True).start() threading.Thread(target=publish_state, daemon=True).start()
rospy.sleep(0.5) rospy.sleep(0.5)
# set_mode service mock
def set_mode(req):
state_msg.mode = req.custom_mode # set mocked mode to requested
return True,
rospy.Service('/mavros/set_mode', SetMode, set_mode)
telem = get_telemetry() telem = get_telemetry()
assert telem.connected == False assert telem.connected == False
@@ -157,7 +169,23 @@ def test_offboard(node, tf_buffer):
assert state.z_frame_id == 'map' assert state.z_frame_id == 'map'
assert state.yaw_frame_id == 'test' assert state.yaw_frame_id == 'test'
# auto_arm should invalidate the setpoint # auto_arm should not invalidate the setpoint if not effective
res = navigate(x=nan, y=nan, z=1, frame_id='map', auto_arm=True)
assert res.success == True
state = get_state()
assert state.mode == State.MODE_NAVIGATE
assert state.yaw_mode == State.YAW_MODE_YAW
assert state.x == 1
assert state.y == 2
assert state.z == 1
assert state.yaw == 0
assert state.xy_frame_id == 'test'
assert state.z_frame_id == 'map'
assert state.yaw_frame_id == 'map'
# auto_arm should invalidate the setpoint if effective
state_msg.mode = 'STABILIZED' # pretend we are not in OFFBOARD mode
rospy.sleep(1)
res = navigate(x=nan, y=nan, z=1, frame_id='map', auto_arm=True) res = navigate(x=nan, y=nan, z=1, frame_id='map', auto_arm=True)
assert res.success == True assert res.success == True
state = get_state() state = get_state()
@@ -170,6 +198,8 @@ def test_offboard(node, tf_buffer):
assert state.xy_frame_id == 'map' assert state.xy_frame_id == 'map'
assert state.z_frame_id == 'map' assert state.z_frame_id == 'map'
assert state.yaw_frame_id == 'map' assert state.yaw_frame_id == 'map'
state_msg.mode = 'OFFBOARD'
rospy.sleep(1)
# set_attitude should invalidate the setpoint # set_attitude should invalidate the setpoint
res = set_attitude() res = set_attitude()
@@ -400,3 +430,8 @@ def test_offboard(node, tf_buffer):
res = set_rates(roll_rate=inf) res = set_rates(roll_rate=inf)
assert res.success == False assert res.success == False
assert res.message == 'roll_rate argument cannot be Inf' assert res.message == 'roll_rate argument cannot be Inf'
# test land service
res = land()
assert res.success == True
assert state_msg.mode == 'AUTO.LAND' # check that the mode was set correctly

View File

@@ -1,17 +1,54 @@
# PixHawk (px4fmu-v2), px4fmu-v3 # Source files: PX4-Autopilot/boards/**/nuttx-config/nsh/defconfig
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0011", ATTRS{product}=="PX4 FMU v2.x", SYMLINK+="px4fmu"
# PixRacer (px4fmu-v4)
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0012", ATTRS{product}=="PX4 FMU v4.x", SYMLINK+="px4fmu"
# px4fmu-v5
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0032", ATTRS{product}=="PX4 FMU v5.x", SYMLINK+="px4fmu"
# auav
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0021", ATTRS{product}=="PX4 AUAV x2.1", SYMLINK+="px4fmu"
# crazyflie
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0016", ATTRS{product}=="PX4 Crazyflie v2.0", SYMLINK+="px4fmu"
# px4fmu-v4pro
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0013", ATTRS{product}=="PX4 FMU v4.x PRO", SYMLINK+="px4fmu"
# Omnibus
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0001", ATTRS{product}=="PX4 OmnibusF4SD", SYMLINK+="px4fmu"
# CUAV X7 Pro
SUBSYSTEM=="tty", ATTRS{idVendor}=="3163", ATTRS{idProduct}=="004c", ATTRS{product}=="PX4 CUAV X7Pro", SYMLINK+="px4fmu"
# Additional info:
# https://docs.px4.io/main/en/flight_controller/
# https://github.com/mavlink/qgroundcontrol/blob/master/src/comm/USBBoardInfo.json
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0001", ATTRS{product}=="PX4 GNF405", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0001", ATTRS{product}=="PX4 OmnibusF4SD", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0016", ATTRS{product}=="PX4 Crazyflie v2.0", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1FC9", ATTRS{idProduct}=="001c", ATTRS{product}=="PX4 FMUK66 v3.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1FC9", ATTRS{idProduct}=="001c", ATTRS{product}=="PX4 FMUK66 E", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1FC9", ATTRS{idProduct}=="001d", ATTRS{product}=="PX4 FMURT1062 v1.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0001", ATTRS{product}=="DiatoneMambaF405 MK2", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a32f", ATTRS{product}=="PX4 FMU ModalAI FCv1", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a330", ATTRS{product}=="PX4 FMU ModalAI FCv2", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0012", ATTRS{product}=="PX4 FMU UVify Core", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3162", ATTRS{idProduct}=="0050", ATTRS{product}=="PX4 KakuteH7", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3162", ATTRS{idProduct}=="0050", ATTRS{product}=="PX4 KakuteH7v2", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3162", ATTRS{idProduct}=="004b", ATTRS{product}=="PX4 DurandalV1", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0050", ATTRS{product}=="PX4 KakuteF7", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3162", ATTRS{idProduct}=="0050", ATTRS{product}=="PX4 KakuteH7Mini-nand", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3162", ATTRS{idProduct}=="004E", ATTRS{product}=="PX4 PIX32V5", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0061", ATTRS{product}=="PX4 ATL Mantis-EDU", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3163", ATTRS{idProduct}=="004c", ATTRS{product}=="PX4 CUAV Nora", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3163", ATTRS{idProduct}=="004c", ATTRS{product}=="PX4 CUAV X7Pro", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1B8C", ATTRS{idProduct}=="0036", ATTRS{product}=="MatekH743-mini", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1B8C", ATTRS{idProduct}=="0036", ATTRS{product}=="MatekH743", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="120A", ATTRS{idProduct}=="1004", ATTRS{product}=="Matekgnssm9nf4", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="1013", ATTRS{product}=="MatekH743", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="0037", ATTRS{product}=="PX4 FMU SmartAP AIRLink", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="2DAE", ATTRS{idProduct}=="1058", ATTRS{product}=="CubeOrange+", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="2DAE", ATTRS{idProduct}=="1012", ATTRS{product}=="CubeYellow", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="2DAE", ATTRS{idProduct}=="1016", ATTRS{product}=="CubeOrange", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3185", ATTRS{idProduct}=="0035", ATTRS{product}=="PX4 FMU v6X.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3185", ATTRS{idProduct}=="0038", ATTRS{product}=="PX4 FMU v6C.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3185", ATTRS{idProduct}=="0033", ATTRS{product}=="PX4 FMU v5X.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1B8C", ATTRS{idProduct}=="0036", ATTRS{product}=="PX4 FMU v6U.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0013", ATTRS{product}=="PX4 FMU v4.x PRO", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0011", ATTRS{product}=="PX4 FMU v2.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0012", ATTRS{product}=="PX4 FMU v4.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0032", ATTRS{product}=="PX4 FMU v5.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3162", ATTRS{idProduct}=="004b", ATTRS{product}=="PX4 SP RACING H7 EXTREME", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0030", ATTRS{product}=="MindPX FMU v2.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="3185", ATTRS{idProduct}=="0039", ATTRS{product}=="ARK FMU v6X.x", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0016", ATTRS{product}=="PX4 FreeFly RTK GPS", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="1024", ATTRS{product}=="mRoControlZeroH7 OEM", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="1017", ATTRS{product}=="mRoPixracerPro", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="1023", ATTRS{product}=="mRoControlZeroH7", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="008D", ATTRS{product}=="mRoControlZeroF7", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0021", ATTRS{product}=="PX4 AUAV X2.1", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="1022", ATTRS{product}=="mRoControlZero Classic", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="26ac", ATTRS{idProduct}=="0088", ATTRS{product}=="mRo x2.1-777", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="35a7", ATTRS{idProduct}=="0002", ATTRS{product}=="FCC-R1", SYMLINK+="px4fmu"
SUBSYSTEM=="tty", ATTRS{idVendor}=="35a7", ATTRS{idProduct}=="0001", ATTRS{product}=="FCC-K1", SYMLINK+="px4fmu"

View File

@@ -3,7 +3,7 @@
<h1>Clover Drone Kit Tools</h1> <h1>Clover Drone Kit Tools</h1>
<ul> <ul>
<li><a href="docs">View documentation</a> (snapshot of <a href="https://clover.coex.tech">clover.coex.tech</a>)</li> <li><a href="docs">View documentation</a> (snapshot of <a href="https://clovercoex.tech">clovercoex.tech</a>)</li>
<li><a href="topics.html">View topics</a></li> <li><a href="topics.html">View topics</a></li>
<li><a href="" id="wvs">View image topics</a> (<code>web_video_server</code>)</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="" id="butterfly">Open web terminal</a> (<code>Butterfly</code>)</li>

View File

@@ -1,236 +0,0 @@
// Browserified https://www.npmjs.com/package/json-to-pretty-yaml module
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function() {
"use strict";
var typeOf = require('remedial').typeOf;
var trimWhitespace = require('remove-trailing-spaces');
function stringify(data) {
var handlers, indentLevel = '';
handlers = {
"undefined": function() {
// objects will not have `undefined` converted to `null`
// as this may have unintended consequences
// For arrays, however, this behavior seems appropriate
return 'null';
},
"null": function() {
return 'null';
},
"number": function(x) {
return x;
},
"boolean": function(x) {
return x ? 'true' : 'false';
},
"string": function(x) {
// to avoid the string "true" being confused with the
// the literal `true`, we always wrap strings in quotes
return JSON.stringify(x);
},
"array": function(x) {
var output = '';
if (0 === x.length) {
output += '[]';
return output;
}
indentLevel = indentLevel.replace(/$/, ' ');
x.forEach(function(y, i) {
// TODO how should `undefined` be handled?
var handler = handlers[typeOf(y)];
if (!handler) {
throw new Error('what the crap: ' + typeOf(y));
}
output += '\n' + indentLevel + '- ' + handler(y, true);
});
indentLevel = indentLevel.replace(/ /, '');
return output;
},
"object": function(x, inArray, rootNode) {
var output = '';
if (0 === Object.keys(x).length) {
output += '{}';
return output;
}
if (!rootNode) {
indentLevel = indentLevel.replace(/$/, ' ');
}
Object.keys(x).forEach(function(k, i) {
var val = x[k],
handler = handlers[typeOf(val)];
if ('undefined' === typeof val) {
// the user should do
// delete obj.key
// and not
// obj.key = undefined
// but we'll error on the side of caution
return;
}
if (!handler) {
throw new Error('what the crap: ' + typeOf(val));
}
if (!(inArray && i === 0)) {
output += '\n' + indentLevel;
}
output += k + ': ' + handler(val);
});
indentLevel = indentLevel.replace(/ /, '');
return output;
},
"function": function() {
// TODO this should throw or otherwise be ignored
return '[object Function]';
}
};
return trimWhitespace(handlers[typeOf(data)](data, true, true) + '\n');
}
window.yamlStringify = stringify;
module.exports.stringify = stringify;
}());
},{"remedial":2,"remove-trailing-spaces":3}],2:[function(require,module,exports){
/*jslint onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true */
(function () {
"use strict";
var global = Function('return this')()
, classes = "Boolean Number String Function Array Date RegExp Object".split(" ")
, i
, name
, class2type = {}
;
for (i in classes) {
if (classes.hasOwnProperty(i)) {
name = classes[i];
class2type["[object " + name + "]"] = name.toLowerCase();
}
}
function typeOf(obj) {
return (null === obj || undefined === obj) ? String(obj) : class2type[Object.prototype.toString.call(obj)] || "object";
}
function isEmpty(o) {
var i, v;
if (typeOf(o) === 'object') {
for (i in o) { // fails jslint
v = o[i];
if (v !== undefined && typeOf(v) !== 'function') {
return false;
}
}
}
return true;
}
if (!String.prototype.entityify) {
String.prototype.entityify = function () {
return this.replace(/&/g, "&amp;").replace(/</g,
"&lt;").replace(/>/g, "&gt;");
};
}
if (!String.prototype.quote) {
String.prototype.quote = function () {
var c, i, l = this.length, o = '"';
for (i = 0; i < l; i += 1) {
c = this.charAt(i);
if (c >= ' ') {
if (c === '\\' || c === '"') {
o += '\\';
}
o += c;
} else {
switch (c) {
case '\b':
o += '\\b';
break;
case '\f':
o += '\\f';
break;
case '\n':
o += '\\n';
break;
case '\r':
o += '\\r';
break;
case '\t':
o += '\\t';
break;
default:
c = c.charCodeAt();
o += '\\u00' + Math.floor(c / 16).toString(16) +
(c % 16).toString(16);
}
}
}
return o + '"';
};
}
if (!String.prototype.supplant) {
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
}
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s*(\S*(?:\s+\S+)*)\s*$/, "$1");
};
}
// CommonJS / npm / Ender.JS
module.exports = {
typeOf: typeOf,
isEmpty: isEmpty
};
global.typeOf = global.typeOf || typeOf;
global.isEmpty = global.isEmpty || isEmpty;
}());
},{}],3:[function(require,module,exports){
"use strict";
/**
* removeTrailingSpaces
* Remove the trailing spaces from a string.
*
* @name removeTrailingSpaces
* @function
* @param {String} input The input string.
* @returns {String} The output string.
*/
module.exports = function removeTrailingSpaces(input) {
// TODO If possible, use a regex
return input.split("\n").map(function (x) {
return x.trimRight();
}).join("\n");
};
},{}]},{},[1]);

View File

@@ -64,8 +64,11 @@ function viewTopic(topic) {
} }
} }
let txt = `<div class=counter>${counter} received</div>${yamlStringify(msg)}`; // JSON.stringify(msg, null, 4); let width = Number(params.width) || 100;
topicMessage.innerHTML = txt; let indent = Number(params.indent) || 2;
let txt = YAML.stringify(msg, { lineWidth: width, indent: indent });
let html = `<div class=counter>${counter} received</div>${txt}`; // JSON.stringify(msg, null, 4);
topicMessage.innerHTML = html;
}); });
} }

19
clover/www/js/yaml.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
<script src="js/roslib.js"></script> <script src="js/roslib.js"></script>
<link rel="icon" href="data:,"> <!-- make chrome don't request icon --> <link rel="icon" href="data:,"> <!-- make chrome don't request icon -->
<script type="module" src="js/topics.js"></script> <script type="module" src="js/topics.js"></script>
<script src="js/json-to-pretty-yaml.js"></script> <script src="js/yaml.js"></script>
<style> <style>
#topics { line-height: 1.2em; } #topics { line-height: 1.2em; }
#topic-view { #topic-view {

View File

@@ -4,7 +4,7 @@ Blockly programming support for Clover.
<img src="screenshot.png" width=700> <img src="screenshot.png" width=700>
See user documentation at the [main Clover documentation site](https://clover.coex.tech/en/blocks.html). See user documentation at the [main Clover documentation site](https://clovercoex.tech/en/blocks.html).
Internal package documentation is given below. Internal package documentation is given below.
@@ -47,6 +47,7 @@ http://<hostname>/clover_blocks/?navigate_tolerance=0.5&sleep_time=0.1
* `~running` ([*std_msgs/Bool*](http://docs.ros.org/noetic/api/std_msgs/html/msg/Bool.html)) indicates if the program is currently running. * `~running` ([*std_msgs/Bool*](http://docs.ros.org/noetic/api/std_msgs/html/msg/Bool.html)) indicates if the program is currently running.
* `~block` ([*std_msgs/String*](http://docs.ros.org/noetic/api/std_msgs/html/msg/String.html)) current executing block (maximum topic rate is limited). * `~block` ([*std_msgs/String*](http://docs.ros.org/noetic/api/std_msgs/html/msg/String.html)) current executing block (maximum topic rate is limited).
* `~print` ([*std_msgs/String*](http://docs.ros.org/noetic/api/std_msgs/html/msg/String.html)) user program output messages (published in *print* blocks).
* `~error` ([*std_msgs/String*](http://docs.ros.org/noetic/api/std_msgs/html/msg/String.html))  user program errors and exceptions. * `~error` ([*std_msgs/String*](http://docs.ros.org/noetic/api/std_msgs/html/msg/String.html))  user program errors and exceptions.
* `~prompt` ([*clover_blocks/Prompt*](msg/Prompt.msg)) user input request (includes random request ID string). * `~prompt` ([*clover_blocks/Prompt*](msg/Prompt.msg)) user input request (includes random request ID string).

View File

@@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<package format="2"> <package format="2">
<name>clover_blocks</name> <name>clover_blocks</name>
<version>0.23.0</version> <version>0.25.0</version>
<description>Blockly programming support for Clover</description> <description>Blockly programming support for Clover</description>
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer> <maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>
<license>MIT</license> <license>MIT</license>

View File

@@ -166,7 +166,7 @@ def load(req):
return {'names': [], 'programs': [], 'message': str(e)} return {'names': [], 'programs': [], 'message': str(e)}
name_regexp = re.compile(r'^[a-zA-Z-_.]{0,20}$') name_regexp = re.compile(r'^[a-zA-Z1-9-_.]{0,30}$')
def store(req): def store(req):
if not name_regexp.match(req.name): if not name_regexp.match(req.name):

View File

@@ -12,7 +12,7 @@ const COLOR_FLIGHT = 293;
const COLOR_STATE = 36; const COLOR_STATE = 36;
const COLOR_LED = 143; const COLOR_LED = 143;
const COLOR_GPIO = 200; const COLOR_GPIO = 200;
const DOCS_URL = 'https://clover.coex.tech/en/blocks.html'; const DOCS_URL = 'https://clovercoex.tech/en/blocks.html';
var frameIds = [["body", "BODY"], ["markers map", "ARUCO_MAP"], ["marker", "ARUCO"], ["last navigate target", "NAVIGATE_TARGET"], ["map", "MAP"]]; var frameIds = [["body", "BODY"], ["markers map", "ARUCO_MAP"], ["marker", "ARUCO"], ["last navigate target", "NAVIGATE_TARGET"], ["map", "MAP"]];
var frameIdsWithTerrain = frameIds.concat([["terrain", "TERRAIN"]]); var frameIdsWithTerrain = frameIds.concat([["terrain", "TERRAIN"]]);
@@ -269,6 +269,19 @@ Blockly.Blocks['voltage'] = {
} }
}; };
Blockly.Blocks['get_rc'] = {
init: function () {
this.appendDummyInput()
.appendField("RC channel")
this.appendValueInput("CHANNEL")
.setCheck("Number");
this.setInputsInline(true);
this.setOutput(true, "Number");
this.setColour(COLOR_STATE);
this.setTooltip("Returns current RC channel value.");
this.setHelpUrl(DOCS_URL + '#' + this.type);
}
}
Blockly.Blocks['armed'] = { Blockly.Blocks['armed'] = {
init: function () { init: function () {

View File

@@ -100,6 +100,9 @@
<block type="mode"></block> <block type="mode"></block>
<block type="armed"></block> <block type="armed"></block>
<block type="voltage"></block> <block type="voltage"></block>
<block type="get_rc">
<value name="CHANNEL"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
</block>
</category> </category>
<category name="LED" colour="#02d754"> <category name="LED" colour="#02d754">
<block type="set_effect"> <block type="set_effect">

View File

@@ -83,6 +83,9 @@ function generateROSDefinitions() {
if (rosDefinitions.navigateGlobal) { if (rosDefinitions.navigateGlobal) {
code += `navigate_global = rospy.ServiceProxy('navigate_global', srv.NavigateGlobal)\n`; code += `navigate_global = rospy.ServiceProxy('navigate_global', srv.NavigateGlobal)\n`;
} }
if (rosDefinitions.setYaw) {
code += `set_yaw = rospy.ServiceProxy('set_yaw', srv.SetYaw)\n`;
}
if (rosDefinitions.setVelocity) { if (rosDefinitions.setVelocity) {
code += `set_velocity = rospy.ServiceProxy('set_velocity', srv.SetVelocity)\n`; code += `set_velocity = rospy.ServiceProxy('set_velocity', srv.SetVelocity)\n`;
} }
@@ -399,6 +402,12 @@ Blockly.Python.voltage = function(block) {
return [code, Blockly.Python.ORDER_FUNCTION_CALL]; return [code, Blockly.Python.ORDER_FUNCTION_CALL];
} }
Blockly.Python.get_rc = function(block) {
Blockly.Python.definitions_['import_rcin'] = 'from mavros_msgs.msg import RCIn';
var channel = Blockly.Python.valueToCode(block, 'CHANNEL', Blockly.Python.ORDER_NONE);
return [`rospy.wait_for_message('mavros/rc/in', RCIn).channels[${channel}]`, Blockly.Python.ORDER_FUNCTION_CALL]
}
function parseColor(color) { function parseColor(color) {
return { return {
r: parseInt(color.substr(2, 2), 16), r: parseInt(color.substr(2, 2), 16),

View File

@@ -1,6 +1,6 @@
<package format="2"> <package format="2">
<name>clover_description</name> <name>clover_description</name>
<version>0.23.0</version> <version>0.25.0</version>
<description>The clover_description package provides URDF models of the Clover series of quadcopters.</description> <description>The clover_description package provides URDF models of the Clover series of quadcopters.</description>
<maintainer email="sfalexrog@gmail.com">Alexey Rogachevskiy</maintainer> <maintainer email="sfalexrog@gmail.com">Alexey Rogachevskiy</maintainer>

View File

@@ -1,6 +1,6 @@
<package format="3"> <package format="3">
<name>clover_simulation</name> <name>clover_simulation</name>
<version>0.23.0</version> <version>0.25.0</version>
<description>The clover_simulation package provides worlds and launch files for Gazebo.</description> <description>The clover_simulation package provides worlds and launch files for Gazebo.</description>
<maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer> <maintainer email="okalachev@gmail.com">Oleg Kalachev</maintainer>

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

View File

@@ -12,4 +12,4 @@ If you have studied the documentation but have not found an answer to your quest
We also have a chat for programmers coding for PX4, autonomous navigation indoors, and drone swarms: [@DroneCode](tg://resolve?domain=DroneCode). We also have a chat for programmers coding for PX4, autonomous navigation indoors, and drone swarms: [@DroneCode](tg://resolve?domain=DroneCode).
You can download [PDF-version](https://clover.coex.tech/clover_en.pdf) of this documentation. You can download [PDF-version](https://clovercoex.tech/clover_en.pdf) of this documentation.

View File

@@ -57,6 +57,7 @@
* [COEX Pix](coex_pix.md) * [COEX Pix](coex_pix.md)
* [COEX PDB](coex_pdb.md) * [COEX PDB](coex_pdb.md)
* [COEX GPS](coex_gps.md) * [COEX GPS](coex_gps.md)
* [Using SSH keys](ssh_keys.md)
* [Guide on autonomous flight](auto_setup.md) * [Guide on autonomous flight](auto_setup.md)
* [Hostname](hostname.md) * [Hostname](hostname.md)
* [PX4 Simulation](sitl.md) * [PX4 Simulation](sitl.md)
@@ -105,6 +106,12 @@
* [Video contest](video_contest.md) * [Video contest](video_contest.md)
* [Educational contests](educational_contests.md) * [Educational contests](educational_contests.md)
* [Clover-based projects](projects.md) * [Clover-based projects](projects.md)
* [Clover Cloud Platform](clover-cloud-platform.md)
* [Autonomous Racing Drone](djs_phoenix_chetak.md)
* [Motion Capture System](mocap_clover.md)
* [Swarm in Blocks 2](swarm_in_blocks_2.md)
* [Advanced Clover 2](advanced_clover_simulator_platform.md)
* [Network of charging stations](liceu128.md)
* [Swarm-in-blocks](swarm_in_blocks.md) * [Swarm-in-blocks](swarm_in_blocks.md)
* [Obstacle avoidance using artificial potential fields method](obstacle-avoidance-potential-fields.md) * [Obstacle avoidance using artificial potential fields method](obstacle-avoidance-potential-fields.md)
* [The Clover Rescue Project](clover-rescue-team.md) * [The Clover Rescue Project](clover-rescue-team.md)

View File

@@ -0,0 +1,161 @@
# Advanced Clover 3: The Platform
[CopterHack-2023](copterhack2023.md), team **FTL**.
## Team Information
```cpp
#include "veryInterestingCommandDescription.h"
```
Team members:
- Maxim Ramanouski, [@max8rr8](https://t.me/max8rr8).
Country: Belarus.
## Project Description
Last year at CopterHack 2022, we created a [project](../ru/advanced_clover_simulator.html) that simplified the simulation of Clover, and in 2021, we created a [project](../ru/advanced_clover.html) that simplified the development of products for Clover (IDE and library for writing). The time has come to combine them and achieve unlimited power.
### Project Idea
The idea of the project is to combine CloverIDE and CloverSim (a tool for running Clover simulations). Thus, a platform is planned that allows developing products based on Clover using a simulator and an advanced IDE. The platform will include the following features:
- Add a web interface that allows using CloverSim without touching the command line.
- Work both in the browser (without installing anything) and from CLI.
- Have a course that covers different aspects of clover.
- Simplify installation, especially in WSL.
- Running a simulation on a remote device (more powerful computer or cloud).
### Project videos
Video presentation of the project: [link](https://www.youtube.com/watch?v=T4RU9sfxsSI).
Live presentation at CopterHack: TBD.
CLI demonstration: [link](https://www.youtube.com/watch?v=Ao-ukR58sSQ).
## Installation
Installation process is described in the [project documentation](https://ftl-team.github.io/clover_sim/#/?id=installation).
## Usage
The CloverSim platform offers a seamless workflow for users:
1. Users can effortlessly select or create a workspace and task and
launch them with ease.
![Step 1 screenshot](../assets/ftl/acp_workflow1.png)
2. After launching the simulation, users are presented with CloverSim WebUI that
provides them with an intuitive way to view their scores and progress,
control the simulator, and access task descriptions and scoring information.
From it users can open terminal, gzweb and more importantly they can easily
access the CloverSim IDE to solve task.
![Step 2 screenshot](../assets/ftl/acp_workflow2.png)
3. The IDE provides a full suite of tools and features for writing and
debugging code. One example is autocompletion to help streamline the
development process, making it more efficient and effective.
![Step 3 screenshot](../assets/ftl/acp_workflow3.png)
4. Users can launch their programs with ease and monitor its progress via
the GZWeb, CopterStatus, and SimulatorStatus views of the IDE.
![Step 4 screenshot](../assets/ftl/acp_workflow4.png)
5. Users can track their progress and scores in real-time and effortlessly
restart the simulator if necessary. Additionally, different randomization
seed can be set to check various inputs and outcomes.
We also have video demonstration/tutorial: [link](https://www.youtube.com/watch?v=aPOPHD3M3ZM).
## More features
- Easy installation process.
- Efficient simulation launch, surpassing traditional virtual machines.
- Generation of dynamic Gazebo worlds with randomization based on seed.
- Real-time task completion verification and score presentation.
- Execution with security in isolated containers.
- Multiple project capability without the need for multiple virtual machine images.
- WebUI for ease of use, removing the need to use the command line.
- IDE similar to VSCode with support for C++ and Python, including autocompletion and autoformatting.
- Custom-patched GZWeb with bug fixes and additional features, including the display of the Clover LED strip.
- GZWeb provides a follow-objects feature superior to that of Gazebo.
- IDE includes tools to interact with ROS, such as topic visualization, service calling, and image topic visualization.
- IDE also includes Copter Status, displaying most of the drone's information, including position, camera, and LED strip, in one view.
- IDE integrates with the simulator by providing control from it, viewing task descriptions, and opening GZWeb.
We also have developed a learning course based on CloverSim: [link](https://github.com/FTL-team/CloverSim_course). It currently has the following tasks:
- 1_thesquare - First task of CloverSim course with goal to fly square.
- 2_iseeall - Task that teaches how to interact with camera.
- 3_landmid - Find and land onto randomly positioned object.
- 4_flybyline - Flying along the line.
- 5_posknown - Find position of objects relative to ArUco map.
## More details
At this point, our platform consists of four major parts:
- [CloverSim](https://github.com/FTL-team/clover_sim) - tool that manages simulation.
- [CloverSim Basefs](https://github.com/FTL-team/clover_sim_basefs) - container image that is used in simulator.
- [Clover IDE](https://github.com/FTL-team/cloverIDE) - clover ide tools and theia.
- [CloverSim course](https://github.com/FTL-team/CloverSim_course) - course with tasks based on our platform.
### CloverSim
The simulation architecture is a continuation of work from CopterHack 2022, but while 2022 version was closer to Proof-of-Concept, the updated version is more robust.
There are three major difference in simulator architecture
- Replacement of `systemd-nspawn` with `runc` provides us higher degree of container control and seemingless support of non-systemd systems, for example WSL.
- Migration to squash fs images, which greatly reduced size of installed CloverSim from 13 gigabytes to just 3.5 gigabytes.
- Tasks are now mounted instead of being copied and also build before starting.
Because of the way catkin_make works, it is incredibly slow when new packages are added (whole cmake configuration is rerun for all packages). catkin_make provides a way to build only some packages, but it caches this packages and to reset this cache you need to recompile whole catkin_make. But we have found a solution: `catkin_make -DCATKIN_WHITELIST_PACKAGES="task;CloverSim" --build build_CloverSim` This command, builds only CloverSim and task package in separate build directory, this drastically reduces time that catkin_make takes, and keeps expected behavior of catkin_make without arguments.
There are also differences in tool that launches simulation:
- Client-server architecture allows us to create web UI and run CloverSim on server.
- More robust error handling improves user experience.
- Rewritten in rust, better reliability and development experience.
### CloverSim basefs
Version 2 integrates CloverIDE into system. We also updated clover in simulator to v0.23 and added web terminal. Basefs is now squashed and doesn't require additional installation. It also uses patched(by us) version of gzweb that is more suitable for our use-case:
- Unlike original GZWeb assets can be dynamically loaded, which is required to support dynamically generated tasks.
- It also implements multiple bugfixes for rendering, UI.
- Fixed performance, original gzweb had two constantly running loops that used 200% of cpu. We fixed this by instead using synchronization primitives.
- Clover LED strip is rendered, our gzweb connects to ROS and pulls LED data from there to render LED strip like Gazebo does.
- Users can now follow-objects like in Gazebo better actually.
- Reconnect on disconnect, when simulator is restarted gzweb looses connection and it now can automatically reconnect.
Patched gzweb available there: [FTL-team/gzweb](https://github.com/FTL-team/gzweb).
### CloverIDE
CloverIDE got some updates too:
- We have updated theia and extensions used.
- Better C++ support via clangd.
- Clover IDE tools can now reconnect after simulator restart.
- Copter Status now displays LED strip status.
- Tools ui has better support for different themes.
But the most important change is CloverSim integration, there are new tools (task description, simulator control and gzweb). While gzweb tool is just an iframe (though it's very cool to have it in IDE).
Task description and simulator control are more interesting as they have to interact with both IDE and CloverSim, to maintain different versions support we use quite interesting trick, extension webview after being initialized dynamically loads JavaScript from CloverSim. That provides better integration between two.
### CloverSim course
CloverSim course is a new part of our platform. It uses robust task API of CloverSim to create practical learning course. It currently teaches different aspects of clover development that i encountered during my participation in different contests involving clover. But we are happy to accpet suggestions about other aspects we should teach in out course.
## Conclusion
This project is a final (or maybe there is more?) project of our advanced clover saga. AdvancedClover is a project that is easy to use and greatly improves experience during learning about clover, participating in clover based competitions and development clover based projects. We thank COEX team for their support and look forward to further cooperation.

View File

@@ -136,7 +136,7 @@ navigate(x=2, y=2, z=2, speed=1, frame_id='aruco_map')
### Using a specific marker frame ### Using a specific marker frame
Starting with the [image](image.md) version 0.18, the drone also can fly relative to a marker in the map, even if it is not currently visible. Like with [single-marker navigation](aruco_marker.md#working-with-detected-markers), this works by setting the frame_id parameter to aruco_ID, where ID is the desired marker number. Starting with the [image](image.md) version 0.18, the drone also can fly relative to a marker in the map, even if it is not currently visible. Like with [single-marker navigation](aruco_marker.md#working-with-detected-markers), this works by setting the frame_id parameter to `aruco_ID`, where ID is the desired marker number.
The following code will move the drone to the point 1 meter above the center of marker 5: The following code will move the drone to the point 1 meter above the center of marker 5:

View File

@@ -72,12 +72,6 @@ Sample code to fly to a point 1 metre to the left and 2 metres above marker with
navigate(frame_id='aruco_7', x=-1, y=0, z=2) navigate(frame_id='aruco_7', x=-1, y=0, z=2)
``` ```
Sample code to rotate counterclockwise while hovering 1.5 metres above marker id 10:
```python
navigate(frame_id='aruco_10', x=0, y=0, z=1.5, yaw_rate=0.5)
```
Note that if the required marker isn't detected for 0.5 seconds after the `navigate` command, the command will be ignored. Note that if the required marker isn't detected for 0.5 seconds after the `navigate` command, the command will be ignored.
These frames may also be used in other services that accept TF frames (like `get_telemetry`). The following code will get the drone's position relative to the marker with id 3: These frames may also be used in other services that accept TF frames (like `get_telemetry`). The following code will get the drone's position relative to the marker with id 3:

View File

@@ -210,7 +210,7 @@ Most of the parameters for autonomous flight are located in the following direct
<arg name="aruco_vpe" default="true"/>` <arg name="aruco_vpe" default="true"/>`
``` ```
- Generate the ArUco markers field. See the article [Map-based navigation with ArUco markers] (aruco_map.md # marker map settings) for details. To generate markers, you need to enter a command with specific values. - Generate the ArUco markers field. See the article [Map-based navigation with ArUco markers](aruco_map.md#marker-map-definition) for details. To generate markers, you need to enter a command with specific values.
Here is the example generating command where: Here is the example generating command where:

View File

@@ -42,7 +42,7 @@ Main documentation: http://wiki.ros.org/roslaunch.
The list of nodes / programs declared for running is specified in file `/home/pi/catkin_ws/src/clover/clover/launch/clover.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/clover/clover/src`. Then add the start of your node to `clover.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`. Then add the start of your node to `clover.launch`, for example:
```xml ```xml
<node name="my_program" pkg="clover" type="my_program.py" output="screen"/> <node name="my_program" pkg="clover" type="my_program.py" output="screen"/>

View File

@@ -2,7 +2,7 @@
<img src="../assets/blocks/blockly.svg" width=200 align="right"> <img src="../assets/blocks/blockly.svg" width=200 align="right">
Visual blocks programming feature has been added to the [RPi image](image.md), starting with the version **0.21**. Blocks programming is implemented using [Google Blockly](https://developers.google.com/blockly) platform. Blocks programming integration can lower the entry barrier to a minimum. Visual blocks programming feature has been added to the [RPi image](image.md), starting with the version **0.21**. Blocks programming is implemented using [Google Blockly](https://developers.google.com/blockly) library. Blocks programming integration can lower the entry barrier to a minimum.
## Configuration ## Configuration

View File

@@ -1,5 +1,7 @@
# Working with the camera # Working with the camera
> **Note** The following applies to the [image version **0.24**](https://github.com/CopterExpress/clover/releases/tag/v0.24), which is not yet released. Older documentation is still available for [for version **0.23**](https://github.com/CopterExpress/clover/blob/f78a03ec8943b596d5a99b893188a159d5319888/docs/en/camera.md).
Make sure the camera is enabled in the `~/catkin_ws/src/clover/clover/launch/clover.launch` file: Make sure the camera is enabled in the `~/catkin_ws/src/clover/clover/launch/clover.launch` file:
```xml ```xml

View File

@@ -30,6 +30,16 @@ Print path to the current directory:
pwd pwd
``` ```
Go to the user's home directory:
```bash
# all three commands are equivalent, where the tilde character (~) is an abbreviated
# path entry to the home directory, and the $HOME variable stores this path
cd
cd ~
cd $HOME
```
Print contents of the `file.py` file: Print contents of the `file.py` file:
```bash ```bash

View File

@@ -0,0 +1,93 @@
# Clover Cloud Platform
[CopterHack-2023](copterhack2023.md), team **Clover Cloud Team**.
The list of our team members:
* Кирилл Лещинский / Kirill Leshchinskiy, [@k_leshchinskiy](https://t.me/k_leshchinskiy) - Team Lead.
* Кузнецов Михаил / Mikhail Kuznetsov, [@bruhfloppa](https://t.me/bruhfloppa) - Frontend Developer.
* Даниил Валишин / Daniil Valishin, [@Astel_1](https://t.me/Astel_1) - Backend Developer.
## Table of contents
* [Introduction](#introduction)
* [Usability](#usability)
* [How to work with our platform?](#how-to-work-with-our-platform)
* [About the development of the platform](#about-the-development-of-the-platform)
* [Conclusion](#conclusion)
## Video demonstration
<p align="center">
<a href="https://www.youtube.com/watch?v=FZPl2LOMgi4"><img img width="560" height="315" src="https://img.youtube.com/vi/FZPl2LOMgi4/maxresdefault.jpg" /></a>
</p>
## Introduction
Clover Cloud Platform is an innovative platform that enables users to access COEX Clover drone simulation online, without the need to download any programs or virtual machines.
> **Note** Visit our [documentation](https://docs.clovercloud.software) to learn all about the platform, its development and how to use it.
## Unleash Your Coding Power: Develop Autonomous Flight Code at Lightning Speed on Clover Cloud Platform
If you're a developer working on autonomous flight projects, you know how time-consuming and distracting all of the routine activities can be. Between managing your hardware, debugging, and configuring your environment, it can feel like the real work of coding gets lost in the shuffle.
That's where our platform comes in. Our streamlined interface and powerful tools make it easy to tackle all of those essential tasks so you can focus on what really matters: developing flawless, high-performance code for your autonomous flight project.
So why wait to unleash your coding power? Sign up for our platform today and discover the difference it can make in the speed, quality, and focus of your autonomous flight coding work.
## Usability
Our platform is incredibly user-friendly and provides seamless access to the simulation in just a few clicks. Together with a simulator that displays simulation data accurately and without delay, there is a map editor allows users to edit the ArUco marker map and add or modify other objects on the scene directly within the simulation window. Additionally, users can create pre-configured workspaces complete with autonomous flight code and simulation scene configuration. Each user can also create their templates or apply a pre-made one to their workspace in just a few clicks. In addition to its other features, Clover Cloud Platform provides users with a convenient code editor for autonomous flight coding. Users can write code in the built-in editor and run it directly from the editor, viewing program output in real-time in the terminal. The platform also includes a file manager that simplifies file manipulation tasks, further enhancing the user's overall experience. With these tools at your fingertips, Clover Cloud Platform delivers an unparalleled level of accessibility and convenience for autonomous flight simulation.
<p align="center">
<img src="https://raw.githubusercontent.com/Clover-Cloud-Platform/clover-cloud-platform-frontend/master/docs/workspace.png" alt="Workspace screenshot">
</p>
## The CodeSandbox for COEX Clover
You can describe the usability and relevance of our platform in another way. Have you heard of CodeSandbox? Our platform offers the same convenience, flexibility, and accessibility as CodeSandbox, but is specifically designed to work with the COEX Clover drone simulation.
## How to work with our platform?
Let's dive into the sea of functionality that our platform offers. Detailed description of each feature is available in our [documentation](https://docs.clovercloud.software), here we will provide a general overview of the platform.
### Creating an account
First, you should create an account on our site. You can do this by clicking on this [link](https://clovercloud.software/signup).
### Instance management
After creating an account, you will be taken to the [dashboard](https://clovercloud.software/instances). Here you can create, start, stop and delete workspaces.
>Workspaces are containers with Gazebo simulator and our software that provide data flow for simulation visualization, as well as handle requests from file manager, code editor and terminal.
<p align="center">
<img src="https://raw.githubusercontent.com/Clover-Cloud-Platform/clover-cloud-platform-frontend/master/docs/instances.gif" alt="Instance management">
</p>
### Workspace overview
In the workspace, in addition to the simulator, you have a file manager, code editor and terminal. There is also an editing mode in the simulator - one of the key features of our project. It allows you to quickly and conveniently edit the simulation scene, namely: move ArUco markers, change their size, change id of the marker, load instead of marker picture, add new markers or delete them. You can also add 3d objects to the scene and change their position, size and color. Below is an example of working with our workspace.
<p align="center">
<img src="https://github.com/Clover-Cloud-Platform/clover-cloud-platform-frontend/raw/master/docs/workspace.gif" alt="Workspace overview">
</p>
### Templates
Templates are another key feature of our platform.Is there something you can't do and you want to see how to properly perform a task? Look for the right template with ready-made code in the Template Browser and apply it to your workspace! Each user can create a template with an autonomous flight code and simulator configuration and share it.
## About the development of the platform
Our team has worked tirelessly to develop a simple yet multifunctional platform. We utilized the most modern standards and tools and implemented numerous optimization methods to ensure seamless performance and error-free operation. The frontend programming language chosen was JavaScript with the React framework, as a design system we utilizing Material Design style for an elegant and intuitive user interface. With the help of GitHub Actions the website is being built and deployed to Firebase hosting. The platform's backend is written in Python and contains multiple simultaneously running scripts. User data is secured and stored in a MongoDB database. Communication between the server and site is enabled through web sockets and the socket.io library, guaranteeing lightning-fast data transfer with minimal lag.
You can view the source code of our platform by clicking on the links below:
[Repository with the frontend-side code](https://github.com/Clover-Cloud-Platform/clover-cloud-platform-frontend)
[Repository with the backend-side code](https://github.com/Clover-Cloud-Platform/clover-cloud-platform-backend)
## Conclusion
In conclusion, we have successfully created a truly convenient and useful platform, suitable for both novice and advanced COEX Clover drone users. Beginners can test their first autonomous flight code without the need for demanding simulator installation or virtual machines. They can also explore all of the drone's functions and capabilities without editing any configuration files. Advanced users benefit from access to their workspace from anywhere in the world and on any device, along with a convenient code-sharing system. In the future, we plan to add more new features to our platform, scale our network to serve a greater number of users, and collaborate with COEX to integrate their Clover quadcopter documentation into our platform, offering users a very simple and user-friendly way to learn to program autonomous drone flight. We also want to express gratitude to the COEX customer support team for their assistance in resolving complex issues that arose during development.

View File

@@ -6,37 +6,59 @@ In order to program [autonomous flights](simple_offboard.md), [work with Pixhawk
USB connection is the preferred way to connect to the flight controller. USB connection is the preferred way to connect to the flight controller.
<img src="../assets/assembling_clever4/usb_connection_1.png" alt="USB connection" height=400 class="zoom border center">
1. Connect your FCU to the Raspberry Pi using a microUSB to USB cable. 1. Connect your FCU to the Raspberry Pi using a microUSB to USB cable.
2. [Connect to the Raspberry Pi over SSH](ssh.md). 2. [Connect to the Raspberry Pi over SSH](ssh.md).
3. Make sure the connection is working by [running the following command on the Raspberry Pi](ssh.md): 3. Make sure that the connection is working properly by [running the following command on the Raspberry Pi](cli.md):
```bash ```bash
rostopic echo /mavros/state rostopic echo /mavros/state
``` ```
The `connected` field should have the `True` value.s The `connected` field should have the `True` value.
> **Hint** You need to set the `CBRK_USB_CHK` [parameter](parameters.md) to 197848 for the USB connection to work. > **Hint** You need to set the `CBRK_USB_CHK` [parameter](parameters.md) to 197848 for the USB connection to work.
## UART connection ## UART connection
<!-- TODO: Connection scheme -->
UART connection is another way for the Raspberry Pi and FCU to communicate. UART connection is another way for the Raspberry Pi and FCU to communicate.
<img src="../assets/raspberry-uart-telemetry2.png" alt="UART connection via TELEM2" height=400 class="zoom border center">
If the pin marked GND is occupied, you can use any other ground pin (look at the [pinout](https://pinout.xyz) for reference).
1. Connect the TELEM 2 port on the flight controller using a UART cable to the Raspberry Pi pins following this instruction: the black cable (*GND*) to Ground, the green cable (*UART_RX*) to *GPIO14*, the yellow cable (*UART_TX*) to *GPIO15*. Do not connect the red cable (*5V*). 1. Connect the TELEM 2 port on the flight controller using a UART cable to the Raspberry Pi pins following this instruction: the black cable (*GND*) to Ground, the green cable (*UART_RX*) to *GPIO14*, the yellow cable (*UART_TX*) to *GPIO15*. Do not connect the red cable (*5V*).
2. Set the PX4 parameters: `MAV_1_CONFIG` to TELEM 2, `SER_TEL2_BAUND` to 921600 8N1. In PX4 of version prior to v1.10.0 the parameter `SYS_COMPANION` should be set to 921600. 2. In PX4 of version v1.9.0 or higher, set parameter values: `MAV_1_CONFIG` to TELEM 2, `SER_TEL2_BAUND` to 921600 8N1. In PX4 of version [prior to v1.9.0](https://github.com/mavlink/qgroundcontrol/issues/6905#issuecomment-464549610) the parameter `SYS_COMPANION` should be set to `Companion Link (921600 baud, 8N1)`, to set it correctly use the old version of QGC [v3.3.1](https://github.com/mavlink/qgroundcontrol/releases/tag/v3.3.1).
3. [Connect to the Raspberry Pi over SSH](ssh.md). 3. [Connect to the Raspberry Pi over SSH](ssh.md).
4. Change the connection type in `~/catkin_ws/src/clover/clover/launch/clover.launch` to UART: 4. Check the presence of the parameters `enable_uart=1` and `dtoverlay=pi 3-disable-bt` in the file `/boot/config.txt` by [running the following command on the Raspberry Pi](cli.md):
```bash
cat /boot/config.txt | grep -E "^enable_uart=.|^dtoverlay=pi3-disable-bt"
```
If the parameters in the file are different or missing, then edit the file and restart the Raspberry Pi.
5. Change the connection type from `usb` to `uart` in the Clover' launch file `~/catkin_ws/src/clover/clover/launch/clover.launch`:
```xml ```xml
<arg name="fcu_conn" default="uart"/> <arg name="fcu_conn" default="uart"/>
``` ```
Be sure to restart the `clover` service after editing the .launch file: If you change the launch file, you need to restart the `clover' service:
```bash ```bash
sudo systemctl restart clover sudo systemctl restart clover
``` ```
6. Make sure that the connection is working properly by running the following command:
```bash
rostopic echo -n1 /mavros/state
```
The `connected` field should have the `True` value.
Read more in the PX4 docs: https://docs.px4.io/main/en/peripherals/serial_configuration.html.
**Next**: [Using QGroundControl over Wi-Fi](gcs_bridge.md) **Next**: [Using QGroundControl over Wi-Fi](gcs_bridge.md)

View File

@@ -91,7 +91,7 @@ Prepare your article and send it as a pull request to the [Clover repository](ht
<img src="../assets/github-pull-request-create.png" alt="GitHub Create Pull"> <img src="../assets/github-pull-request-create.png" alt="GitHub Create Pull">
10. Wait for the review, be ready to make changes if needed. 10. Wait for the review, be ready to make changes if needed.
11. Look at your new and useful article at https://clover.coex.tech ! 11. Look at your new and useful article at https://clovercoex.tech !
## Easy way ## Easy way

View File

@@ -58,7 +58,7 @@ See all points by criteria in the [full table](https://docs.google.com/spreadshe
Teams are welcome to dive into the development of the following company cases: Teams are welcome to dive into the development of the following company cases:
1. Develop the Pixhawk FMUv6U flight controller board with the dimensions 55x40 mm and the compatibility of a Raspberry Pi CM 4 installation. 1. Develop the Pixhawk FMUv6U flight controller board with the dimensions 55x40 mm and the compatibility of a Raspberry Pi CM 4 installation.
2. Cloud platform for the [Clover simulator](https://clover.coex.tech/ru/simulation.html) similar as to/based on [ROS Development Studio](https://app.theconstructsim.com/). 2. Cloud platform for the [Clover simulator](https://clovercoex.tech/ru/simulation.html) similar as to/based on [ROS Development Studio](https://app.theconstructsim.com/).
The list of cases may be expanded in future. The list of cases may be expanded in future.

View File

@@ -8,27 +8,35 @@ To learn more about the articles of the CopterHack finalist teams follow the lin
The proposed projects are supposed to be open-source and be compatible with the Clover quadcopter platform. Teams-participants are supposed to work on their projects throughout the competition, bringing them closer to the state of the finished product while being assisted by industry experts through lectures and regular feedback. The proposed projects are supposed to be open-source and be compatible with the Clover quadcopter platform. Teams-participants are supposed to work on their projects throughout the competition, bringing them closer to the state of the finished product while being assisted by industry experts through lectures and regular feedback.
Final of the CopterHack 2022 was held on May 27, 2023. The winner team was the team 🇷🇺 **[Clover Cloud Platform](clover-cloud-platform.md)**.
## Full stream of the final
<iframe width="560" height="315" src="https://www.youtube.com/embed/Hdl6Sah7nkE" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## Projects of the contest's participants {#participants} ## Projects of the contest's participants {#participants}
|Place|Team|Project|Points| |Place|Team|Project|Points|
|:-:|-|-|-| |:-:|-|-|-|
||🇷🇺 Clover Cloud Team|[Clover Cloud Platform](https://github.com/DevMBS/clover/blob/clover-cloud-platform/docs/en/clover-cloud-platform.md)|| |1|🇷🇺 Clover Cloud Team|[Clover Cloud Platform](clover-cloud-platform.md)|21.7|
||🇰🇬 Zavarka|[Система обмена грузами с помощью конвейера](https://github.com/aiurobotics/clover/blob/conveyance/docs/ru/conveyance.md)|| |2|🇧🇾 FTL|[Advanced Clover 2](advanced_clover_simulator_platform.md)|21|
||🇮🇳 DJS PHOENIX|[Autonomous Racing Drone](https://github.com/DJSPhoenix/clover/blob/DJSPhoenix_chetak/docs/ru/djs_phoenix_chetak.md)|| |3|🇨🇦 Clover with Motion Capture System|[Clover with Motion Capture System](mocap_clover.md)|20.5|
||🇷🇺 FSOTM|[Drone Interceptor](https://github.com/deadln/clover/blob/interceptor/docs/ru/interceptor.md)|| |4|🇧🇷 Atena|[Swarm in Blocks 2](swarm_in_blocks_2.md)|20.3|
||🇰🇬 Homelesses|[Trash Collector](https://github.com/Isa-jesus/clover/blob/trash-collector/docs/ru/trash-collector.md)|| |5|🇷🇺 C305|[Система радио-навигации](../ru/nav-beacon.html)|17.5|
||🇷🇺 Digital otters|[Digital otters](https://github.com/Mentalsupernova/clover_cool/blob/new-article.md/docs/ru/new-article.md)|| |6|🇮🇳 DJS PHOENIX|[Autonomous Racing Drone](djs_phoenix_chetak.md)|14.6|
||🇷🇺 Light Flight|[Сопровождение БПЛА при посадке](https://github.com/SirSerow/clover_inertial_ns/blob/inertial-1/Description.md)|| |7|🇷🇺 Lyceum №128|[Network of Clover charging stations](liceu128.md)|13.7|
||🇰🇬 LiveSavers|[LiveSavers](https://github.com/Sarvar00/clover/blob/livesavers/docs/ru/livesaver.md)|| ||🇰🇬 Zavarka|[Система обмена грузами с помощью конвейера](https://github.com/aiurobotics/clover/blob/conveyance/docs/ru/conveyance.md)||
||🇷🇺 C305|[Система радио-навигации](https://github.com/Lukerrr/clover-c305/blob/nav_beacon/docs/ru/nav-beacon.md)|| ||🇷🇺 FSOTM|[Drone Interceptor](https://github.com/deadln/clover/blob/interceptor/docs/ru/interceptor.md)||
||🇷🇺 XenCOM|[Bound by fate](https://github.com/xenkek/clover/blob/xenkek-patch-1/docs/ru/bound_by_fate.md)|| |✕|🇰🇬 Homelesses|[Trash Collector](https://github.com/Isa-jesus/clover/blob/trash-collector/docs/ru/show_maker.md)||
||🇨🇦 Clover with Motion Capture System|[Clover with Motion Capture System](https://github.com/ssmith-81/clover/blob/MoCap_Clover/docs/en/mocap_clover.md)|| |✕|🇷🇺 Digital otters|[Digital otters](https://github.com/Mentalsupernova/clover_cool/blob/new-article.md/docs/ru/new-article.md)||
||🇧🇷 Atena|[Swarm in Blocks 2](https://github.com/Grupo-SEMEAR-USP/clover/blob/swarm_in_blocks_2/docs/en/swarm_in_blocks_2.md)|| |✕|🇷🇺 Light Flight|[Сопровождение БПЛА при посадке](https://github.com/SirSerow/clover_inertial_ns/blob/inertial-1/Description.md)||
||🇧🇾 FTL|[Advanced Clover 2](https://github.com/FTL-team/clover/blob/FTL-advancedClover3/docs/ru/advanced_clover_simulator_platform.md)|| |✕|🇰🇬 LiveSavers|[LiveSavers](https://github.com/Sarvar00/clover/blob/livesavers/docs/ru/livesaver.md)||
||🇷🇺 Лицей №128|[Платформа для зарядки квадрокоптера](https://github.com/Juli-Shvetsova/clover/blob/liceu128-1/docs/ru/liceu128.md)|| ||🇷🇺 XenCOM|[Bound by fate](https://github.com/xenkek/clover/blob/xenkek-patch-1/docs/ru/bound_by_fate.md)||
||🇷🇺 Ava_Clover|[DoubleClover](https://github.com/bessiaka/clover/blob/Ava_Clover/docs/ru/soosocta.md)|| ||🇷🇺 Ava_Clover|[DoubleClover](https://github.com/bessiaka/clover/blob/Ava_Clover/docs/ru/soosocta.md)||
||🇷🇺 TPU_1|[Совместная транспортировка груза](https://github.com/shamoleg/clover/blob/tpu_1/docs/ru/tpu_1.md)|| ||🇷🇺 TPU_1|[Совместная транспортировка груза](https://github.com/shamoleg/clover/blob/tpu_1/docs/ru/tpu_1.md)||
||🇷🇺 TPU_2|[Алгоритм полета сквозь лесную местность](https://github.com/shamoleg/clover/blob/tpu_2/docs/ru/tpu_2.md)|&nbsp;| ||🇷🇺 TPU_2|[Алгоритм полета сквозь лесную местность](https://github.com/shamoleg/clover/blob/tpu_2/docs/ru/tpu_2.md)|&nbsp;|
See all points by criteria in the [full table](https://docs.google.com/spreadsheets/d/1qTpW8zFVdSEGnbtOvMgQD6DcYwu8URFt1RKOCeUaOe8).
## CopterHack 2023 stages ## CopterHack 2023 stages

View File

@@ -0,0 +1,55 @@
# Autonomous Racing Drone: CHETAK
[CopterHack-2023](copterhack2023.md), team **DJS PHOENIX**.
## Team Information
![Without bg](https://user-images.githubusercontent.com/93365067/195974501-0acef6b7-e4ea-4c47-bd7a-615caf73a625.png)
We are the DJS Phoenix, the official drone team of Dwarkadas. J. Sanghvi College of Engineering
The list of team members:
* Shubham Mehta, @Just_me_05, Mentor.
* Harshal Warde, @kryptonisinert, Mechanical.
* Parth Sawjiyani, @Non_Active, Mechanical.
* Soham Dalvi, @devilsfootprint_1973, Mechanical.
* Vedant Patel, @VedantMP, Mechanical.
* Harsh Shah, @harssshhhhh, Mechanical.
* Lisha Mehta, @lishamehta, Mechanical.
* Shubh Pokarne, @Shubhpokarne, Electronics.
* Tushar Nagda, @tushar_n11, Electronics.
* Deep Tank, @Kraven, Electronics.
* Khushi Sanghvi, @Cryptoknigghtt, Programmer.
* Harshil Shah, @divine_fossil, Programmer.
* Omkar Parab, @Omkar_parab21, Programmer.
* Madhura Korgaonkar, @Madhura221, Programmer.
* Shruti Shah, @Shrutishah22, Programmer.
* Aditi Dubey, @aditi_0503, Marketing.
* Krisha Lakhani, @krishalakhani, Marketing.
## Project Description
This year, our team DJS Phoenix, presents to you a fully Autonomous Racing Drone. The drone scans for ArUco tags on the gates and passes through them.
### Project Idea
This project proposes to develop an autonomous racing drone that can navigate through complex courses at high speeds while avoiding obstacles and detecting changes in the environment. In racing competitions, autonomous drones can compete in high-speed, precision races that challenge their agility, speed, and accuracy. These competitions could be held in indoor arenas or outdoor tracks, and they could attract enthusiasts and spectators from all over the world. With their advanced capabilities, autonomous racing drones could usher in a new era of racing events that are more exciting and challenging than ever before. From racing competitions to search and rescue operations, the autonomous racing drone can be used in a wide range of applications that benefit individuals, businesses, and society as a whole.
## Potential Outcome
### Problem
In many industries and applications, there is a need for fast, efficient, and safe movement of goods and information. Drones have become an increasingly popular tool for a wide range of applications, from aerial photography to surveying and monitoring. However, operating a drone requires a certain level of skill and experience, which can be a barrier for individuals or businesses who want to take advantage of this technology. Additionally, traditional drones can be expensive and time-consuming to operate, limiting their accessibility and effectiveness. Therefore, there is a need for a more user-friendly and affordable solution that can expand the use of drones to new audiences and applications.
### Solution
The solution to the above problem statement is an autonomous racing drone. An autonomous racing drone is equipped with a camera that scans the ArUco tags for gate detection which is supported by software used in autonomous flights that enable it to navigate through a predetermined course while avoiding obstacles and achieving high speeds. Unlike traditional drones, an autonomous racing drone does not require manual control, making it an ideal solution for those who do not have the skills or experience to operate a drone.Its autonomous capabilities make it a more accessible and user-friendly solution than traditional drones, enabling individuals or businesses to take advantage of this technology without requiring extensive training or expertise.
![image](https://user-images.githubusercontent.com/93365067/235303281-f63e379d-c156-45ad-b554-2c84bd82781d.png)
### Additional Information
In 2017, a student committee for DJS Phoenix was formed. In India, our team has participated in a number of contests, including IDRL-IIT GandhiNagar (sixth rank), IDRL-SVPCET Nagpur(second rank) and TECHNOXIAN (second place out of 50 national teams). In CopterHack-2021, our team participated, and we placed eighth internationally. We are back with improved concepts after learning from the previous season.
For more information checkout gitbook: https://djs-phoenix.gitbook.io/chetak-faster-than-you-can-imagine/.

View File

@@ -9,7 +9,7 @@ The main goal of the contest is aerial robotics popularization and community de
### Lecture requirements ### Lecture requirements
* The topic of the lecture is of free choice. Programmable quadcopter kit COEX Clover 4 and/or The Clover simulation environment should be used as the main tool in the lecture. * The topic of the lecture is of free choice. Programmable quadcopter kit COEX Clover 4 and/or The Clover simulation environment should be used as the main tool in the lecture.
> **Note** *The version of COEX Clover is not earlier than [version 4](https://clover.coex.tech/en/assemble_4.html). The virtual machine image is not earlier than [version 1.0](https://github.com/CopterExpress/clover_vm/releases/tag/v1.0). > **Note** *The version of COEX Clover is not earlier than [version 4](https://clovercoex.tech/en/assemble_4.html). The virtual machine image is not earlier than [version 1.0](https://github.com/CopterExpress/clover_vm/releases/tag/v1.0).
* The video is uploaded on YouTube or another public platform and is public accessible. * The video is uploaded on YouTube or another public platform and is public accessible.
* The language of the lecture is any. The video contains subtitles in English in case the language is made neither of English nor Russian. * The language of the lecture is any. The video contains subtitles in English in case the language is made neither of English nor Russian.
* The duration of the lecture is limited from 15 min. to 3 hours. * The duration of the lecture is limited from 15 min. to 3 hours.
@@ -47,7 +47,7 @@ The main goal of the contest is aerial robotics popularization and community de
### Lesson requirements ### Lesson requirements
* Programmable quadcopter kit COEX Clover 4 should be used as the main tool for the lesson. * Programmable quadcopter kit COEX Clover 4 should be used as the main tool for the lesson.
> **Note** *The version of COEX Clover is not earlier than [version 4](https://clover.coex.tech/en/assemble_4.html). > **Note** *The version of COEX Clover is not earlier than [version 4](https://clovercoex.tech/en/assemble_4.html).
* Integration of the quadcopter into any of the general education disciplines (physics, mathematics, computer science, etc.). * Integration of the quadcopter into any of the general education disciplines (physics, mathematics, computer science, etc.).
* Practical use of the main tool in the lesson. * Practical use of the main tool in the lesson.
* Grade - no restrictions (primary, high school). * Grade - no restrictions (primary, high school).
@@ -88,7 +88,7 @@ The course is evaluated according to a separate, publicly available lesson submi
* The course is related to the direction of Aerial robotics. * The course is related to the direction of Aerial robotics.
* Programmable quadcopter kit COEX Clover 4 and/or The Clover simulation environment should be used as the main tool in the course; * Programmable quadcopter kit COEX Clover 4 and/or The Clover simulation environment should be used as the main tool in the course;
> **Note** *The version of COEX Clover is not earlier than [version 4](https://clover.coex.tech/en/assemble_4.html). The virtual machine image is not earlier than [version 1.0](https://github.com/CopterExpress/clover_vm/releases/tag/v1.0). > **Note** *The version of COEX Clover is not earlier than [version 4](https://clovercoex.tech/en/assemble_4.html). The virtual machine image is not earlier than [version 1.0](https://github.com/CopterExpress/clover_vm/releases/tag/v1.0).
* The course is located on a public platform (e.g., Coursera). * The course is located on a public platform (e.g., Coursera).
* The course can be either paid or free of charge. One public lesson from the course is submitted for the competition; * The course can be either paid or free of charge. One public lesson from the course is submitted for the competition;
* The lesson submitted for the contest should be publicly accessible. * The lesson submitted for the contest should be publicly accessible.

View File

@@ -17,6 +17,8 @@ It is advisable to use a specialized build of PX4 with the necessary fixes and b
</ul> </ul>
</div> </div>
> **Warning** If you are using the firmware version older than *v1.10* (for example, `v1.8.2-clover.13`), then in order to avoid configuration errors, use [QGroundControl version *v4.2.0*](https://github.com/mavlink/qgroundcontrol/releases/tag/v4.2.0) (or older). See [detailed information](https://docs.px4.io/v1.11/en/config/battery.html#parameter-migration-notes) about changes in the firmware parameters that cause errors in newer versions of QGroundControl.
<script type="text/javascript"> <script type="text/javascript">
// get latest release from GitHub // get latest release from GitHub
fetch('https://api.github.com/repos/CopterExpress/Firmware/releases').then(function(res) { fetch('https://api.github.com/repos/CopterExpress/Firmware/releases').then(function(res) {

View File

@@ -9,6 +9,7 @@ Main frames in the `clover` package:
* `base_link` is rigidly bound to the drone. It is shown by the simplified drone model on the image above; * `base_link` is rigidly bound to the drone. It is shown by the simplified drone model on the image above;
* `body` is bound to the drone, but its Z axis points up regardless of the drone's pitch and roll. It is shown by the red, blue and green lines in the illustration; * `body` is bound to the drone, but its Z axis points up regardless of the drone's pitch and roll. It is shown by the red, blue and green lines in the illustration;
* <a name="navigate_target"></a>`navigate_target` is bound to the current navigation target (as set by the [navigate](simple_offboard.md#navigate) service); * <a name="navigate_target"></a>`navigate_target` is bound to the current navigation target (as set by the [navigate](simple_offboard.md#navigate) service);
* `terrain` is bound to the floor at the current drone position (see the [set_altitude](simple_offboard.md#set_altitude) service);
* `setpoint` is current position setpoint; * `setpoint` is current position setpoint;
* `main_camera_optical` is the coordinate system, [linked to the main camera](camera_setup.md#frame); * `main_camera_optical` is the coordinate system, [linked to the main camera](camera_setup.md#frame);

View File

@@ -31,7 +31,7 @@ Before you test it you need to install on your laptop:
- Install Nodejs from [here](https://nodejs.org/en/download/). For [Ubuntu installation](https://tecadmin.net/install-latest-nodejs-npm-on-ubuntu/) - Install Nodejs from [here](https://nodejs.org/en/download/). For [Ubuntu installation](https://tecadmin.net/install-latest-nodejs-npm-on-ubuntu/)
- Install Yarn package manager from [here](https://yarnpkg.com/lang/en/docs/install/). [Usual problem](https://github.com/yarnpkg/yarn/issues/3189) while installing and using yarn with Ubuntu. - Install Yarn package manager from [here](https://yarnpkg.com/lang/en/docs/install/). [Usual problem](https://github.com/yarnpkg/yarn/issues/3189) while installing and using yarn with Ubuntu.
- Have an experience in manual control on the drone in case of any weird behavior happen. - Have an experience in manual control on the drone in case of any weird behavior happen.
- Worked before with COEX drones, if this is your first time to work with COEX drones check [this](https://clover.coex.tech/en/). - Worked before with COEX drones, if this is your first time to work with COEX drones check [this](https://clovercoex.tech/en/).
and you are ready to build and use the required codes. and you are ready to build and use the required codes.
@@ -145,7 +145,7 @@ Animation is created by [this](https://justsketchme.web.app/)
## References ## References
- [Human pose estimation guide](https://blog.nanonets.com/human-pose-estimation-2d-guide/) - [Human pose estimation guide](https://blog.nanonets.com/human-pose-estimation-2d-guide/)
- [Clover drones tutorials](https://clover.coex.tech/en/) - [Clover drones tutorials](https://clovercoex.tech/en/)
- [Posenet GitHub repo](https://github.com/tensorflow/tfjs-models/tree/master/posenet) - [Posenet GitHub repo](https://github.com/tensorflow/tfjs-models/tree/master/posenet)
- [Posenet meduim article](https://medium.com/tensorflow/real-time-human-pose-estimation-in-the-browser-with-tensorflow-js-7dd0bc881cd5) - [Posenet meduim article](https://medium.com/tensorflow/real-time-human-pose-estimation-in-the-browser-with-tensorflow-js-7dd0bc881cd5)
- [Tensorflow.js demos](https://www.tensorflow.org/js/demos) - [Tensorflow.js demos](https://www.tensorflow.org/js/demos)

45
docs/en/liceu128.md Normal file
View File

@@ -0,0 +1,45 @@
# "QCS" - the network of Clover charging stations
[CopterHack-2023](copterhack2023.md), team **Lyceum 128**.
## Network realisation
Our charging stations use Python web server created with Django framework. On that server we storage information about charging stations:
- Position (GPS + ArUco marker).
- Possibility to drone landing.
- Drone info (If it's on it).
To connect to server we use API with special personal key for every drone and station. It can be regenerated if secured key became public.
If you want to test station without drone you can use API Debug page. You must be in your account to open it.
### Electronics in the station
There are Arduino Mega and Wemos D1 on the station.
![scheme](https://github.com/Juli-Shvetsova/clover/assets/78372613/3ab05a79-0046-463b-83dd-4db06115909b)
Wemos D1 connect with server to collect information, do tasks. Arduino Mega receive signals from Wemos and make physical updates such as moving landing platform, LED indication and other more.
After completing mission Wemos send request to a server to confirm updates on the server.
## Clover flight
We're using recursive landing algorithm to achieve success landing. Small ArUco marker is on the landing platform. Camera can use this marker on the ~25cm height. Next drone use standard landing.
## Visit our landing and API page
[https://qcs.pythonanywhere.com/](https://qcs.pythonanywhere.com/)
## Source code
Of that project is in our [GitHub page](https://github.com/qcs-charge/).
## Team
CH2023, Lyceum 128.
- Mikhail Konstantinov, [@mikemka](https://t.me/mikemka/), programmer.
- Julia Shvecova, [@Juli_Phil](https://t.me/Juli_Phil/), science adviser.
- Oleg Sherstobitov, [@kulumuluu](https://t.me/kulumuluu/), constructor.

200
docs/en/mocap_clover.md Normal file
View File

@@ -0,0 +1,200 @@
# Project Video
[CopterHack-2023](copterhack2023.md), team **Clover with Motion Capture System**. Click logo for project video.
<div align="center">
<a href="https://www.youtube.com/watch?v=jOovjo0aBpQ&t=4s&ab_channel=SeanSmith"><img src="../assets/mocap_clover/semi_logo_small.jpg" width="70%" height="70%" alt="IMAGE ALT TEXT"></a>
</div>
## Table of Contents
* [Team Information](#item-one)
* [Educational Document](#item-two)
* [Introduction](#item-three)
* [Project Description](#item-four)
* [Hardware](#item-hardware)
* [Data Transfer](#item-transfer)
* [Examples](#item-examples)
* [Trajectory Tracking](#item-figure8)
* [Auto-Tuning](#item-auto)
* [Conclusion](#item-last)
## Team Information {#item-one}
The list of team members:
* Sean Smith, @ssmith_81, roboticist and developer: [GitHub](https://github.com/ssmith-81), [Linkedin](https://www.linkedin.com/in/sean-smith-61920915a/).
## Educational Document {#item-two}
**My Gitbook, with detailed step by step analysis of the proposed project during the CopterHack 2023 competition can be found:**
[MoCap Clover Gitbook](https://0406hockey.gitbook.io/mocap-clover/).
This page gives a broad overview on the motivation and purpose behind this project, it also provides research and industry based knowledge around UAV application that the reader may find interesting. If the user is interested in the technical details and implementation then refer to the educational Gitbook document.
## Introduction {#item-three}
Aerial robotics has become a common focus in research and industry over the past few decades. Many technical developments in research require a controlled test environment to isolate certain characteristics of the system for analysis. This typically takes place indoors to eliminate unwanted disturbances allowing results to be more predictable. Removing localization and pose feedback concerns can be accomplished with motion capture (MoCap) systems that track unmanned aerial vehicles (UAVs) pose with high precision as stated:
"OptiTracks drone and ground robot tracking systems consistently produce positional error less than 0.3mm and rotational error less than 0.05°" [[reference](https://optitrack.com/applications/robotics/#:~:text=Exceptional%203D%20precision%20and%20accuracy&text=OptiTrack's%20drone%20and%20ground%20robot,error%20less%20than%200.05%C2%B0)].
<!-- markdownlint-disable MD044 -->
This enables researchers to study the dynamics and behavior of UAVs in different environments, evaluate their performance, and develop advanced control algorithms for improved flight stability, autonomy, and safety. Research facilities around the world tend to built research drones from the ground up using off-the-shelf components with open source platforms such as PX4. While the end goal is the same: transferring pose feedback to the flight controller along with high level commands, the platforms and methods can vary significantly depending on factors such as onboard and offboard computing frameworks and data transfer methods. Many developers have a detailed background and understanding of the theoretical components of their research, however, adapting hardware configurations to their own platform such as sensor feedback and sensor fusion is not obvious. The purpose of this project is to provide detailed documentation on integrating the Clover platform with the MoCap system along with examples to familiarize users with the hardware, sensor fusion, high and low level controller development, and trajectory tracking.
<!-- markdownlint-enable MD044 -->
## Project Description {#item-four}
In this article, we will provide an overview of MoCap systems for tracking UAV pose in research applications, highlighting their significance, advantages, and potential impacts in the field of UAV controller development.
## Document structure
The Motion Capture System educational document is divided into three main sections outside of the Introduction and Conclusion. Each section and its purpose is listed:
### Hardware {#item-hardware}
The main goal in this section is to educate the reader on the MoCap system hardware and software. This can be further divided into several steps including camera placement, marker placement, and system calibration. A summary of the process is provided:
| Task | Description |
| --------- | ----------- |
| Camera Placement | Position the motion capture cameras in strategic locations around the area where the UAV will be flying. The number of cameras and their placement will depend on the size of the area and the desired capture volume. Typically, cameras are placed on tripods or mounted on walls or ceilings at specific heights and angles to capture the UAV's movements from different perspectives. **A simple 4-camera setup example is provided in the educational document**. |
| Marker Placement | Attach OptiTrack markers to the UAV in specific locations. OptiTrack markers are small reflective spheres that are used as reference points for the motion capture system to track the UAV's position and movements. **An example placement on the Clover is shown in the educational document**.
| System Calibration | Perform system calibration to establish the spatial relationship between the cameras and the markers. This involves capturing a calibration sequence, during which a known pattern or object is moved in the capture volume. The system uses this data to calculate the precise positions and orientations of the cameras and markers in 3D space, which is crucial for accurate motion capture. |
With these components completed correctly, you are well on your way to commanding indoor autonomous missions like this:
<p align="center">
<img title="Figure-8" alt="Alt text" src="../assets/mocap_clover/drone_approach_small.jpg" width="60%" height="50%">
</p>
<!--
- Testing and Validation: After setting up the cameras and markers, perform test flights with the UAV to validate the accuracy of the MoCap system. Analyze the captured data to ensure that the UAV's movements are accurately captured and that the system is functioning correctly.
- Fine-tuning: Fine-tune the motion capture system as needed based on the test results. This may involve adjusting camera angles, marker placements, or calibration settings to improve the accuracy and reliability of the system.
- Data Collection: Once the motion capture system is properly set up and calibrated, you can start collecting data for your UAV research. The system will continuously track the positions and movements of the markers on the UAV in real-time, providing precise data that can be used for various analyses and experiments.
- Data Analysis: Analyze the captured data using appropriate software to extract relevant information for your UAV research. This may involve tracking the UAV's position, velocity, acceleration, orientation, and other parameters, and analyzing how they change over time or in response to different conditions or inputs.
-->
Overall, configuring a motion capture system for UAV research requires careful planning, precise marker placement, accurate system calibration, and thorough validation to ensure accurate and reliable data collection for your research purposes. For more information, refer to the [informative documentation](https://0406hockey.gitbook.io/mocap-clover/hardware/motion-capture-setup-optitrack).
### Data Transfer {#item-transfer}
With the data acquired from the MoCap system, the main goal in this section is to transfer it to the Raspberry Pi onboard the Clover and remap it to the flight controller/PX4 for control. A summary of the steps are listed:
<p align="center">
<img title="Figure-8" alt="Alt text" src="https://drive.google.com/uc?export=view&id=1B0OMIGveFZNyE1_UHpmBOukeFVgl-bTV" width="50%" height="50%">
</p>
* Data Acquisition: The motion capture system continuously tracks the position and orientation (pose) of the UAV using markers attached to the UAV and cameras positioned in the capture volume. The system calculates the 3D pose of the UAV in real-time and can be viewed through the motive software.
* Data Transmission: The pose data is transmitted from the motion capture system to a Raspberry Pi using VRPN and a ROS network. While this works, I have implemented a strictly UDP data transmission method where highlighting the setup process and ease of use will be a future development, both configurations can be seen in the below figures. The Raspberry Pi acts as an intermediary for processing and relaying the data to the flight controller onboard the UAV using MAVROS. The connection can be established using USB or UART, I chose UART in my setups.
<p align="center">
<img src="../assets/mocap_clover/block_ROS.jpg" width="49%" alt="ROS Block"/>
<img src="../assets/mocap_clover/block_udp.jpg" width="49%" alt="ROS Block"/>
<em>Fig.1(a) - Left figure: ROS network experimental setup topology. Legend: Black dotted line is the provided local network; Blue solid line is the Clover pose transmission where the final transmission from laptop to Pi is over a ROS network; Red line is hardware connections; MAVLink arrow is communication via a MAVLink protocol. .</em> <br>
<em>Fig.1(b) - Right figure: UDP transmission experimental setup topology. Legend: Black dotted line is the provided local network; Black solid line is the UDP client-server drone pose transmission; Light blue line is the pose data transmission; Red line is hardware connections; Purple line is communication via secure shell protocol and ROS network communication; MAVLink arrow is communication via a MAVLink protocol. .</em>
</p>
* Data Processing: The Raspberry Pi receives the pose data from the motion capture system over a ROS network on a VRPN ROS topic, this was initially parsed from the sensor readings into position and attitude.
* Data Remapping: Once the pose data is processed, the Raspberry Pi maps it to the to a gateway/MAVROS topic sending it to the flight controller onboard the UAV. All coordinate transformations (ENU->NED) are taken care of with MAVROS.
* Flight Control Update: The flight controller onboard the UAV receives the remapped pose data and uses it to update the UAV's flight control algorithms. The updated pose information can be used to adjust the UAV's flight trajectory, orientation, or other control parameters to achieve the desired flight behavior or control objectives based on the motion capture system feedback.
* Closed-Loop Control: The flight controller continuously receives pose feedback from the motion capture system via the Raspberry Pi, and uses it to update the UAV's flight control commands in a closed-loop fashion (PX4 uses a cascaded PID control system with more details provided in the educational document). This allows the UAV to maintain precise position and orientation control based on the real-time pose data provided by the motion capture system.
Overall, sending pose feedback from a motion capture system to a Raspberry Pi and remapping the data to the flight controller onboard a UAV involves acquiring, processing, and transmitting the pose data in a compatible format to enable real-time closed-loop control of the UAV based on the motion capture system's feedback.
### Examples {#item-examples}
This section provides two practical examples to help the user better understand the Clover platform, sensor fusion, UAV applications such as trajectory tracking, high level commands, and low level control. The reader will become familiar with an abundance of state-of-the-art open source UAV platforms/technologies such as:
| Platform | Description |
| ----------- | ----------- |
| PX4 | PX4 is an open-source flight control software for drones and other unmanned vehicles used on the Clover. It supports a wide range of platforms and sensors and is used in commercial and research applications. |
| Robot Operating System (ROS) |ROS is an open-source software framework for building robotic systems. It provides a set of libraries and tools for developing and managing robot software and is widely used in drone and robotics research. |
| MAVLink| MAVLink is a lightweight messaging protocol for communicating with unmanned systems. It is widely used in drone and robotics applications and provides a flexible and extensible communication framework.|
|QGroundControl (QGC)| QGC is an open-source ground control station software for drones and other unmanned vehicles. It provides a user-friendly interface for managing and monitoring drone flights and is widely used in commercial and research applications. |
<a id="item-figure8"></a>
1. **A figure-8 high-level trajectory generation**: this example is outlined for both Software in the Loop (SITL) simulations and hardware testing with the Clover platform. Check out this interesting example from my [trajectory tracking section](https://0406hockey.gitbook.io/mocap-clover/examples/flight-tests/complex-trajectory-tracking)!
<p align="center">
<img title="Figure-8" alt="Alt text" src="https://drive.google.com/uc?export=view&id=1imlqhaUl-v6JuEiOFA4BPvO1N174NWgY">
</p>
<p align = "center">
<em>Fig.2 - Lemniscate of Bernoulli [<a href="https://upload.wikimedia.org/wikipedia/commons/f/f1/Lemniscate_of_Bernoulli.gif">reference</a>].</em>
</p>
Here's a summary of the importance of trajectory tracking for UAV applications:
* *Navigation and Path Planning*: Trajectory tracking allows UAVs to follow pre-defined paths or trajectories, which is essential for tasks such as aerial mapping, surveying, inspection, and monitoring.
* *Precision and Safety*: Trajectory tracking enables precise control of the UAV's position, velocity, and orientation, which is crucial for maintaining safe and stable flight operations. Precise trajectory tracking allows UAVs to avoid obstacles, maintain safe distances from other objects or aircraft, and operate in confined or complex environments with high precision, reducing the risk of collisions or accidents.
* *Autonomy and Scalability*: Trajectory tracking enables UAV autonomy, allowing them to operate independently without constant operator intervention. This enables UAVs to perform repetitive or complex tasks autonomously, freeing up human operators to focus on higher-level decision-making or supervisory roles. Trajectory tracking also facilitates scalable operations, where multiple UAVs can follow coordinated trajectories to perform collaborative tasks, such as swarm operations or coordinated data collection.
* *Flexibility and Adaptability*: Trajectory tracking allows UAVs to adapt their flight paths or trajectories in real-time based on changing conditions or objectives. UAVs can dynamically adjust their trajectories to accommodate changes in environmental conditions, mission requirements, or operational constraints, allowing for flexible and adaptive operations in dynamic or unpredictable environments.
In summary, trajectory tracking is crucial for UAV applications as it enables precise navigation, safety, efficiency, autonomy, and scalability, while optimizing payload performance and adaptability to changing conditions. It plays a fundamental role in ensuring that UAVs can accomplish their missions effectively and safely, making it a critical component of UAV operations in various industries and domains.
<a id="item-auto"></a>
1. **Clover adaptive auto-tuning**: The second example shows the user how to implement the adaptive auto-tune module provided by PX4 to tune the low-level controllers or attitude control module. You can take a look into how this is accomplished with the Clover platform in the [auto-tuning section](https://0406hockey.gitbook.io/mocap-clover/examples/auto-tuning).
<p align="center">
<img title="Figure-8" alt="Alt text" src="../assets/mocap_clover/px4_control_structure.jpg" width="80%" height="80%">
</p>
<p align = "center">
<em>Fig.3 - Cascaded PX4 control system [<a href="https://docs.px4.io/v1.12/en/flight_stack/controller_diagrams.html#multicopter-control-architecture">reference</a>].</em>
</p>
This is a much faster and easier way to tune a real drone and provides good tuning for most air frames. Manual tuning is recommended when auto-tuning dos not work, or when fine-tuning is essential. However, the process is tedious and not easy especially for users with limited control background and experience. The Clover airframe provides sufficient base settings where auto-tuning can further improve performance depending on the Clover being used.
Here's a summary of the importance of low-level controller performance for UAV applications:
* *Flight Stability and Safety*: The low-level controller, typically implemented as a PID (Proportional-Integral-Derivative) or similar control algorithm, governs the UAV's attitude and position control. Properly tuning the low-level controller ensures that the UAV remains stable during flight, with accurate and responsive control inputs. This is essential for safe and reliable UAV operations, as it helps prevent undesired oscillations, overshooting, or instability that can lead to crashes or accidents.
* *Control Precision and Responsiveness*: Accurate control is crucial for achieving precise and responsive UAV maneuvers, such as smooth trajectory tracking, precise hovering, or dynamic maneuvers. Proper tuning of the low-level controller allows for precise control of the UAV's attitude, position, and velocity, enabling it to accurately follow desired flight trajectories, respond to changing conditions or commands, and perform complex flight maneuvers with high precision.
* *Adaptability and Robustness*: UAV operations can be subject to varying environmental conditions, payload configurations, or operational requirements. Proper low-level controller tuning allows for adaptability and robustness, enabling the UAV to perform reliably and accurately across a wide range of conditions or mission requirements. Tuning the controller parameters can help account for changes in payload mass, wind conditions, or other external factors, ensuring stable and responsive flight performance.
<p align="center">
<img title="Figure-8" alt="Alt text" src="https://drive.google.com/uc?export=view&id=1ech31B2JvYLcW9c7W67IguuQT-S53AFF" width="50%" height="50%">
</p>
In summary, low-level controller tuning is crucial for UAV applications as it directly affects flight stability, control precision, payload performance, energy efficiency, adaptability, and compliance with safety and regulatory requirements. It is an essential step in optimizing the performance and safety of UAV operations, ensuring reliable and effective flight control for various applications across different industries and domains.
## Conclusion {#item-last}
Over the course of this project I was able to extend my knowledge in robotic applications while enduring many ups and downs along the way. This greatly helped me with my research when testing controller development was required. The motivation behind this documentation is to improve this experience for other researchers, robotic developers, or hobbyists that have a desire to learn fundamental robotic application which is beginning to shape the world we know today. These details can be explored in a [GitBook](https://0406hockey.gitbook.io/mocap-clover/) for those who are interested.
I provided many details on the interworking components required to achieve an indoor autonomous flight setup with the COEX Clover platform. With an extensive background in UAV control, I tried to provide a basic understanding of this for the readers benefit. There are many more sections I would like to include along with improving upon the existing ones. A few examples include firmware testing with hardware in the loop simulations, advanced trajectory generation, and an extensive list of flight examples for the Gazebo simulator with application to hardware.
Lastly, I would like to thank the entire COEX team that made this project possible by providing a wonderful platform with support. I would like to give a special thanks to [Oleg Kalachev](https://github.com/okalachev) for helping me debug and succeed through applied learning. With that being said, I hope you all enjoy the resourceful content provided, and I plan on releasing more detailed documents on other interesting topics as I progress through my research and development.
<!--
## Project description
This project is an educational reference and detailed tutorial on how to setup the OptiTrack Motion Capture (MoCap) system with the COEX Clover platform.
It gives brief descriptions on the camera and motive software setup with many resourceful links, but it assumes the user has a basic understanding on how to
setup the cameras and motive computer software. MoCap markers allow the MoCap to stream positional data of the Clover therefore marker placement is discussed.
From there details on how to stream position data from the MoCap to the Clover along with how to configure the Clover; specifically, the Raspberry Pi and PX4
firmware parameters are discussed. The overall network will be provided as it is the most important part.
At the end, I will provide an interesting example such as a tracking a complex trajectory that any user can implement.
### Project idea
In many research applications highly precise position feedback is required and that is why a MoCap system is popular in this field of robotics. Research papers
are published detailed around certain topics such as control, path planning, obstacle avoidance and many more although the details surrounding certain hardware
setups such as with the MoCap system are not provided. There are a few sources that provide help with setting up the MoCap system with PX4 and other specific
systems but with limited knowledge of how and why steps are made one might not be able to adapt it to their own setup such as with the Clover. That is why this
project has been created; so that a student or user can follow this tutorial with the COEX Clover and have a working setup with the MoCap and Clover even with
a limited understanding of software and hardware. The article also provides descriptions on why certain things are done to allow the user the better understand
the system setup.
I currently have the setup running but now working well. The Clover is unable to follow setpoints with any precision
therefore working through network and software issues seems to be the current stage (I am not sure what exactly is causing this issue actually). I am hoping to
receive guidance in this area from this project so I can have it working as desired.
### Using Clover platform
The COEX Clover 4.2 kit is used where the MoCap system setup is specific for the Clover platform. It provides useful information for all robotics users interested in
implementing external sensor feedback although it is specific for Clover owners.
### Additional information at the request of participants
I am a masters student looking to implement this project in my research.
-->

View File

@@ -198,6 +198,15 @@ This page contains models and drawings of some of the drone parts. They can be u
</tr> </tr>
</table> </table>
### 3D print
#### Mechanical gripper
* **Left claw**: [`grip_left.stl`](https://github.com/CopterExpress/clover/raw/master/docs/assets/stl/grip_left.stl).
* **Right claw**: [`grip_right.stl`](https://github.com/CopterExpress/clover/raw/master/docs/assets/stl/grip_right.stl).
Material: SBS Glass. Infill: 100%. Quantity: 1 pcs.
## Clover 4 ## Clover 4
### 3D print ### 3D print

View File

@@ -166,7 +166,7 @@ network={
} }
``` ```
Inside the config file, general `wpa_supplicant` settings, and the settings for the adapter configuration are specified. The configuration file also contains `network` section with the basic settings of the Wi-Fi network, such as network SSID, password, adapter operating mode. There may be several `network` sections, but only the first valid one is used. For example, if the first section contains a connection to an unavailable network, the adapter will be configured according to a next valid section, if there is one. Read more about the syntax of `wpa_supplicant.conf` [TODO WIKI]. Inside the config file, general `wpa_supplicant` settings, and the settings for the adapter configuration are specified. The configuration file also contains `network` section with the basic settings of the Wi-Fi network, such as network SSID, password, adapter operating mode. There may be several `network` sections, but only the first valid one is used. For example, if the first section contains a connection to an unavailable network, the adapter will be configured according to a next valid section, if there is one. Read more about the syntax of `wpa_supplicant.conf` in the [Debian manual page](https://manpages.debian.org/buster/wpasupplicant/wpa_supplicant.conf.5.en.html).
#### wpa_passphrase #### wpa_passphrase

View File

@@ -14,7 +14,7 @@ The list of team members:
<img src="https://github.com/den250400/potential-fields-obstacle-avoidance/raw/main/assets/avoidance_sim_demo.gif" class="center"/> <img src="https://github.com/den250400/potential-fields-obstacle-avoidance/raw/main/assets/avoidance_sim_demo.gif" class="center"/>
[This](https://github.com/den250400/potential-fields-obstacle-avoidance) repository contains obstacle avoidance system for quadcopters with Raspberry Pi 4 onboard computer. The code in this repository is designed to work with [Clover Raspberry Pi image](https://clover.coex.tech/en/image.html) and [special PX4-based firmware](https://clover.coex.tech/en/firmware.html) modified for easier communication with Raspberry Pi. [This](https://github.com/den250400/potential-fields-obstacle-avoidance) repository contains obstacle avoidance system for quadcopters with Raspberry Pi 4 onboard computer. The code in this repository is designed to work with [Clover Raspberry Pi image](https://clovercoex.tech/en/image.html) and [special PX4-based firmware](https://clovercoex.tech/en/firmware.html) modified for easier communication with Raspberry Pi.
Artificial potential fields method is based on considering quadcopter, obstacles and target point as electric-charged points. Quadcopter and obstacles have positive charge, and target point is assigned with negative charge. This results in quadcopter "attracting" itself to the target point, while being repelled by the same-signed charges of obstacles. Using this analogy, you can compute a safe, collision-free trajectory, which can be executed by the vehicle. Artificial potential fields method is based on considering quadcopter, obstacles and target point as electric-charged points. Quadcopter and obstacles have positive charge, and target point is assigned with negative charge. This results in quadcopter "attracting" itself to the target point, while being repelled by the same-signed charges of obstacles. Using this analogy, you can compute a safe, collision-free trajectory, which can be executed by the vehicle.
@@ -26,7 +26,7 @@ It's obvious that you need some sort of geometrical information about the surrou
This guide is intended to be used on Ubuntu 20.04. Python version is 3.8.10, but it's very likely that it will work on other versions like 3.7, 3.9, 3.10 without any changes. This guide is intended to be used on Ubuntu 20.04. Python version is 3.8.10, but it's very likely that it will work on other versions like 3.7, 3.9, 3.10 without any changes.
1. Install the [Clover simulator](https://clover.coex.tech/en/simulation.html). 1. Install the [Clover simulator](https://clovercoex.tech/en/simulation.html).
2. Install [realsense_gazebo_plugin](https://github.com/issaiass/realsense_gazebo_plugin) and [realsense2_description](https://github.com/issaiass/realsense2_description): 2. Install [realsense_gazebo_plugin](https://github.com/issaiass/realsense_gazebo_plugin) and [realsense2_description](https://github.com/issaiass/realsense2_description):
```bash ```bash

View File

@@ -66,11 +66,11 @@ Flying forward for 1m:
navigate(x=1.5, frame_id='body') navigate(x=1.5, frame_id='body')
``` ```
[Navigation using ArUco-markers](aruco_marker.md) and [using VPE] are available when using Optical Flow. [Navigation using ArUco-markers](aruco_marker.md) and [using VPE](aruco_map.md) are available when using Optical Flow.
## Additional settings ## Additional settings
<!-- TODO: статья по пидам --> For additional background on PID tuning, see the [PID tuning guide](calibratePID.md).
If the copter has an unstable position, try to increase the *P* coefficient of speed PID controller - parameters are `MPC_XY_VEL_P` and `MPC_Z_VEL_P`. If the copter has an unstable position, try to increase the *P* coefficient of speed PID controller - parameters are `MPC_XY_VEL_P` and `MPC_Z_VEL_P`.

View File

@@ -39,17 +39,28 @@ In case of using EKF2 (official firmware):
|Parameter|Value|Comment| |Parameter|Value|Comment|
|-|-|-| |-|-|-|
|`EKF2_AID_MASK`|26|Checkboxes: *flow* + *vision position* + *vision yaw*.<br>Details: [Optical Flow](optical_flow.md), [ArUco markers](aruco_map.md), [GPS](gps.md).| |`EKF2_AID_MASK`\*|26|Checkboxes: *flow* + *vision position* + *vision yaw*.<br>Details: [Optical Flow](optical_flow.md), [ArUco markers](aruco_map.md), [GPS](gps.md).|
|`EKF2_OF_DELAY`|0|| |`EKF2_OF_DELAY`|0||
|`EKF2_OF_QMIN`|10|| |`EKF2_OF_QMIN`|10||
|`EKF2_OF_N_MIN`|0.05|| |`EKF2_OF_N_MIN`|0.05||
|`EKF2_OF_N_MAX`|0.2|| |`EKF2_OF_N_MAX`|0.2||
|`EKF2_HGT_MODE`|3 (*Vision*)|If the [rangefinder](laser.md) is present and flying over horizontal floor  2 (*Range sensor*)| |`EKF2_HGT_MODE`\*|3 (*Vision*)|If the [rangefinder](laser.md) is present and flying over horizontal floor  2 (*Range sensor*)|
|`EKF2_EVA_NOISE`|0.1|| |`EKF2_EVA_NOISE`|0.1 rad or 5 deg||
|`EKF2_EVP_NOISE`|0.1|| |`EKF2_EVP_NOISE`|0.1||
|`EKF2_EV_DELAY`|0|| |`EKF2_EV_DELAY`|0||
|`EKF2_MAG_TYPE`|5 (*None*)|Disabling usage of the magnetometer (when navigating indoor)| |`EKF2_MAG_TYPE`|5 (*None*)|Disabling usage of the magnetometer (when navigating indoor)|
\* — starting from PX4 version 1.14, the parameters marked with an asterisk are replaced with the following:
|Parameter|Value|Comment|
|-|-|-|
|`EKF2_EV_CTRL`|11|Checkboxes: *Horizontal position* + *Vertical position* + *Yaw*|
|`EKF2_GPS_CTRL`|0|All checkboxes are disabled|
|`EKF2_BARO_CTRL`|0 (*Disabled*)|Barometer is disabled|
|`EKF2_OF_CTRL`|1 (*Enabled*)|Optical flow is enabled|
|`EKF2_HGT_REF`|3 (*Vision*)|If the [rangefinder](laser.md) is present and flying over horizontal floor  2 (*Range sensor*)|
|`EKF2_RNG_CTRL`|2 (*Enabled*)|Range sensor is enabled|
<!-- markdownlint-enable MD031 --> <!-- markdownlint-enable MD031 -->
> **Info** See also: list of default parameters of the [Clover simulator](simulation.md): https://github.com/CopterExpress/clover/blob/master/clover_simulation/airframes/4500_clover. > **Info** See also: list of default parameters of the [Clover simulator](simulation.md): https://github.com/CopterExpress/clover/blob/master/clover_simulation/airframes/4500_clover.

View File

@@ -51,6 +51,6 @@ The sticks on the screen of the application work just like real sticks. To arm t
Malfunctions Malfunctions
--- ---
* If the interface of the transmitter displays a surely incorrect voltage (e.g., > 5 V), check that the value of PX4 parameter `BAT_N_CELLS` matches the actual number of battery cells. If the displayed voltage is still incorrect, calibrate the battery (TODO: link). * If the interface of the transmitter displays a surely incorrect voltage (e.g., > 5 V), check that the value of PX4 parameter `BAT_N_CELLS` matches the actual number of battery cells. If the displayed voltage is still incorrect, calibrate the [power sensor](power.md).
* If instead of mode PX4, text "DISCONNECTED FROM FCU" is displayed, check [Raspberry Pi connection to Pixhawk](connection.md). * If instead of mode PX4, text "DISCONNECTED FROM FCU" is displayed, check [Raspberry Pi connection to Pixhawk](connection.md).

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