From 1dd098ba6b73d5e7807efa435b8d918b491a096c Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Tue, 21 Jun 2022 02:02:13 +0300 Subject: [PATCH 01/37] docs: redirect for blocks programming article --- redirects.json | 1 + 1 file changed, 1 insertion(+) diff --git a/redirects.json b/redirects.json index a9421177..07d1d70c 100644 --- a/redirects.json +++ b/redirects.json @@ -64,6 +64,7 @@ { "from": "connection/", "to": "en/connection.html" }, { "from": "clover_vm/", "to": "en/simulation_vm.html" }, { "from": "gpio/", "to": "en/gpio.html" }, + { "from": "blocks/", "to": "en/blocks.html" }, { "from": "ru/microsd_images.html", "to": "image.html" }, { "from": "en/microsd_images.html", "to": "image.html" }, From e8de04a1dd8c5f906cd5f52b1e7d1eb1065ffe22 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Thu, 14 Jul 2022 19:42:54 +0300 Subject: [PATCH 02/37] Add shortcut launch-file to run the simulation --- clover/launch/simulator.launch | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 clover/launch/simulator.launch diff --git a/clover/launch/simulator.launch b/clover/launch/simulator.launch new file mode 100644 index 00000000..c7427cf7 --- /dev/null +++ b/clover/launch/simulator.launch @@ -0,0 +1,4 @@ + + + + From a13806ef14210ddb85a2ce4e9bd0d4293233624d Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Fri, 15 Jul 2022 00:24:34 +0300 Subject: [PATCH 03/37] Minor whitespace fix --- clover/launch/simulator.launch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clover/launch/simulator.launch b/clover/launch/simulator.launch index c7427cf7..12475a8f 100644 --- a/clover/launch/simulator.launch +++ b/clover/launch/simulator.launch @@ -1,4 +1,4 @@ - - + + From 98d21d1760d0a84052154eb2f75be783acfe90bc Mon Sep 17 00:00:00 2001 From: Niels Hoppe Date: Mon, 18 Jul 2022 16:05:00 +0200 Subject: [PATCH 04/37] Add missing dependency --- clover/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/clover/CMakeLists.txt b/clover/CMakeLists.txt index 1144902d..abfaa9c3 100644 --- a/clover/CMakeLists.txt +++ b/clover/CMakeLists.txt @@ -17,6 +17,7 @@ find_package(catkin REQUIRED COMPONENTS message_generation geometry_msgs sensor_msgs + led_msgs geographic_msgs tf tf2 From 5325017a77ee2d678dfda21d41efda713ea7ecaa Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Tue, 19 Jul 2022 03:30:43 +0300 Subject: [PATCH 05/37] Implement dynamic reconfiguration for aruco_map (#448) --- aruco_pose/CMakeLists.txt | 1 + aruco_pose/cfg/Map.cfg | 14 +++++ aruco_pose/src/aruco_map.cpp | 85 ++++++++++++++++++++++------ aruco_pose/test/test_node_failure.py | 5 +- docs/en/snippets.md | 20 +++++++ docs/ru/snippets.md | 20 +++++++ 6 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 aruco_pose/cfg/Map.cfg diff --git a/aruco_pose/CMakeLists.txt b/aruco_pose/CMakeLists.txt index ce65c428..d1134eff 100644 --- a/aruco_pose/CMakeLists.txt +++ b/aruco_pose/CMakeLists.txt @@ -119,6 +119,7 @@ generate_messages( ## Generate dynamic reconfigure parameters in the 'cfg' folder generate_dynamic_reconfigure_options( cfg/Detector.cfg + cfg/Map.cfg ) ################################### diff --git a/aruco_pose/cfg/Map.cfg b/aruco_pose/cfg/Map.cfg new file mode 100644 index 00000000..8c10bb36 --- /dev/null +++ b/aruco_pose/cfg/Map.cfg @@ -0,0 +1,14 @@ +#!/usr/bin/env python +PACKAGE = "aruco_pose" + +from dynamic_reconfigure.parameter_generator_catkin import * + +gen = ParameterGenerator() + +gen.add("enabled", bool_t, 0, "if map detection enabled", True) + +gen.add("map", str_t, 0, "full path for the map file") + +gen.add("image_axis", bool_t, 0, "debug image axis", default=True) + +exit(gen.generate(PACKAGE, "aruco_pose", "Map")) diff --git a/aruco_pose/src/aruco_map.cpp b/aruco_pose/src/aruco_map.cpp index 02f32b0b..41250be8 100644 --- a/aruco_pose/src/aruco_map.cpp +++ b/aruco_pose/src/aruco_map.cpp @@ -19,11 +19,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -41,6 +43,7 @@ #include #include +#include #include #include @@ -74,6 +77,9 @@ private: tf2_ros::StaticTransformBroadcaster static_br_; tf2_ros::Buffer tf_buffer_; tf2_ros::TransformListener tf_listener_{tf_buffer_}; + std::shared_ptr> dyn_srv_; + bool enabled_ = true; + std::string type_; visualization_msgs::MarkerArray vis_array_; std::string known_tilt_, map_, markers_frame_, markers_parent_frame_; int image_width_, image_height_, image_margin_; @@ -96,8 +102,7 @@ public: static_cast(nh_priv_.param("dictionary", 2))); camera_matrix_ = cv::Mat::zeros(3, 3, CV_64F); - std::string type, map; - type = nh_priv_.param("type", "map"); + type_ = nh_priv_.param("type", "map"); transform_.child_frame_id = nh_priv_.param("frame_id", "aruco_map"); known_tilt_ = nh_priv_.param("known_tilt", ""); auto_flip_ = nh_priv_.param("auto_flip", false); @@ -110,13 +115,13 @@ public: // createStripLine(); - if (type == "map") { - param(nh_priv_, "map", map); - loadMap(map); - } else if (type == "gridboard") { + if (type_ == "map") { + map_ = nh_priv_.param("map" , ""); + loadMap(map_); + } else if (type_ == "gridboard") { createGridBoard(nh_priv_); } else { - NODELET_FATAL("unknown type: %s", type.c_str()); + NODELET_FATAL("unknown type: %s", type_.c_str()); ros::shutdown(); } @@ -124,10 +129,7 @@ public: vis_markers_pub_ = nh_priv_.advertise("visualization", 1, true); debug_pub_ = it_priv.advertise("debug", 1); - publishMarkersFrames(); - publishMarkers(); - publishMapImage(); - vis_markers_pub_.publish(vis_array_); + publishMap(); image_sub_.subscribe(nh_, "image_raw", 1); info_sub_.subscribe(nh_, "camera_info", 1); @@ -136,6 +138,12 @@ public: sync_.reset(new message_filters::Synchronizer(SyncPolicy(10), image_sub_, info_sub_, markers_sub_)); sync_->registerCallback(boost::bind(&ArucoMap::callback, this, _1, _2, _3)); + dyn_srv_ = std::make_shared>(nh_priv_); + dynamic_reconfigure::Server::CallbackType cb; + + cb = std::bind(&ArucoMap::paramCallback, this, std::placeholders::_1, std::placeholders::_2); + dyn_srv_->setCallback(cb); + NODELET_INFO("ready"); } @@ -143,6 +151,9 @@ public: const sensor_msgs::CameraInfoConstPtr& cinfo, const aruco_pose::MarkerArrayConstPtr& markers) { + if (!enabled_) return; + if (markers->markers.empty()) return; // map not loaded + int valid = 0; int count = markers->markers.size(); std::vector ids; @@ -268,9 +279,17 @@ publish_debug: std::ifstream f(filename); std::string line; + clearMarkers(); + + if (map_ == "") { + NODELET_INFO("No map loaded"); + return; + } + if (!f.good()) { - NODELET_FATAL("%s - %s", strerror(errno), filename.c_str()); - ros::shutdown(); + NODELET_ERROR("%s - %s", strerror(errno), filename.c_str()); + map_ = ""; + return; } while (std::getline(f, line)) { @@ -296,9 +315,10 @@ publish_debug: s.putback(first); } else { // Probably garbage data; inform user and throw an exception, possibly killing nodelet - NODELET_FATAL("Malformed input: %s", line.c_str()); - ros::shutdown(); - throw std::runtime_error("Malformed input"); + NODELET_ERROR("Malformed input: %s", line.c_str()); + map_ = ""; + clearMarkers(); + return; } if (!(s >> id >> length >> x >> y)) { @@ -329,6 +349,14 @@ publish_debug: NODELET_INFO("loading %s complete (%d markers)", filename.c_str(), static_cast(board_->ids.size())); } + void publishMap() + { + publishMarkersFrames(); + publishMarkers(); + publishMapImage(); + vis_markers_pub_.publish(vis_array_); + } + void createGridBoard(ros::NodeHandle& nh) { NODELET_INFO("generate gridboard"); @@ -370,6 +398,15 @@ publish_debug: } } + void clearMarkers() + { + board_->ids.clear(); + board_->objPoints.clear(); + markers_.markers.clear(); + vis_array_.markers.clear(); + markers_transforms_.clear(); + } + // void createStripLine() // { // visualization_msgs::Marker marker; @@ -509,6 +546,22 @@ publish_debug: msg.image = image; img_pub_.publish(msg.toImageMsg()); } + + void paramCallback(aruco_pose::MapConfig &config, uint32_t level) + { + // https://github.com/CopterExpress/clover/commit/2cd334c474e3ed04ef65ca1ba7f08ab535a3dc6d#diff-942723f9452c398ae93f1a91427f9a7b614be5e5871f8a3e590f324d804f0d58R356 + enabled_ = config.enabled; + if (type_ == "map" && config.map != map_) { + map_ = config.map; + loadMap(map_); + publishMap(); + } + + if (config.image_axis != image_axis_) { + image_axis_ = config.image_axis; + publishMapImage(); + } + } }; PLUGINLIB_EXPORT_CLASS(ArucoMap, nodelet::Nodelet) diff --git a/aruco_pose/test/test_node_failure.py b/aruco_pose/test/test_node_failure.py index e0d8b2e9..cb28cfc7 100755 --- a/aruco_pose/test/test_node_failure.py +++ b/aruco_pose/test/test_node_failure.py @@ -2,6 +2,7 @@ import rospy import pytest from visualization_msgs.msg import MarkerArray as VisMarkerArray +from aruco_pose.msg import MarkerArray @pytest.fixture @@ -9,5 +10,5 @@ def node(): return rospy.init_node('aruco_pose_test', anonymous=True) def test_node_failure(node): - with pytest.raises(rospy.exceptions.ROSException): - rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5) + assert rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5).markers == [] + assert rospy.wait_for_message('aruco_map/map', MarkerArray, timeout=5).markers == [] diff --git a/docs/en/snippets.md b/docs/en/snippets.md index 1d0c3a41..87eade17 100644 --- a/docs/en/snippets.md +++ b/docs/en/snippets.md @@ -390,6 +390,26 @@ rospy.sleep(5) flow_client.update_configuration({'enabled': True}) ``` + + +### # {#aruco-map-dynamic} + +> **Info** For [RPi image](image.md) version > 0.23. + +Change the used [ArUco markers map file](aruco_map.md) dynamically: + + + +```python +import rospy +import dynamic_reconfigure.client + +rospy.init_node('flight') +map_client = dynamic_reconfigure.client.Client('aruco_map') + +map_client.update_configuration({'map': '/home/pi/catkin_ws/src/clover/aruco_pose/map/office.txt'}) +``` + ### # {#wait-global-position} Wait for global position to appear (finishing [GPS receiver](gps.md) initialization): diff --git a/docs/ru/snippets.md b/docs/ru/snippets.md index 7a9f2271..30bf38ce 100644 --- a/docs/ru/snippets.md +++ b/docs/ru/snippets.md @@ -401,6 +401,26 @@ rospy.sleep(5) flow_client.update_configuration({'enabled': True}) ``` + + +### # {#aruco-map-dynamic} + +> **Info** Для [образа](image.md) версии > 0.23. + +Динамически изменить используемый файл с [картой ArUco-маркеров](aruco_map.md): + + + +```python +import rospy +import dynamic_reconfigure.client + +rospy.init_node('flight') +map_client = dynamic_reconfigure.client.Client('aruco_map') + +map_client.update_configuration({'map': '/home/pi/catkin_ws/src/clover/aruco_pose/map/office.txt'}) +``` + ### # {#wait-global-position} Ожидать появления глобальной позиции (окончания инициализации [GPS-приемника](gps.md)): From 840f2c220ce664189a9f964501a154ba6ce214ae Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Tue, 26 Jul 2022 21:25:01 +0300 Subject: [PATCH 06/37] simulator: change COM_RCL_EXCEPT param to enable offboard flights without RC on PX4 v1.13 --- clover_simulation/airframes/4500_clover | 1 + 1 file changed, 1 insertion(+) diff --git a/clover_simulation/airframes/4500_clover b/clover_simulation/airframes/4500_clover index a68f5d8b..0039c50d 100644 --- a/clover_simulation/airframes/4500_clover +++ b/clover_simulation/airframes/4500_clover @@ -11,6 +11,7 @@ param set-default ATT_W_EXT_HDG 0.5 param set-default ATT_EXT_HDG_M 1 # 0 = none, 1 = vision, 2 = mocap param set-default COM_DISARM_LAND 1.0 +param set-default COM_RCL_EXCEPT 4 # enable offboard flights without rc param set-default LPE_FLW_SCALE 1.0 param set-default LPE_FLW_R 0.2 From c64a80312ce64eaae848711a84909c4f5419fa5c Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Fri, 29 Jul 2022 06:05:48 +0300 Subject: [PATCH 07/37] Make PX4 node required in the sim --- clover_simulation/launch/simulator.launch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clover_simulation/launch/simulator.launch b/clover_simulation/launch/simulator.launch index 30c036cb..059dc1e5 100644 --- a/clover_simulation/launch/simulator.launch +++ b/clover_simulation/launch/simulator.launch @@ -21,7 +21,7 @@ - + @@ -36,7 +36,7 @@ - + From 54e685a9d61561afa2676720d91ddd9ddc18be40 Mon Sep 17 00:00:00 2001 From: Elena Seliverstova <64311178+SeliverstovaE@users.noreply.github.com> Date: Tue, 9 Aug 2022 10:15:56 +0300 Subject: [PATCH 08/37] docs: add new articles about CopterHack2023 (#450) --- docs/assets/copterhack2023.svg | 61 ++++++++++++++ docs/en/SUMMARY.md | 1 + docs/en/copterhack2023.md | 147 +++++++++++++++++++++++++++++++++ docs/ru/SUMMARY.md | 1 + docs/ru/copterhack2023.md | 147 +++++++++++++++++++++++++++++++++ 5 files changed, 357 insertions(+) create mode 100644 docs/assets/copterhack2023.svg create mode 100644 docs/en/copterhack2023.md create mode 100644 docs/ru/copterhack2023.md diff --git a/docs/assets/copterhack2023.svg b/docs/assets/copterhack2023.svg new file mode 100644 index 00000000..d77cd335 --- /dev/null +++ b/docs/assets/copterhack2023.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/SUMMARY.md b/docs/en/SUMMARY.md index f45551e9..ab2c3239 100644 --- a/docs/en/SUMMARY.md +++ b/docs/en/SUMMARY.md @@ -96,6 +96,7 @@ * [Migration to v0.20](migrate20.md) * [Migration to v0.22](migrate22.md) * [Events](events.md) + * [CopterHack-2023](copterhack2023.md) * [CopterHack-2022](copterhack2022.md) * [CopterHack-2021](copterhack2021.md) * [CopterHack-2019](copterhack2019.md) diff --git a/docs/en/copterhack2023.md b/docs/en/copterhack2023.md new file mode 100644 index 00000000..7d89e33c --- /dev/null +++ b/docs/en/copterhack2023.md @@ -0,0 +1,147 @@ +# CopterHack 2023 + + + +CopterHack 2023 is an international open-source projects competition on aerial robotics. The main direction of the CopterHack is team competition with a free choice of the project topic. The competition’s official language is English. + +To learn more about the articles of the CopterHack finalist teams follow the links [CopterHack 2021](copterhack2021.md), [CopterHack 2022](copterhack2022.md). + +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. + +## CopterHack 2023 stages + +The qualifying and project development stages will be held in an online format, however, the final round will be in a hybrid mode (offline + online). The competition involves monthly updates from the teams with regular feedback from the jury. All teams are required to prepare a final video and presentation on the project's results to participate in the final stage. + +1. Qualifying stage. Applications are accepted on the deadline date until October 31, 2022. +2. Projects development stage. This stage includes monthly updates and mentorship of participants. Starting date - November 1, 2022. Deadline date - February 28, 2023. +3. All teams-participants are required to make the final video to proceed to the final round. Final videos are required to be uploaded until March 31, 2023. +4. The final round. Projects presentation takes place April 23, 2023. + +## Conditions and criteria for evaluation the final result + +General project requirements: + +1. Open-source. +2. Compatibility with the Clover platform. + +Judging criteria for the jury at the final: + +1. Readiness and the article (max. 10 points): the degree of readiness of the project; an accessible and understandable description of the project in the article; a link to the code with comments, diagrams, drawings. It should be possible to reproduce the project and get the result according to the article. +2. Amount of work done (max. 6 points): the amount of work done by the team in the framework within of CopterHack, its complexity, and the technical level. +3. Usefulness for Clover (max. 6 points): the relevance to the Clover and PX4 platform application in practice, the potential level of demand from other Clover users. +4. Presentation at the final (max. 3 points): quality and entertainment points of the final presentation; completeness of the project coverage; demonstration; answers to the jury's questions. + +## Prize fund + +Basing on the results of the evaluation of projects at the final round, the jury will select the winners with the following prizes. + +* 1st place: $3000 (USD). +* 2nd place: $2000 (USD). +* 3rd place: $1000 (USD). +* 4th place: $500 (USD). +* 5th place: $500 (USD). + +The competition partners can reward the teams according to additional criteria identified during the evaluation of projects during the final round. + +## How to apply? + +> **Note** In order to be able to apply, you must have an account on [GitHub](https://github.com). + +Prepare your application and send it as a Draft Pull Request to [Clover repository](https://github.com/CopterExpress/clover) + +1. Fork the Clover repository: + + GitHub Fork + +2. On the web page of your fork, go to the `docs/en` section and create a new file in the [Markdown](http://en.wikipedia.org/wiki/Markdown) format: + + GitHub Create New File + +3. Enter the title of your article. For example, `new-article.md` + + GitHub New Article + +4. Fill in your application by the recommended template: + + ```markdown + # Project name + + [CopterHack-2023](copterhack2023.md), team **Team name**. + + ## Team information + + The list of team members: + + (Describe the team: full name, contacts (Telegram username), role in the team). + + * Alexander Sokolov, @aleksandrsokolov111, engineer. + * Elena Smirnova, @elenasmirnova111, programmer. + + ## Project description + + ### Project idea + + Briefly describe the idea and stage of the project. + + ### The potential outcomes + + Describe how you see the project result. + + ### Using Clover platform + + Describe how the Clover platform will be used in your project. + + ### Additional information at the request of participants + + For example, information about the team's experience while working on projects, attach a link to articles, videos. + ``` + +5. Go to the bottom of the page and create a new branch with the title of your article: + + GitHub Propose New File + + > **Note** Don't commit changes directly to the `master` branch, create a new branch. + +6. If necessary, place additional visual assets in the `docs/assets` folder and add them to your article. + +7. Send a Draft Pull Request from your branch to Clover: + + GitHub Create Pull + +8. In the Pull Request comments, you will be given feedback on the application. + +9. Please note, in the *Checks* block the *Documentation* field should contain a tick, id cross appeared, click *Details* link to see the list of issues in you article found by markdownlint. If you need to change added files, edit them in you branch – changes will appear in the Pull Request automatically. **Do not open a new Pull Request for the same application**. + +10. During the contest, you will work on this document, bringing it closer to the finished state. By the end of the contest you are expected to publish your article which is supposed to be the result of your work in CopterHack. + +Teams-participants are supposed to be added to the special Telegram group, where one can send the project's updates and get feedback from the Jury. For all participating teams, COEX will provide a 40% discount on the Clover drone kit. + +> **Info** There are no restrictions on the age, education, and number of people in a team. + +## CopterHack 2023 projects’ papers contest + +Our participants have been engaged in advanced projects in the field of aerial robotics for already two years. This year we are planning to launch a new type of contest stimulating participants to present the research results running within the whole contest, at high -level international conferences as well as to publish them in Russian and international magazines in thematic areas. + +Original articles are accepted in following nominations: + +* $2000 (USD) for an article in a magazine of first quartile (Q1), indexed in Scopus, Web of Science. +* $1000 (USD) for an article in a magazine, indexed in Scopus, Web of Science. +* $500 (USD) for an article, published in Compendium (Conference Proceedings), indexed in Scopus, Web of Science. + +> **Note** [Easy way to find quartiles for journals in Web of Science and Scopus](https://www.texpedi.com/2021/07/how-to-find-journal-quartile.html). + +Requirements: + +1. The article is required to reflect the results of the project, developed within CopterHack 2023. +2. The article is required to be accepted for publication by the moment of application for the Contest. +3. It is required to indicate in the acknowledgement area that work is accomplished within the Contest. + +**Applications deadline**: December 10, 2023. The application for the contest should be submitted through the [Google Form](https://docs.google.com/forms/d/e/1FAIpQLSf52x0CTur-wUCG2URwY-p85gEUBUvgC0mPVNot0RHVjqcLZA/viewform). + +**Results announcement**: December 24, 2023. + +--- + +For all questions: [CopterHack in Telegram](https://t.me/CopterHack). + +> **Info** Please contact [Oleg Ponfilenok in Telegram](@ponfilenok) if you are interested in becoming the contest's partner or jury member. diff --git a/docs/ru/SUMMARY.md b/docs/ru/SUMMARY.md index 127d16da..347b8635 100644 --- a/docs/ru/SUMMARY.md +++ b/docs/ru/SUMMARY.md @@ -109,6 +109,7 @@ * [Виртуальная MAVLink-камера](duocam_mavlink.md) * [Настройка DuoCam](duocam_setup.md) * [Мероприятия](events.md) + * [CopterHack-2023](copterhack2023.md) * [CopterHack-2022](copterhack2022.md) * [CopterHack-2021](copterhack2021.md) * [CopterHack-2019](copterhack2019.md) diff --git a/docs/ru/copterhack2023.md b/docs/ru/copterhack2023.md new file mode 100644 index 00000000..a922a594 --- /dev/null +++ b/docs/ru/copterhack2023.md @@ -0,0 +1,147 @@ +# CopterHack 2023 + + + +CopterHack 2023 — это международный конкурс по разработке проектов по летающей робототехнике с открытым исходным кодом. Основным языком конкурса является английский. + +Ознакомиться со статьями команд-финалистов предыдущих лет можно в статьях о [CopterHack 2021](copterhack2021.md), [CopterHack 2022](copterhack2022.md). + +На конкурс принимаются проекты с открытым исходным кодом и совместимые с платформой квадрокоптера "Клевер". На протяжении конкурса команды работают на собственными идеями и разработками, приближая их к состоянию готового продукта. В этом участникам помогают эксперты отрасли через лекции и регулярную обратную связь. + +## Этапы CopterHack 2023 + +Отборочный и проектный этапы конкурса проходят в онлайн-формате, формат проведения финала – гибридный (оффлайн + онлайн). Конкурс подразумевает ежемесячные апдейты от команд с получением регулярной обратной связи от жюри. Для участия в заключительном этапе необходимо подготовить финальное видео и презентацию о результатах проекта. + +1. Отборочный этап. Подача заявок (до 31 октября 2022). +2. Проектный этап. Менторство проектов (1 ноября 2022 — 28 февраля 2023). +3. Подготовка финального видео (1 — 31 марта 2023). +4. Заключительный этап. Финальная защита проектов на английском языке (23 апреля 2023). + +## Условия и критерии оценки + +Условия, предъявляемые к проектам: + +1. Открытый исходный код/модели/схемы/чертежи. +2. Совместимость с платформой "Клевер". + +Критерии оценивания жюри в финале: + +1. Готовность и статья (макс. 10 баллов): степень готовности проекта; доступное и понятное описание проекта в статье; прикреплены код с комментариями, схемы, чертежи. По статье должно быть возможно повторить проект, получить результат. +2. Объем проделанной работы (макс. 6 баллов): объем проделанной командой работы в рамках CopterHack, ее сложность и технический уровень. +3. Полезность для Клевера (макс. 6 баллов): актуальность применения на практике в платформе Клевер и PX4, потенциальный уровень спроса на разработку со стороны других пользователей Клевера. +4. Презентация на финале (макс. 3 балла): качество и зрелищность финальной презентации; полнота освещения проекта; демонстрация; ответы на вопросы жюри. + +## Призовой фонд + +Призы от компании COEX по результатам оценивания жюри на финале: + +* I место: $3000. +* II место: $2000. +* III место: $1000. +* IV место: $500. +* V место: $500. + +Партнеры конкурса могут поощрить команды по дополнительным критериям, выявленным в результате оценки проектов в ходе финала. + +## Как подать заявку? + +> **Note** Для подачи заявки необходимо иметь аккаунт на [GitHub](https://github.com). + +Подготовьте вашу заявку и пришлите ее в виде Draft Pull Request в [репозиторий Клевера](https://github.com/CopterExpress/clover). + +1. Сделайте форк репозитория Клевера: + + GitHub Fork + +2. На странице вашего форка зайдите в раздел `docs/ru` и создайте новый файл в формате [Markdown](https://ru.wikipedia.org/wiki/Markdown): + + GitHub Create New File + +3. Введите название вашей статьи. Например, `new-article.md` + + GitHub New Article + +4. Оформите вашу заявку в соответствии с рекомендуемым шаблоном: + + ```markdown + # Название проекта + + [CopterHack-2023](copterhack2023.md), команда **Название команды**. + + ## Информация о команде + + Состав команды: + + (Опишите состав команды: имя и фамилия, контакты (имя пользователя в Telegram), роль в команде). + + * Александр Соколов, @aleksandrsokolov111, инженер. + * Елена Смирнова, @elenasmirnova111, программист. + + ## Описание проекта + + ### Идея проекта + + Опишите кратко идею и стадию проекта. + + ### Планируемые результаты + + Опишите как вы видите результат проекта. + + ### Использование платформы "Клевер" + + Опишите как в вашем проекте будет использоваться платформа "Клевер". + + ### Дополнительная информация по желанию участников + + Например, информация об опыте работы команды над проектами, прикрепить ссылку на статьи, видео. + ``` + +5. Перейдите вниз страницы и создайте новую ветку с названием вашей статьи: + + GitHub Propose New File + + > **Note** Не добавляйте ваши изменения непосредственно в ветку `master`, создайте новую ветку. + +6. При необходимости поместите дополнительные визуальные материалы в папку `docs/assets` и оформите на них ссылки в вашей статье. + +7. Сделайте Draft Pull Request вашей ветки в master Клевера: + + GitHub Create Pull + +8. В комментариях Pull Request вам будет дана обратная связь по заявке. + +9. Обратите внимание на блок *Checks*, в графе Documentation должна стоять галочка. Если там стоит крестик, перейдите по ссылке *Details*, чтобы увидеть список проблем с оформлением статьи. При необходимости изменения добавляемых файлов, меняйте их в вашей ветке – изменения будут появляться в Pull Request автоматически. **Не создавайте новый Pull Request для одной и той же заявки**. + +10. На протяжении конкурса вы будете работать над этим документом, приближая его к состоянию статьи. В документе будет видна история разработки и ежемесячные апдейты. К финалу конкурса вы сможете опубликовать вашу статью, это и будет результат вашей работы в CopterHack. + +Участники конкурса будут добавлены в Telegram-группу, куда можно отправлять первый апдейт и получить обратную связь от жюри. Для команд-участников предусмотрена скидка 40% на конструктор программируемого квадрокоптера "Клевер". + +> **Info** Ограничения по возрасту, образованию и количеству человек в команде отсутствуют. + +## Конкурс статей участников проектов CopterHack 2023 + +Наши участники уже 2 года работают над передовыми проектами в области летающей робототехники. В этом году мы хотим ввести новый конкурс, стимулирующий участников презентовать результаты исследований, выполняющихся в рамках конкурса на престижных международных конференциях, а также публиковать их в российских и международных журналах по тематике конкурса. + +На конкурс принимаются оригинальные статьи в следующих номинациях: + +* $2000 за статью в журнале первого квартиля (Q1), индексируемом в Scopus, Web of Science. +* $1000 за статью журнале, индексируемом в Scopus, Web of Science. +* $500 за статью, опубликованную в сборнике материалов конференции (Conference Proceedings), индексируемые в Scopus, Web of Science. + +> **Note** [Как узнать квартиль журнала в Scopus и WOS](http://russian-science.info/kak-uznat-kvartil-i-protsentil-zhurnala-v-scopus-i-wos). + +Правила: + +1. Статья должна отражать результаты проекта, разработанного в рамках CopterHack 2023. +2. Статья должна быть принята к печати к моменту подачи заявки на участие в конкурсе статей. +3. В acknowledgment следует указать, что работа выполнена в рамках конкурса. + +**Прием заявок**: до 10 декабря 2023 года. Прием заявок осуществляется через [Google Форму](https://docs.google.com/forms/d/e/1FAIpQLSf52x0CTur-wUCG2URwY-p85gEUBUvgC0mPVNot0RHVjqcLZA/viewform). + +**Объявление результатов**: 24 декабря 2023 года. + +--- + +По всем вопросам: [группа CopterHack в Telegram](https://t.me/CopterHack). + +> **Info** Если вы хотите стать партнером конкурса или членом жюри, обращайтесь к [Олегу Понфиленку в Telegram](@ponfilenok). From bb68b56c25ceb9b32b193ce447f966cfe0c87988 Mon Sep 17 00:00:00 2001 From: Elena Seliverstova <64311178+SeliverstovaE@users.noreply.github.com> Date: Tue, 9 Aug 2022 19:59:55 +0300 Subject: [PATCH 09/37] Update the contact link in Telegram --- docs/en/copterhack2023.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/copterhack2023.md b/docs/en/copterhack2023.md index 7d89e33c..2c5cb2f9 100644 --- a/docs/en/copterhack2023.md +++ b/docs/en/copterhack2023.md @@ -144,4 +144,4 @@ Requirements: For all questions: [CopterHack in Telegram](https://t.me/CopterHack). -> **Info** Please contact [Oleg Ponfilenok in Telegram](@ponfilenok) if you are interested in becoming the contest's partner or jury member. +> **Info** Please contact [Oleg Ponfilenok in Telegram](https://t.me/ponfilenok) if you are interested in becoming the contest's partner or jury member. From e0f200f069fc4ad3c218918013884e360c71b83f Mon Sep 17 00:00:00 2001 From: Elena Seliverstova <64311178+SeliverstovaE@users.noreply.github.com> Date: Tue, 9 Aug 2022 20:01:38 +0300 Subject: [PATCH 10/37] Update the contact link in Telegram --- docs/ru/copterhack2023.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/copterhack2023.md b/docs/ru/copterhack2023.md index a922a594..5d2484c4 100644 --- a/docs/ru/copterhack2023.md +++ b/docs/ru/copterhack2023.md @@ -144,4 +144,4 @@ CopterHack 2023 — это международный конкурс по ра По всем вопросам: [группа CopterHack в Telegram](https://t.me/CopterHack). -> **Info** Если вы хотите стать партнером конкурса или членом жюри, обращайтесь к [Олегу Понфиленку в Telegram](@ponfilenok). +> **Info** Если вы хотите стать партнером конкурса или членом жюри, обращайтесь к [Олегу Понфиленку в Telegram](https://t.me/ponfilenok). From a2d984272b25c993bc28eada60d7238b94dc87dd Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Thu, 18 Aug 2022 18:17:30 +0300 Subject: [PATCH 11/37] Deploy docs using build artifacts instead of gh-pages branch (#452) https://github.blog/changelog/2021-12-16-github-pages-using-github-actions-for-builds-and-deployments-for-public-repositories/ --- .github/workflows/docs.yml | 42 +++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 530aaffb..195c67a8 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -4,16 +4,25 @@ on: push: branches: [ '*' ] pull_request: - branches: [ master ] + branches: [ '*' ] + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: true + +defaults: + run: + shell: bash jobs: docs: runs-on: ubuntu-18.04 steps: - - name: Cancel previous runs - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - uses: actions/checkout@v2 - name: Use Node.js uses: actions/setup-node@v1 @@ -58,11 +67,20 @@ jobs: rm -f _book/clover*.pdf wget --no-verbose https://clover.coex.tech/clover_ru.pdf -P _book/ wget --no-verbose https://clover.coex.tech/clover_en.pdf -P _book/ - - name: Deploy - uses: JamesIves/github-pages-deploy-action@4.1.3 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + - name: Upload artifact + # if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + uses: actions/upload-pages-artifact@v1 with: - branch: gh-pages - folder: _book - clean: true - single-commit: true # to avoid multiple copies of large pdf files + path: _book + + deploy-docs: + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: docs + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v1 From 596a7276ac1635e19a29a7d805ca736fef91bb23 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Thu, 18 Aug 2022 22:57:17 +0300 Subject: [PATCH 12/37] Update docs job runner to ubuntu 22.04 https://github.com/actions/runner-images/issues/6002 --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 195c67a8..a9dc26a8 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -21,7 +21,7 @@ defaults: jobs: docs: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Use Node.js From 2372cdd7db38e62c9e6ff7d9ddf357fc4574ab06 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Fri, 19 Aug 2022 00:17:34 +0300 Subject: [PATCH 13/37] vpe_publisher: fix reading map and base link frame_id from mavros --- clover/src/vpe_publisher.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clover/src/vpe_publisher.cpp b/clover/src/vpe_publisher.cpp index b28d9f6e..4a7778d7 100644 --- a/clover/src/vpe_publisher.cpp +++ b/clover/src/vpe_publisher.cpp @@ -124,8 +124,8 @@ int main(int argc, char **argv) { nh_priv.param("frame_id", frame_id, ""); nh_priv.param("offset_frame_id", offset_frame_id, ""); - nh_priv.param("mavros/local_position/frame_id", local_frame_id, "map"); - nh_priv.param("mavros/local_position/tf/child_frame_id", child_frame_id, "base_link"); + nh.param("mavros/local_position/frame_id", local_frame_id, "map"); + nh.param("mavros/local_position/tf/child_frame_id", child_frame_id, "base_link"); offset_timeout = ros::Duration(nh_priv.param("offset_timeout", 3.0)); if (!frame_id.empty()) { From 687a4f50fd9f7bb5a271a62d7e242c5ba08e3164 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Wed, 24 Aug 2022 22:42:18 +0300 Subject: [PATCH 14/37] Fix python-pymavlink installation adding some lxml dependencies Otherwise installation falls with: Error: Please make sure the libxml2 and libxslt development packages are installed --- clover/package.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clover/package.xml b/clover/package.xml index 8572828a..1c49e2b1 100644 --- a/clover/package.xml +++ b/clover/package.xml @@ -37,6 +37,8 @@ rosbridge_server web_video_server tf2_web_republisher + libxml2 + libxslt python-lxml python3-lxml dynamic_reconfigure From 47c6e5aa9b3f7e7eca2ab37d6e22c4cde4dad921 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Thu, 25 Aug 2022 18:28:52 +0300 Subject: [PATCH 15/37] docs: comment out link to install_software.sh in simulation installation manual The link confuses users so they often try to run it --- docs/en/simulation_native.md | 2 +- docs/ru/simulation_native.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/simulation_native.md b/docs/en/simulation_native.md index 41d877a6..d78ef8de 100644 --- a/docs/en/simulation_native.md +++ b/docs/en/simulation_native.md @@ -2,7 +2,7 @@ Setting up the simulation environment from scratch requires some effort, but results in the most performant setup, with less chance of driver issues. -> **Hint** See up-to-date commands set for installation Clover simulation software in the script, that builds the virtual machine image with the simulator: [`install_software.sh`](https://github.com/CopterExpress/clover_vm/blob/master/scripts/install_software.sh). + Prerequisites: **Ubuntu 20.04**. diff --git a/docs/ru/simulation_native.md b/docs/ru/simulation_native.md index 90573756..e4851384 100644 --- a/docs/ru/simulation_native.md +++ b/docs/ru/simulation_native.md @@ -2,7 +2,7 @@ Настройка среды для симуляции с нуля требует некоторых усилий, однако это приведет к улучшению производительности и к уменьшению вероятности появления проблем с драйверами. -> **Hint** Смотрите актуальный набор команд установки необходимого ПО для запуска симулятора Клевера в скрипте сборки виртуальной машины с симулятором: [`install_software.sh`](https://github.com/CopterExpress/clover_vm/blob/master/scripts/install_software.sh). + Требования для сборки: **Ubuntu 20.04**. From 0efb249d9b95b217ca09f9ff1c88737f739f696c Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Fri, 26 Aug 2022 16:05:28 +0300 Subject: [PATCH 16/37] docs: update PX4 to v1.12.3 in native simulation installation article --- docs/en/simulation_native.md | 2 +- docs/ru/simulation_native.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/simulation_native.md b/docs/en/simulation_native.md index d78ef8de..35df908f 100644 --- a/docs/en/simulation_native.md +++ b/docs/en/simulation_native.md @@ -66,7 +66,7 @@ PX4 will be built along with the other packages in our workspace. You may clone Clone PX4 sources and make the required symlinks: ```bash -git clone --recursive --depth 1 --branch v1.12.0 https://github.com/PX4/PX4-Autopilot.git ~/PX4-Autopilot +git clone --recursive --depth 1 --branch v1.12.3 https://github.com/PX4/PX4-Autopilot.git ~/PX4-Autopilot ln -s ~/PX4-Autopilot ~/catkin_ws/src/ ln -s ~/PX4-Autopilot/Tools/sitl_gazebo ~/catkin_ws/src/ ln -s ~/PX4-Autopilot/mavlink ~/catkin_ws/src/ diff --git a/docs/ru/simulation_native.md b/docs/ru/simulation_native.md index e4851384..a3f738ae 100644 --- a/docs/ru/simulation_native.md +++ b/docs/ru/simulation_native.md @@ -66,7 +66,7 @@ sudo /usr/bin/python3 -m pip install -r ~/catkin_ws/src/clover/clover/requiremen Склонируйте исходный код PX4 и создайте необходимые симлинки: ```bash -git clone --recursive --depth 1 --branch v1.12.0 https://github.com/PX4/PX4-Autopilot.git ~/PX4-Autopilot +git clone --recursive --depth 1 --branch v1.12.3 https://github.com/PX4/PX4-Autopilot.git ~/PX4-Autopilot ln -s ~/PX4-Autopilot ~/catkin_ws/src/ ln -s ~/PX4-Autopilot/Tools/sitl_gazebo ~/catkin_ws/src/ ln -s ~/PX4-Autopilot/mavlink ~/catkin_ws/src/ From 63c71fc331247a24112c7f4db6b46b0c79d989c1 Mon Sep 17 00:00:00 2001 From: oponfil <69752190+oponfil@users.noreply.github.com> Date: Sat, 27 Aug 2022 02:08:22 +0700 Subject: [PATCH 17/37] docs: correction in mavros article on global setpoints (#357) Co-authored-by: Oleg Kalachev --- docs/ru/mavros.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/ru/mavros.md b/docs/ru/mavros.md index 3b53656c..6bc12f54 100644 --- a/docs/ru/mavros.md +++ b/docs/ru/mavros.md @@ -40,6 +40,8 @@ MAVROS подписывается на определенные ROS-топики `/mavros/setpoint_position/local` — установить целевую позицию и рысканье \(yaw\) беспилотника \(в системе координат ENU\). +`/mavros/setpoint_position/global` – установить целевую позицию в глобальных координатах (ширина, долгота и высота) и рысканье беспилотника. + `/mavros/setpoint_velocity/cmd_vel` — установить целевую линейную скорость беспилотника. `/mavros/setpoint_attitude/attitude` и `/mavros/setpoint_attitude/att_throttle` — установить целевую ориентацию \(Attitude\) и уровень газа. @@ -52,4 +54,4 @@ MAVROS подписывается на определенные ROS-топики `/mavros/setpoint_raw/attitude` — отправка пакета [SET\_ATTITUDE\_TARGET](https://mavlink.io/en/messages/common.html#SET_ATTITUDE_TARGET). Позволяет установить целевую ориентацию / угловые скорости и уровень газа. Выбор устанавливаемых величин осуществляется с помощью поля `type_mask` -`/mavros/setpoint_raw/global` — отправка пакета [SET\_POSITION\_TARGET\_GLOBAL\_INT](https://mavlink.io/en/messages/common.html#SET_POSITION_TARGET_GLOBAL_INT). Позволяет установить целевую позицию в глобальных координатах \(ширина, долгота, высота\), а также скорости полета. **Не поддерживается в PX4** \([issue](https://github.com/PX4/Firmware/issues/7552)\). +`/mavros/setpoint_raw/global` — отправка пакета [SET\_POSITION\_TARGET\_GLOBAL\_INT](https://mavlink.io/en/messages/common.html#SET_POSITION_TARGET_GLOBAL_INT). Позволяет установить целевую позицию в глобальных координатах \(ширина, долгота, высота\), а также скорости полета. From 596ed3dcf2376906b1504a54acddac33dcfbaa06 Mon Sep 17 00:00:00 2001 From: oponfil <69752190+oponfil@users.noreply.github.com> Date: Sat, 27 Aug 2022 02:09:56 +0700 Subject: [PATCH 18/37] docs: docs: correction in mavros article on global setpoints (en) (#358) Co-authored-by: Oleg Kalachev --- docs/en/mavros.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/mavros.md b/docs/en/mavros.md index 32a26cb8..00fd4f73 100644 --- a/docs/en/mavros.md +++ b/docs/en/mavros.md @@ -40,6 +40,8 @@ Messages published in the topics may be viewed with the `rostopic` utility, e.g. `/mavros/setpoint_position/local` — set target position and yaw of the drone \(in the ENU coordinate system\). +`/mavros/setpoint_position/global` – set target position in global coordinates (latitude, longitude, altitude) and yaw of the drone. + `/mavros/setpoint_position/cmd_vel` — set target linear velocity of the drone. `/mavros/setpoint_attitude/attitude` and `/mavros/setpoint_attitude/att_throttle` — set target attitude and throttle level. @@ -52,4 +54,4 @@ Messages published in the topics may be viewed with the `rostopic` utility, e.g. `/mavros/setpoint_raw/attitude` — sends [SET\_ATTITUDE\_TARGET](https://mavlink.io/en/messages/common.html#SET_ATTITUDE_TARGET) message. Allows setting the target attitude /angular velocity and throttle level. The values to be set are selected using the `type_mask` field -`/mavros/setpoint_raw/global` — sends [SET\_POSITION\_TARGET\_GLOBAL\_INT](https://mavlink.io/en/messages/common.html#SET_POSITION_TARGET_GLOBAL_INT). Allows setting the target attitude in global coordinates \(latitude, longitude, altitude\) and flight speed. **Not supported in PX4** \([issue](https://github.com/PX4/Firmware/issues/7552)\). +`/mavros/setpoint_raw/global` — sends [SET\_POSITION\_TARGET\_GLOBAL\_INT](https://mavlink.io/en/messages/common.html#SET_POSITION_TARGET_GLOBAL_INT). Allows setting the target attitude in global coordinates \(latitude, longitude, altitude\) and flight speed. From 81f4795aecc5a0291b8814173fbc600cd9a950f0 Mon Sep 17 00:00:00 2001 From: oponfil <69752190+oponfil@users.noreply.github.com> Date: Sat, 27 Aug 2022 02:35:40 +0700 Subject: [PATCH 19/37] docs: update connection article (#362) * Add instructions on how to connect FMU to Raspberry Pi by UART * Remove inactual sitl connection Co-authored-by: Oleg Kalachev --- docs/ru/connection.md | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/docs/ru/connection.md b/docs/ru/connection.md index f31d93c8..90f2855a 100644 --- a/docs/ru/connection.md +++ b/docs/ru/connection.md @@ -26,9 +26,10 @@ Дополнительным способом подключения является подключение подключение по интерфейсу UART. -1. Подключите Raspberry Pi к полетному контроллеру по UART. -2. [Подключитесь в Raspberry Pi по SSH](ssh.md). -3. Поменяйте в launch-файле Клевера (`~/catkin_ws/src/clover/clover/launch/clover.launch`) тип подключения на UART: +1. Подключите Raspberry Pi к полетному контроллеру по UART. Для этого соедините кабелем порт TELEM 2 на полетном контроллере к пинам на Raspberry Pi следующем образом: черный провод (GND) к Ground, зеленый (*UART_RX*) к *GPIO14*, желтый (*UART_TX*) к *GPIO15*. Красный провод (*5V*) подключать не нужно. +2. Измените значения параметров PX4: `MAV_1_CONFIG` на TELEM 2, `SER_TEL2_BAUND` на 921600 8N1. В PX4 до версии v1.10.0 необходима установка параметра `SYS_COMPANION` в значение 921600. +3. [Подключитесь в Raspberry Pi по SSH](ssh.md). +4. Поменяйте в launch-файле Клевера (`~/catkin_ws/src/clover/clover/launch/clover.launch`) тип подключения на UART: ```xml @@ -40,15 +41,4 @@ sudo systemctl restart clover ``` -> **Hint** Для корректной работы подключения Raspberry Pi и полетного контроллера по UART необходимо установить значение параметра `SYS_COMPANION` на 921600. - -## Подключение к SITL - -Для того, чтобы подсоединиться к локально/удаленно запущенному [SITL](sitl.md), необходимо установить аргумент `fcu_conn` в `udp`, и `fcu_ip` в IP-адрес машины, где запущен SITL (`127.0.0.1` для локального): - -```xml - - -``` - **Далее**: [Подключение QGroundControl по Wi-Fi](gcs_bridge.md). From ffe2d3d5e4fb3894cb5ccfe598236d1862f1b2d6 Mon Sep 17 00:00:00 2001 From: oponfil <69752190+oponfil@users.noreply.github.com> Date: Sat, 27 Aug 2022 02:36:11 +0700 Subject: [PATCH 20/37] docs: update connection article (en) (#363) * Add instructions on how to connect FMU to Raspberry Pi by UART * Remove sitl connection section Co-authored-by: Oleg Kalachev --- docs/en/connection.md | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/docs/en/connection.md b/docs/en/connection.md index e86176ca..82cf537e 100644 --- a/docs/en/connection.md +++ b/docs/en/connection.md @@ -26,9 +26,10 @@ USB connection is the preferred way to connect to the flight controller. UART connection is another way for the Raspberry Pi and FCU to communicate. -1. Connect Raspberry Pi to your FCU using a UART cable. -2. [Connect to the Raspberry Pi over SSH](ssh.md). -3. Change the connection type in `~/catkin_ws/src/clover/clover/launch/clover.launch` to UART: +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. +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: ```xml @@ -40,15 +41,4 @@ UART connection is another way for the Raspberry Pi and FCU to communicate. sudo systemctl restart clover ``` -> **Hint** Set the `SYS_COMPANION` PX4 parameter to 921600 to enable UART on the FCU. - -## SITL connection - -In order to connect to a local or a remote [SITL](sitl.md) instance set the `fcu_conn` parameter to `udp` and `fcu_ip` to the IP address of the SITL instance (`127.0.0.1` if you are running the instance locally): - -```xml - - -``` - **Next**: [Using QGroundControl over Wi-Fi](gcs_bridge.md) From 0a2ad3d64f1d88963889bd16b7c1c9475dbf7b97 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Fri, 26 Aug 2022 22:50:55 +0300 Subject: [PATCH 21/37] docs: remove some obsolete notes about renaming --- docs/en/camera.md | 2 -- docs/en/connection.md | 2 -- docs/ru/camera.md | 2 -- docs/ru/connection.md | 2 -- 4 files changed, 8 deletions(-) diff --git a/docs/en/camera.md b/docs/en/camera.md index 5dfe34fa..bbf68d87 100644 --- a/docs/en/camera.md +++ b/docs/en/camera.md @@ -1,7 +1,5 @@ # Working with the camera -> **Note** In the image version **0.20** `clever` package was renamed to `clover`. See [previous version of the article](https://github.com/CopterExpress/clover/blob/v0.19/docs/en/camera.md) for older images. - Make sure the camera is enabled in the `~/catkin_ws/src/clover/clover/launch/clover.launch` file: ```xml diff --git a/docs/en/connection.md b/docs/en/connection.md index 82cf537e..2ca89d62 100644 --- a/docs/en/connection.md +++ b/docs/en/connection.md @@ -20,8 +20,6 @@ USB connection is the preferred way to connect to the flight controller. ## UART connection -> **Note** In the image version **0.20** `clever` package and service was renamed to `clover`. See [previous version of the article](https://github.com/CopterExpress/clover/blob/v0.19/docs/en/connection.md) for older images. - UART connection is another way for the Raspberry Pi and FCU to communicate. diff --git a/docs/ru/camera.md b/docs/ru/camera.md index 522f89ba..7d90084e 100644 --- a/docs/ru/camera.md +++ b/docs/ru/camera.md @@ -1,7 +1,5 @@ # Работа с камерой -> **Note** В версии образа **0.20** пакет и сервис `clever` был переименован в `clover`. Для более ранних версий см. документацию для версии [**0.19**](https://github.com/CopterExpress/clover/blob/v0.19/docs/ru/camera.md). - Для работы с основной камерой необходимо убедиться что она включена в файле `~/catkin_ws/src/clover/clover/launch/clover.launch`: diff --git a/docs/ru/connection.md b/docs/ru/connection.md index 90f2855a..a9d2e893 100644 --- a/docs/ru/connection.md +++ b/docs/ru/connection.md @@ -20,8 +20,6 @@ ## Подключение по UART -> **Note** В версии образа **0.20** пакет и сервис `clever` был переименован в `clover`. Для более ранних версий см. документацию для версии [**0.19**](https://github.com/CopterExpress/clover/blob/v0.19/docs/ru/connection.md). - Дополнительным способом подключения является подключение подключение по интерфейсу UART. From efb44484b0e09dc8d6afa734cb9b5cb4eb689f89 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Fri, 26 Aug 2022 22:51:08 +0300 Subject: [PATCH 22/37] Remove obsolete note from readme --- clover_simulation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clover_simulation/README.md b/clover_simulation/README.md index 9ad220e7..67d2ca76 100644 --- a/clover_simulation/README.md +++ b/clover_simulation/README.md @@ -10,7 +10,7 @@ The simulation may be configured by a set of arguments: * `mav_id` (*integer*, default: *0*) - MAVLink identifier of the vehicle. **Note**: Multi-vehicle simulation is possible, but requires extensive changes to launch files; * `est` (*string*, default: *lpe*, possible values: *lpe*, *ekf2*) - PX4 estimator selection. Note that this may be overriden in the startup scripts for your craft; -* `vehicle` (*string*, default: *clover*) - PX4 vehicle name. Depending on this parameter, different PX4 presets will be loaded. **Note**: The default value, *clover*, requires you to use [Clover-specific PX4 branch](https://github.com/CopterExpress/Firmware/tree/v1.10.1-clever); +* `vehicle` (*string*, default: *clover*) - PX4 vehicle name. Depending on this parameter, different PX4 presets will be loaded. * `main_camera` (*boolean*, default: *true*) - controls whether the drone will have a vision position estimation camera; * `rangefinder` (*boolean*, default: *true*) - controls whether the drone will have a laser rangefinder; * `led` (*boolean*, default: *true*) - controls whether the drone will have a programmable LED strip; From b5d300e218b45e01941b2febbf57dfc468c1b950 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Sat, 3 Sep 2022 07:26:25 +0300 Subject: [PATCH 23/37] optical_flow: timeout for previous frame For cases when optical flow is dynamically disabled and enabled back --- clover/src/optical_flow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clover/src/optical_flow.cpp b/clover/src/optical_flow.cpp index e244d849..7207f516 100644 --- a/clover/src/optical_flow.cpp +++ b/clover/src/optical_flow.cpp @@ -154,7 +154,7 @@ private: img.convertTo(curr_, CV_32F); - if (prev_.empty()) { + if (prev_.empty() || (msg->header.stamp - prev_stamp_).toSec() > 0.1) { // outdated previous frame prev_ = curr_.clone(); prev_stamp_ = msg->header.stamp; cv::createHanningWindow(hann_, curr_.size(), CV_32F); From 9376c017b444caf623e27232cd1d82671c390ed3 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Sat, 3 Sep 2022 22:53:38 +0300 Subject: [PATCH 24/37] selfcheck.py: skip boot duration check on not Clover image --- clover/src/selfcheck.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clover/src/selfcheck.py b/clover/src/selfcheck.py index ad539467..159fcad2 100755 --- a/clover/src/selfcheck.py +++ b/clover/src/selfcheck.py @@ -625,6 +625,10 @@ def check_rangefinder(): @check('Boot duration') def check_boot_duration(): + if not os.path.exists('/etc/clover_version'): + info('skip check') + return # Don't check not on Clover's image + output = subprocess.check_output('systemd-analyze').decode() r = re.compile(r'([\d\.]+)s\s*$', flags=re.MULTILINE) duration = float(r.search(output).groups()[0]) From 614784e9491a6d8008fb5fc00d541a4daebb4063 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Wed, 7 Sep 2022 00:55:13 +0300 Subject: [PATCH 25/37] mavros.launch: add hitl option for fcu_conn argument --- clover/launch/mavros.launch | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clover/launch/mavros.launch b/clover/launch/mavros.launch index 33078139..7adad467 100644 --- a/clover/launch/mavros.launch +++ b/clover/launch/mavros.launch @@ -1,5 +1,5 @@ - + @@ -23,6 +23,9 @@ + + + From c1d6ed27aaf5fddc8ad4473b50d826273a21c5e4 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Thu, 8 Sep 2022 01:32:51 +0300 Subject: [PATCH 26/37] mavros.launch: fix fcu_url for hitl connection --- clover/launch/mavros.launch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clover/launch/mavros.launch b/clover/launch/mavros.launch index 7adad467..8b445d62 100644 --- a/clover/launch/mavros.launch +++ b/clover/launch/mavros.launch @@ -24,7 +24,7 @@ - + From 105eac7e1d57bc347fb1e0eee3070364412ad075 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Thu, 8 Sep 2022 14:42:45 +0300 Subject: [PATCH 27/37] clover.launch: make force_init argument overridable externally --- clover/launch/clover.launch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clover/launch/clover.launch b/clover/launch/clover.launch index 58a05f3e..1efe1b89 100644 --- a/clover/launch/clover.launch +++ b/clover/launch/clover.launch @@ -12,7 +12,7 @@ - + From 5223bef5e7f2e228ad82996ef950dc28a21c3bf7 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Sat, 10 Sep 2022 01:31:38 +0300 Subject: [PATCH 28/37] Fix error when viewing messages without header in topic viewer --- clover/www/js/topics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clover/www/js/topics.js b/clover/www/js/topics.js index 1bb3069f..1ad13176 100644 --- a/clover/www/js/topics.js +++ b/clover/www/js/topics.js @@ -54,7 +54,7 @@ function viewTopic(topic) { document.title = topic; if (mouseDown) return; - if (msg.header.stamp) { + if (msg.header && msg.header.stamp) { if (params.date || params.offset) { let date = new Date(msg.header.stamp.secs * 1e3 + msg.header.stamp.nsecs * 1e-6); if (params.date) msg.header.date = date.toISOString(); From 24cd1f6fac2d80ef39c749fc115d49747eeda770 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Sat, 10 Sep 2022 08:08:09 +0300 Subject: [PATCH 29/37] Show number of messages received in topic viewer --- clover/www/js/topics.js | 5 ++++- clover/www/topics.html | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clover/www/js/topics.js b/clover/www/js/topics.js index 1ad13176..7d8f03df 100644 --- a/clover/www/js/topics.js +++ b/clover/www/js/topics.js @@ -40,6 +40,7 @@ function viewTopicsList() { let rosdistro; function viewTopic(topic) { + let counter = 0; let index = 'Topics'; title.innerHTML = `${index}: ${topic}`; topicMessage.style.display = 'block'; @@ -51,6 +52,7 @@ function viewTopic(topic) { }); new ROSLIB.Topic({ ros: ros, name: topic }).subscribe(function(msg) { + counter++; document.title = topic; if (mouseDown) return; @@ -62,7 +64,8 @@ function viewTopic(topic) { } } - topicMessage.innerHTML = yamlStringify(msg); // JSON.stringify(msg, null, 4); + let txt = `
${counter} received
${yamlStringify(msg)}`; // JSON.stringify(msg, null, 4); + topicMessage.innerHTML = txt; }); } diff --git a/clover/www/topics.html b/clover/www/topics.html index 348a3329..a5f6bc92 100644 --- a/clover/www/topics.html +++ b/clover/www/topics.html @@ -15,6 +15,7 @@ white-space: pre; font-family: monospace; } + .counter { color: #b9b9b9; margin-bottom: 1em; } #topic-type { font-family: monospace; font-size: 0.5em; vertical-align: super; font-weight: normal; } .topic { font-family: monospace; } body.closed { background-color: rgb(207, 207, 207); } From 1efe10c9ddb7bebf3e6df12f366200c989dfa2ec Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Sat, 10 Sep 2022 15:26:34 +0300 Subject: [PATCH 30/37] Simplify script for testing native Noetic build --- .github/workflows/build.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29b305d3..88a97f1d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,8 +16,22 @@ jobs: # docker run --rm -v $(pwd):/root/catkin_ws/src/clover ros:melodic-ros-base /root/catkin_ws/src/clover/builder/standalone-install.sh noetic: runs-on: ubuntu-latest + container: ros:noetic-ros-base + defaults: + run: + working-directory: catkin_ws + shell: bash steps: - - uses: actions/checkout@v2 - - name: Native Noetic build - run: | - docker run --rm -v $(pwd):/root/catkin_ws/src/clover ros:noetic-ros-base /root/catkin_ws/src/clover/builder/standalone-install.sh + - uses: actions/checkout@v2 + with: + path: catkin_ws/src/clover + - name: Install pip + run: apt-get update && apt-get -y install python3-pip + - name: Install dependencies + run: rosdep update && rosdep install --from-paths src --ignore-src -y + - name: catkin_make + run: source /opt/ros/$ROS_DISTRO/setup.bash && catkin_make + - name: Run tests + run: source devel/setup.bash && catkin_make run_tests && catkin_test_results + - name: Install + run: source devel/setup.bash && catkin_make install From d06b0a0cd29bbccd783dbca09df835ab9e61a01e Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Wed, 14 Sep 2022 12:35:16 +0300 Subject: [PATCH 31/37] aruco_pose: implement test for TF_REPEATED_DATA when multiple markers with the same ID --- aruco_pose/test/duplicate.png | Bin 0 -> 63372 bytes aruco_pose/test/duplicate.py | 8 ++++++++ aruco_pose/test/duplicate.test | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 aruco_pose/test/duplicate.png create mode 100644 aruco_pose/test/duplicate.py create mode 100644 aruco_pose/test/duplicate.test diff --git a/aruco_pose/test/duplicate.png b/aruco_pose/test/duplicate.png new file mode 100644 index 0000000000000000000000000000000000000000..8802c2491b880a3d2b2c921b386abfd519411d31 GIT binary patch literal 63372 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
+IG=%B;hK>>5cO`4=A*T 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 z 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
TGK{UINCfdTZTsx<6(X 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 + + + + + + + + + + + + + + + + + + + +
From 2ea848721c27e1e809608df7d94fad358907ae0a Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Wed, 14 Sep 2022 12:46:04 +0300 Subject: [PATCH 32/37] aruco_pose: add duplicate test to CMakeLists.txt --- aruco_pose/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/aruco_pose/CMakeLists.txt b/aruco_pose/CMakeLists.txt index d1134eff..e23f5fc3 100644 --- a/aruco_pose/CMakeLists.txt +++ b/aruco_pose/CMakeLists.txt @@ -251,4 +251,5 @@ if (CATKIN_ENABLE_TESTING) add_rostest(test/test_node_failure.test) add_rostest(test/largemap.test) add_rostest(test/crash_opencv.test) + add_rostest(test/duplicate.test) endif() From 43037f515d5705fc08a7815ee85824397c6dce99 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Wed, 14 Sep 2022 12:55:27 +0300 Subject: [PATCH 33/37] aruco_detect: check for duplicates in marker transforms, send all transforms in one message --- aruco_pose/src/aruco_detect.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/aruco_pose/src/aruco_detect.cpp b/aruco_pose/src/aruco_detect.cpp index 4a6cfac7..fe1ad5be 100644 --- a/aruco_pose/src/aruco_detect.cpp +++ b/aruco_pose/src/aruco_detect.cpp @@ -187,6 +187,8 @@ private: array_.markers.reserve(ids.size()); aruco_pose::Marker marker; + vector transforms; + transforms.reserve(ids.size()); geometry_msgs::TransformStamped transform; transform.header.stamp = msg->header.stamp; transform.header.frame_id = msg->header.frame_id; @@ -204,20 +206,33 @@ private: snapOrientation(marker.pose.orientation, snap_to.transform.rotation, auto_flip_); } - // TODO: check IDs are unique if (send_tf_) { transform.child_frame_id = getChildFrameId(ids[i]); // check if such static transform is in the map if (map_markers_ids_.find(ids[i]) == map_markers_ids_.end()) { - transform.transform.rotation = marker.pose.orientation; - fillTranslation(transform.transform.translation, tvecs[i]); - br_->sendTransform(transform); + // check if a markers with that id is already added + bool send = true; + for (auto &t : transforms) { + if (t.child_frame_id == transform.child_frame_id) { + send = false; + break; + } + } + if (send) { + transform.transform.rotation = marker.pose.orientation; + fillTranslation(transform.transform.translation, tvecs[i]); + transforms.push_back(transform); + } } } } array_.markers.push_back(marker); } + + if (send_tf_) { + br_->sendTransform(transforms); + } } markers_pub_.publish(array_); From 1e12498cb29f37e210fd886c86352ec0c6167ecb Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Wed, 14 Sep 2022 14:19:06 +0300 Subject: [PATCH 34/37] Install GeographicLib datasets in build workflow --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 88a97f1d..ba7fbe05 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,6 +29,8 @@ jobs: run: apt-get update && apt-get -y install python3-pip - name: Install dependencies run: rosdep update && rosdep install --from-paths src --ignore-src -y + - name: Install GeographicLib datasets + run: wget -qO- https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | bash - name: catkin_make run: source /opt/ros/$ROS_DISTRO/setup.bash && catkin_make - name: Run tests From 7b431fa021a28fd8c1e132e27a559ed91d621c08 Mon Sep 17 00:00:00 2001 From: Sergey Stetsky <46196443+stinger000@users.noreply.github.com> Date: Fri, 23 Sep 2022 20:15:57 +0300 Subject: [PATCH 35/37] docs: add command for updating markers map in the sim (#456) Co-authored-by: Oleg Kalachev --- docs/en/simulation_usage.md | 10 ++++++++++ docs/ru/simulation_usage.md | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/docs/en/simulation_usage.md b/docs/en/simulation_usage.md index c8cc6ecb..e189b60f 100644 --- a/docs/en/simulation_usage.md +++ b/docs/en/simulation_usage.md @@ -97,3 +97,13 @@ PX4_SIM_SPEED_FACTOR=0.42 roslaunch clover_simulation simulator.launch The virtual machine may benefit from several CPU cores, especially if the cores are not very performant. In our tests, a four-core machine with only a single core allocated to the VM was unable to run the simulation, with constant interface freezes and dropped ROS messages. The same machine with all four cores available to the VM was able to run the simulation at 0.25 real-time speed. Do note that you should not allocate more resources than you have on your host hardware. + +### Changing the map of ArUco-markers in the simulator + +In order to change the map of ArUco-markers in the simulator, you can use the following command: + +```bash +rosrun clover_simulation aruco_gen --single-model --source-world=$(catkin_find clover_simulation resources/worlds/clover.world) $(catkin_find aruco_pose map/map.txt) > $(catkin_find clover_simulation resources/worlds/clover_aruco.world) +``` + +In this example, `map.txt` is the name of markers name. diff --git a/docs/ru/simulation_usage.md b/docs/ru/simulation_usage.md index 591862b3..f6ce2b64 100644 --- a/docs/ru/simulation_usage.md +++ b/docs/ru/simulation_usage.md @@ -99,3 +99,13 @@ PX4_SIM_SPEED_FACTOR=0.42 roslaunch clover_simulation simulator.launch Выделение нескольких процессорных ядер для виртуальной машины может значительно повысить производительность симуляции. В наших испытаниях виртуальная машина, для которой было выделено одно ядро, не позволяла работать в симуляторе: окно Gazebo не реагировало на пользовательский ввод, сообщения ROS терялись. После выделения четырёх ядер для этой же виртуальной машины симуляция стала работать со скоростью 0.25 от реального времени. При этом не следует пытаться выделить для виртуальной машины больше ресурсов, чем доступно на основной системе. + +### Изменение карты ArUco-меток в симуляторе + +Для того, чтобы изменить карту ArUco-меток в симуляторе, можно использовать следующую команду: + +```bash +rosrun clover_simulation aruco_gen --single-model --source-world=$(catkin_find clover_simulation resources/worlds/clover.world) $(catkin_find aruco_pose map/map.txt) > $(catkin_find clover_simulation resources/worlds/clover_aruco.world) +``` + +В данном примере `map.txt` – имя карты меток. From 91c69986335bf427b42d045972bd568414330503 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Thu, 29 Sep 2022 01:40:16 +0300 Subject: [PATCH 36/37] docs: add snippet to subscribe and decode incoming mavlink messages --- docs/en/snippets.md | 24 ++++++++++++++++++++++++ docs/ru/snippets.md | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/docs/en/snippets.md b/docs/en/snippets.md index 87eade17..af2e36c9 100644 --- a/docs/en/snippets.md +++ b/docs/en/snippets.md @@ -240,6 +240,30 @@ ros_msg = mavlink.convert_to_rosmsg(msg) mavlink_pub.publish(ros_msg) ``` + + +### # {#mavlink-receive} + + + +Subscribe to all MAVLink messages from the flight controller and decode them: + +```python +from mavros_msgs.msg import Mavlink +from mavros import mavlink +from pymavlink import mavutil + +link = mavutil.mavlink.MAVLink('', 255, 1) + +def mavlink_cb(msg): + mav_msg = link.decode(mavlink.convert_to_bytes(msg)) + print('msgid =', msg.msgid, mav_msg) # print message id and parsed message + +mavlink_sub = rospy.Subscriber('mavlink/from', Mavlink, mavlink_cb) + +rospy.spin() +``` + ### # {#rc-sub} React to the drone's mode switching (may be used for starting an autonomous flight, see [example](https://gist.github.com/okalachev/b709f04522d2f9af97e835baedeb806b)): diff --git a/docs/ru/snippets.md b/docs/ru/snippets.md index 30bf38ce..85af2531 100644 --- a/docs/ru/snippets.md +++ b/docs/ru/snippets.md @@ -251,6 +251,30 @@ ros_msg = mavlink.convert_to_rosmsg(msg) mavlink_pub.publish(ros_msg) ``` + + +### # {#mavlink-receive} + + + +Подписка на все MAVLink-сообщения от полетного контроллера и их декодирование: + +```python +from mavros_msgs.msg import Mavlink +from mavros import mavlink +from pymavlink import mavutil + +link = mavutil.mavlink.MAVLink('', 255, 1) + +def mavlink_cb(msg): + mav_msg = link.decode(mavlink.convert_to_bytes(msg)) + print('msgid =', msg.msgid, mav_msg) # print message id and parsed message + +mavlink_sub = rospy.Subscriber('mavlink/from', Mavlink, mavlink_cb) + +rospy.spin() +``` + ### # {#rc-sub} Реакция на переключение режима на пульте радиоуправления (может быть использовано для запуска автономного полета, см. [пример](https://gist.github.com/okalachev/b709f04522d2f9af97e835baedeb806b)): From c0707e066aca586d6138a3144cf6ad31bd989117 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Wed, 5 Oct 2022 15:10:17 +0500 Subject: [PATCH 37/37] actions: build Debian packages and upload to artifacts (#458) --- .github/workflows/build.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ba7fbe05..92d9f927 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,8 +25,8 @@ jobs: - uses: actions/checkout@v2 with: path: catkin_ws/src/clover - - name: Install pip - run: apt-get update && apt-get -y install python3-pip + - name: Install requirements + run: apt-get update && apt-get -y install python3-pip fakeroot python3-bloom debhelper dpkg-dev - name: Install dependencies run: rosdep update && rosdep install --from-paths src --ignore-src -y - name: Install GeographicLib datasets @@ -35,5 +35,17 @@ jobs: run: source /opt/ros/$ROS_DISTRO/setup.bash && catkin_make - name: Run tests run: source devel/setup.bash && catkin_make run_tests && catkin_test_results - - name: Install - run: source devel/setup.bash && catkin_make install + - name: Build Debian packages + run: | + source devel/setup.bash + for file in `find . -name "package.xml"`; do + cd $(dirname ${file}) + bloom-generate rosdebian --os-name ubuntu --os-version $(lsb_release -cs) --ros-distro $ROS_DISTRO + fakeroot debian/rules binary + cd - + done + - uses: actions/upload-artifact@v3 + with: + name: debian-packages + path: catkin_ws/src/clover/*.deb + retention-days: 1