diff --git a/README.md b/README.md index 0f9c156a..2e695db1 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Clover drone is used on a wide range of educational events, including [Copter Ha Preconfigured image for Raspberry Pi with installed and configured software, ready to fly, is available [in the Releases section](https://github.com/CopterExpress/clover/releases). -![GitHub Workflow Status](https://img.shields.io/github/workflow/status/CopterExpress/clover/CI) +![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/CopterExpress/clover/build-image.yaml?branch=master) ![GitHub all releases](https://img.shields.io/github/downloads/CopterExpress/clover/total) Image features: diff --git a/clover/launch/clover.launch b/clover/launch/clover.launch index 68150d49..c78297d6 100644 --- a/clover/launch/clover.launch +++ b/clover/launch/clover.launch @@ -45,7 +45,7 @@ - + diff --git a/clover_blocks/www/python.js b/clover_blocks/www/python.js index a614e5e3..42de72a2 100644 --- a/clover_blocks/www/python.js +++ b/clover_blocks/www/python.js @@ -83,9 +83,6 @@ function generateROSDefinitions() { if (rosDefinitions.navigateGlobal) { 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) { code += `set_velocity = rospy.ServiceProxy('set_velocity', srv.SetVelocity)\n`; } diff --git a/docs/en/SUMMARY.md b/docs/en/SUMMARY.md index ab2c3239..1dd04778 100644 --- a/docs/en/SUMMARY.md +++ b/docs/en/SUMMARY.md @@ -36,7 +36,7 @@ * [Optical Flow](optical_flow.md) * [Autonomous flight (OFFBOARD)](simple_offboard.md) * [Coordinate systems (frames)](frames.md) - * [Code snippets](snippets.md) + * [Code examples](snippets.md) * [Interfacing with a laser rangefinder](laser.md) * [LED strip](leds.md) * [Working with GPIO](gpio.md) diff --git a/docs/en/camera.md b/docs/en/camera.md index ba0dbd3a..a4079a45 100644 --- a/docs/en/camera.md +++ b/docs/en/camera.md @@ -14,7 +14,7 @@ The `clover` service must be restarted after the launch-file has been edited: sudo systemctl restart clover ``` -You may use rqt or [web_video_server](web_video_server.md) to view the camera stream. +You may use [rqt](rviz.md) or [web_video_server](web_video_server.md) to view the camera stream. ## Troubleshooting @@ -52,8 +52,6 @@ The [SD card image](image.md) comes with a preinstalled [OpenCV](https://opencv. ### Python -Main article: http://wiki.ros.org/cv_bridge/Tutorials/ConvertingBetweenROSImagesAndOpenCVImagesPython. - An example of creating a subscriber for a topic with an image from the main camera for processing with OpenCV: ```python @@ -61,12 +59,14 @@ import rospy import cv2 from sensor_msgs.msg import Image from cv_bridge import CvBridge +from clover import long_callback -rospy.init_node('computer_vision_sample') +rospy.init_node('cv') bridge = CvBridge() +@long_callback def image_callback(data): - cv_image = bridge.imgmsg_to_cv2(data, 'bgr8') # OpenCV image + img = bridge.imgmsg_to_cv2(data, 'bgr8') # OpenCV image # Do any image processing with cv2... image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback) @@ -74,19 +74,31 @@ image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback) rospy.spin() ``` +> **Note** Image processing may take significant time to finish. This can cause an [issue](https://github.com/ros/ros_comm/issues/1901) in rospy library, which would lead to processing stale camera frames. To solve this problem you need to use `long_callback` decorator from `clover` library, as in the example above. + +#### Limiting CPU usage + +When using the `main_camera/image_raw` topic, the script will process the maximum number of frames from the camera, actively utilizing the CPU (up to 100%). In tasks, where processing each camera frame is not critical, you can use the topic, where the frames are published at rate 5 Hz: `main_camera/image_raw_throttled`: + +```python +image_sub = rospy.Subscriber('main_camera/image_raw_throttled', Image, image_callback, queue_size=1) +``` + +#### Publishing images + To debug image processing, you can publish a separate topic with the processed image: ```python image_pub = rospy.Publisher('~debug', Image) ``` -Publishing the processed image (at the end of the image_callback function): +Publishing the processed image: ```python -image_pub.publish(bridge.cv2_to_imgmsg(cv_image, 'bgr8')) +image_pub.publish(bridge.cv2_to_imgmsg(img, 'bgr8')) ``` -The obtained images can be viewed using [web_video_server](web_video_server.md). +The published images can be viewed using [web_video_server](web_video_server.md) or [rqt](rviz.md). #### Retrieving one frame @@ -97,7 +109,7 @@ import rospy from sensor_msgs.msg import Image from cv_bridge import CvBridge -rospy.init_node('computer_vision_sample') +rospy.init_node('cv') bridge = CvBridge() # ... @@ -119,40 +131,32 @@ QR codes recognition in Python: ```python import rospy from pyzbar import pyzbar +import cv2 from cv_bridge import CvBridge from sensor_msgs.msg import Image +from clover import long_callback +rospy.init_node('cv') bridge = CvBridge() -rospy.init_node('barcode_test') - -# Image subscriber callback function -def image_callback(data): - cv_image = bridge.imgmsg_to_cv2(data, 'bgr8') # OpenCV image - barcodes = pyzbar.decode(cv_image) +@long_callback +def image_callback(msg): + img = bridge.imgmsg_to_cv2(msg, 'bgr8') + barcodes = pyzbar.decode(img) for barcode in barcodes: - b_data = barcode.data.decode("utf-8") + b_data = barcode.data.decode('utf-8') b_type = barcode.type (x, y, w, h) = barcode.rect xc = x + w/2 yc = y + h/2 - print("Found {} with data {} with center at x={}, y={}".format(b_type, b_data, xc, yc)) + print('Found {} with data {} with center at x={}, y={}'.format(b_type, b_data, xc, yc)) -image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback, queue_size=1) +image_sub = rospy.Subscriber('main_camera/image_raw_throttled', Image, image_callback, queue_size=1) rospy.spin() ``` -The script will take up to 100% CPU capacity. To slow down the script artificially, you can use [throttling](http://wiki.ros.org/topic_tools/throttle) of frames from the camera, for example, at 5 Hz (`main_camera.launch`): - -> **Note** Starting from [image](image.md) version **0.24** `image_raw_throttled` topic is available without addition configuration. - -```xml - -``` - -The topic for the subscriber in this case should be changed for `main_camera/image_raw_throttled`. +> **Hint** See other computer vision examples in the `~/examples` directory of the [RPi image](image.md). ## Video recording diff --git a/docs/en/copterhack2023.md b/docs/en/copterhack2023.md index 89284d3a..d53ca911 100644 --- a/docs/en/copterhack2023.md +++ b/docs/en/copterhack2023.md @@ -22,7 +22,7 @@ The proposed projects are supposed to be open-source and be compatible with the ||πŸ‡°πŸ‡¬ LiveSavers|[LiveSavers](https://github.com/Sarvar00/clover/blob/livesavers/docs/ru/livesaver.md)|| ||πŸ‡·πŸ‡Ί C305|[БистСма Ρ€Π°Π΄ΠΈΠΎ-Π½Π°Π²ΠΈΠ³Π°Ρ†ΠΈΠΈ](https://github.com/Lukerrr/clover-c305/blob/nav_beacon/docs/ru/nav-beacon.md)|| ||πŸ‡·πŸ‡Ί XenCOM|[Bound by fate](https://github.com/xenkek/clover/blob/xenkek-patch-1/docs/ru/bound_by_fate.md)|| -||πŸ‡¨πŸ‡¦ Clover with Motion Capture System|[Clover with Motion Capture System](https://github.com/ssmith-81/clover/blob/MoCap_Clover/docs/en/MoCap-Clover)|| +||πŸ‡¨πŸ‡¦ Clover with Motion Capture System|[Clover with Motion Capture System](https://github.com/ssmith-81/clover/blob/MoCap_Clover/docs/en/mocap_clover.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)|| ||πŸ‡§πŸ‡Ύ FTL|[Advanced Clover 2](https://github.com/FTL-team/clover/blob/FTL-advancedClover3/docs/ru/advanced_clover_simulator_platform.md)|| ||πŸ‡·πŸ‡Ί Π›ΠΈΡ†Π΅ΠΉ β„–128|[ΠŸΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ° для зарядки ΠΊΠ²Π°Π΄Ρ€ΠΎΠΊΠΎΠΏΡ‚Π΅Ρ€Π°](https://github.com/Juli-Shvetsova/clover/blob/liceu128-1/docs/ru/liceu128.md)|| diff --git a/docs/ru/camera.md b/docs/ru/camera.md index 0f9b6a14..ea4082c6 100644 --- a/docs/ru/camera.md +++ b/docs/ru/camera.md @@ -54,8 +54,6 @@ raspistill -o test.jpg ### Python -Основная ΡΡ‚Π°Ρ‚ΡŒΡ: http://wiki.ros.org/cv_bridge/Tutorials/ConvertingBetweenROSImagesAndOpenCVImagesPython. - ΠŸΡ€ΠΈΠΌΠ΅Ρ€ создания подписчика Π½Π° Ρ‚ΠΎΠΏΠΈΠΊ с ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ с основной ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ с использованиСм OpenCV: ```python @@ -63,12 +61,14 @@ import rospy import cv2 from sensor_msgs.msg import Image from cv_bridge import CvBridge +from clover import long_callback -rospy.init_node('computer_vision_sample') +rospy.init_node('cv') bridge = CvBridge() +@long_callback def image_callback(data): - cv_image = bridge.imgmsg_to_cv2(data, 'bgr8') # OpenCV image + img = bridge.imgmsg_to_cv2(data, 'bgr8') # OpenCV image # Do any image processing with cv2... image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback) @@ -76,19 +76,31 @@ image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback) rospy.spin() ``` +> **Note** ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° изобраТСния ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°Π½ΠΈΠΌΠ°Ρ‚ΡŒ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ врСмя. Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ [ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ](https://github.com/ros/ros_comm/issues/1901) Π² Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ rospy, которая ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠΈΡ… ΠΊΠ°Π΄Ρ€ΠΎΠ² с ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹. Для Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ этой ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ `long_callback` ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ `clover`, ΠΊΠ°ΠΊ Π² ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π²Ρ‹ΡˆΠ΅. + +#### ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ использования CPU + +ΠŸΡ€ΠΈ использовании Ρ‚ΠΎΠΏΠΈΠΊΠ° `main_camera/image_raw` скрипт Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ максимальноС количСство ΠΊΠ°Π΄Ρ€ΠΎΠ² с ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹, Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ CPU (Π²ΠΏΠ»ΠΎΡ‚ΡŒ Π΄ΠΎ 100%). Π’ Π·Π°Π΄Π°Ρ‡Π°Ρ…, Π³Π΄Π΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΊΠ°Π΄Ρ€Π° Π½Π΅ ΠΊΡ€ΠΈΡ‚ΠΈΡ‡Π½Π°, ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠΏΠΈΠΊ, Π³Π΄Π΅ ΠΊΠ°Π΄Ρ€Ρ‹ ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΡŽΡ‚ΡΡ с частотой 5 Π“Ρ†: `main_camera/image_raw_throttled`: + +```python +image_sub = rospy.Subscriber('main_camera/image_raw_throttled', Image, image_callback, queue_size=1) +``` + +#### ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ + Для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ изобраТСния ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ‚ΠΎΠΏΠΈΠΊ с ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½Π½Ρ‹ΠΌ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ: ```python image_pub = rospy.Publisher('~debug', Image) ``` -ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½Π½ΠΎΠ³ΠΎ изобраТСния (Π² ΠΊΠΎΠ½Ρ†Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ image_callback): +ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½Π½ΠΎΠ³ΠΎ изобраТСния: ```python -image_pub.publish(bridge.cv2_to_imgmsg(cv_image, 'bgr8')) +image_pub.publish(bridge.cv2_to_imgmsg(img, 'bgr8')) ``` -ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΡ‹Π΅ изобраТСния ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΎΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ [web_video_server](web_video_server.md). +ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΡ‹Π΅ изобраТСния ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΎΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ [web_video_server](web_video_server.md) ΠΈΠ»ΠΈ [rqt](rviz.md). #### ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠ°Π΄Ρ€Π° @@ -99,12 +111,12 @@ import rospy from sensor_msgs.msg import Image from cv_bridge import CvBridge -rospy.init_node('computer_vision_sample') +rospy.init_node('cv') bridge = CvBridge() # ... -# ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΊΠ°Π΄Ρ€Π°: +# Retrieve a frame: img = bridge.imgmsg_to_cv2(rospy.wait_for_message('main_camera/image_raw', Image), 'bgr8') ``` @@ -121,40 +133,32 @@ img = bridge.imgmsg_to_cv2(rospy.wait_for_message('main_camera/image_raw', Image ```python import rospy from pyzbar import pyzbar +import cv2 from cv_bridge import CvBridge from sensor_msgs.msg import Image +from clover import long_callback +rospy.init_node('cv') bridge = CvBridge() -rospy.init_node('barcode_test') - -# Image subscriber callback function -def image_callback(data): - cv_image = bridge.imgmsg_to_cv2(data, 'bgr8') # OpenCV image - barcodes = pyzbar.decode(cv_image) +@long_callback +def image_callback(msg): + img = bridge.imgmsg_to_cv2(msg, 'bgr8') + barcodes = pyzbar.decode(img) for barcode in barcodes: - b_data = barcode.data.decode("utf-8") + b_data = barcode.data.decode('utf-8') b_type = barcode.type (x, y, w, h) = barcode.rect xc = x + w/2 yc = y + h/2 - print("Found {} with data {} with center at x={}, y={}".format(b_type, b_data, xc, yc)) + print('Found {} with data {} with center at x={}, y={}'.format(b_type, b_data, xc, yc)) -image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback, queue_size=1) +image_sub = rospy.Subscriber('main_camera/image_raw_throttled', Image, image_callback, queue_size=1) rospy.spin() ``` -Π‘ΠΊΡ€ΠΈΠΏΡ‚ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π½ΠΈΠΌΠ°Ρ‚ΡŒ 100% процСссора. Для искусствСнного замСдлСния Ρ€Π°Π±ΠΎΡ‚Ρ‹ скрипта ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ [throttling](http://wiki.ros.org/topic_tools/throttle) ΠΊΠ°Π΄Ρ€ΠΎΠ² с ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² 5 Π“Ρ† (`main_camera.launch`): - -> **Note** Начиная с вСрсии [ΠΎΠ±Ρ€Π°Π·Π°](image.md) **0.24** Ρ‚ΠΎΠΏΠΈΠΊ `image_raw_throttled` доступСн Π±Π΅Π· Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ. - -```xml - -``` - -Π’ΠΎΠΏΠΈΠΊ для подписчика Π² этом случаС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ Π½Π° `main_camera/image_raw_throttled`. +> **Hint** Π‘ΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΏΠΎ Ρ€Π°Π±ΠΎΡ‚Π΅ с ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π½Ρ‹ΠΌ Π·Ρ€Π΅Π½ΠΈΠ΅ΠΌ Π² ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ `~/examples` [ΠΎΠ±Ρ€Π°Π·Π° для RPi](image.md). ## Π—Π°ΠΏΠΈΡΡŒ Π²ΠΈΠ΄Π΅ΠΎ diff --git a/docs/ru/copterhack2023.md b/docs/ru/copterhack2023.md index a3225844..0d3ca4af 100644 --- a/docs/ru/copterhack2023.md +++ b/docs/ru/copterhack2023.md @@ -22,7 +22,7 @@ CopterHack 2023 β€” это мСТдународный конкурс ΠΏΠΎ Ρ€Π° ||πŸ‡°πŸ‡¬ LiveSavers|[LiveSavers](https://github.com/Sarvar00/clover/blob/livesavers/docs/ru/livesaver.md)|| ||πŸ‡·πŸ‡Ί C305|[БистСма Ρ€Π°Π΄ΠΈΠΎ-Π½Π°Π²ΠΈΠ³Π°Ρ†ΠΈΠΈ](https://github.com/Lukerrr/clover-c305/blob/nav_beacon/docs/ru/nav-beacon.md)|| ||πŸ‡·πŸ‡Ί XenCOM|[Bound by fate](https://github.com/xenkek/clover/blob/xenkek-patch-1/docs/ru/bound_by_fate.md)|| -||πŸ‡¨πŸ‡¦ Clover with Motion Capture System|[Clover with Motion Capture System](https://github.com/ssmith-81/clover/blob/MoCap_Clover/docs/en/MoCap-Clover)|| +||πŸ‡¨πŸ‡¦ Clover with Motion Capture System|[Clover with Motion Capture System](https://github.com/ssmith-81/clover/blob/MoCap_Clover/docs/en/mocap_clover.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)|| ||πŸ‡§πŸ‡Ύ FTL|[Advanced Clover 2](https://github.com/FTL-team/clover/blob/FTL-advancedClover3/docs/ru/advanced_clover_simulator_platform.md)|| ||πŸ‡·πŸ‡Ί Π›ΠΈΡ†Π΅ΠΉ β„–128|[ΠŸΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ° для зарядки ΠΊΠ²Π°Π΄Ρ€ΠΎΠΊΠΎΠΏΡ‚Π΅Ρ€Π°](https://github.com/Juli-Shvetsova/clover/blob/liceu128-1/docs/ru/liceu128.md)||