mirror of
https://github.com/CopterExpress/clever-show.git
synced 2026-05-26 07:07:58 +00:00
Merge pull request #39 from artem30801/master
Merge with master to maintain project structure
This commit is contained in:
21
.github/ISSUE_TEMPLATE/bug_report.md
vendored
21
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -7,11 +7,10 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
**The bug description**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
**Steps to reproduce the behavior**
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
@@ -23,16 +22,8 @@ A clear and concise description of what you expected to happen.
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
**Version**
|
||||
v0.3-alpha.2 (for example)
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
**Additional information**
|
||||
Add any other information about the problem here.
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
2
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -7,7 +7,7 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
**Request description**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
|
||||
@@ -9,7 +9,7 @@ env:
|
||||
- if [[ -z ${TRAVIS_TAG} ]]; then IMAGE_VERSION="${TRAVIS_COMMIT}}"; else IMAGE_VERSION="${TRAVIS_TAG}"; fi
|
||||
- IMAGE_NAME="$(basename -s '.git' ${TARGET_REPO})_${IMAGE_VERSION}.img"
|
||||
git:
|
||||
depth: 50
|
||||
depth: false
|
||||
jobs:
|
||||
fast_finish: true
|
||||
include:
|
||||
|
||||
@@ -150,7 +150,6 @@ def _command_led_fill(**kwargs):
|
||||
def _copter_flip():
|
||||
FlightLib.flip(frame_id=client.active_client.FRAME_ID)
|
||||
|
||||
|
||||
@messaging.message_callback("takeoff")
|
||||
def _command_takeoff(**kwargs):
|
||||
task_manager.add_task(time.time(), 0, animation.takeoff,
|
||||
|
||||
24
README.md
24
README.md
@@ -1,15 +1,15 @@
|
||||
# CleverSwarm
|
||||
Програмное обеспечение для запуска шоу дронов под управлением Raspberry Pi с пакетом COEX Clever.
|
||||
|
||||
# clever-show
|
||||
[](https://travis-ci.org/artem30801/CleverSwarm)
|
||||
|
||||
### Пакет включает в себя:
|
||||
* Набор ПО для дрона, включащее в себя библиотеку для автономного полёта, модуль для воспроизведения анимаций и клиентское приложение для удаленного синхронизированного управления
|
||||
* Серверное приложение для удаленного синхронизированного управления дронами и удобной передачи анимации
|
||||
Програмное обеспечение для запуска шоу дронов под управлением Raspberry Pi с пакетом COEX [Clever](https://github.com/copterexpress/clever).
|
||||
|
||||
## Установка
|
||||
Скачайте или склонируйте этот репозиторий на компьютер и дроны:
|
||||
```bash
|
||||
git clone https://github.com/artem30801/CleverSwarm.git
|
||||
```
|
||||
Для дальнейших инструкций перейдите на Wiki
|
||||
### Пакет включает в себя:
|
||||
* [Набор ПО для дрона](https://github.com/artem30801/CleverSwarm/tree/master/Drone), включащее в себя библиотеку для автономного полёта, модуль для воспроизведения анимаций и клиентское приложение для удаленного синхронизированного управления
|
||||
* [Серверное приложение](https://github.com/artem30801/CleverSwarm/tree/master/Server) для удаленного синхронизированного управления дронами и удобной настройки системы для воспроизведения анимации
|
||||
* [Аддон для Blender 2.8](https://github.com/artem30801/CleverSwarm/tree/master/blender-addon) для преобразования анимации полёта коптеров, созданной в Blender, в файлы полётов для каждого коптера
|
||||
* [Образ для Raspberry Pi](https://github.com/artem30801/CleverSwarm/releases/latest) для быстрого запуска ПО на коптере
|
||||
|
||||
## Документация
|
||||
Инструкция по запуску ПО находится [здесь](docs/start-tutorial.md).
|
||||
|
||||
Подробная документация расположена в папке [docs](https://github.com/artem30801/CleverSwarm/tree/master/docs).
|
||||
|
||||
5
Server/chrony.conf
Normal file
5
Server/chrony.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
server master iburst
|
||||
driftfile /var/lib/chrony/drift
|
||||
allow 192.168.0.0/16
|
||||
makestep 1.0 3
|
||||
rtcsync
|
||||
@@ -65,17 +65,22 @@ class Server:
|
||||
def load_config(self):
|
||||
self.config.read(self.config_path)
|
||||
self.port = int(self.config['SERVER']['port']) # TODO try, init def
|
||||
self.broadcast_port = int(self.config['SERVER']['broadcast_port'])
|
||||
self.BROADCAST_DELAY = int(self.config['SERVER']['broadcast_delay'])
|
||||
Server.BUFFER_SIZE = int(self.config['SERVER']['buffer_size'])
|
||||
|
||||
self.use_broadcast = self.config.getboolean('BROADCAST', 'use_broadcast')
|
||||
self.broadcast_port = int(self.config['BROADCAST']['broadcast_port'])
|
||||
self.BROADCAST_DELAY = int(self.config['BROADCAST']['broadcast_delay'])
|
||||
|
||||
self.USE_NTP = self.config.getboolean('NTP', 'use_ntp')
|
||||
self.NTP_HOST = self.config['NTP']['host']
|
||||
self.NTP_PORT = int(self.config['NTP']['port'])
|
||||
|
||||
def start(self): # do_auto_connect=True, do_ip_broadcast=True, do_listen_broadcast=False
|
||||
def start(self, do_ip_broadcast=None): # do_auto_connect=True, , do_listen_broadcast=False
|
||||
self.time_started = time.time()
|
||||
|
||||
if do_ip_broadcast is None:
|
||||
do_ip_broadcast = self.use_broadcast
|
||||
|
||||
logging.info("Starting server with id: {} on {}:{} !".format(self.id, self.ip, self.port))
|
||||
logging.info("Starting server socket!")
|
||||
self.server_socket.bind((self.ip, self.port))
|
||||
@@ -84,9 +89,10 @@ class Server:
|
||||
self.client_processor_thread_running.set()
|
||||
self.autoconnect_thread.start()
|
||||
|
||||
logging.info("Starting broadcast sender thread!")
|
||||
self.broadcast_thread_running.set()
|
||||
self.broadcast_thread.start()
|
||||
if do_ip_broadcast:
|
||||
logging.info("Starting broadcast sender thread!")
|
||||
self.broadcast_thread_running.set()
|
||||
self.broadcast_thread.start()
|
||||
|
||||
logging.info("Starting broadcast listener thread!")
|
||||
self.listener_thread_running.set()
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
[SERVER]
|
||||
port = 25000
|
||||
buffer_size = 1024
|
||||
|
||||
[BROADCAST]
|
||||
use_broadcast = True
|
||||
broadcast_port = 8181
|
||||
broadcast_delay = 5
|
||||
buffer_size = 1024
|
||||
|
||||
[NTP]
|
||||
use_ntp = False
|
||||
|
||||
@@ -143,14 +143,14 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
@pyqtSlot()
|
||||
def takeoff_selected(self, **kwargs):
|
||||
for copter in self.model.user_selected():
|
||||
if all_checks(copter):
|
||||
if takeoff_checks(copter):
|
||||
copter.client.send_message("takeoff")
|
||||
|
||||
@confirmation_required("This operation will flip(!!!) copters immediately. Proceed?")
|
||||
@pyqtSlot()
|
||||
def flip(self, **kwargs):
|
||||
for copter in self.model.user_selected():
|
||||
if all_checks(copter):
|
||||
if takeoff_checks(copter):
|
||||
copter.client.send_message("flip")
|
||||
|
||||
@pyqtSlot()
|
||||
|
||||
25
blender-addon/README.md
Normal file
25
blender-addon/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# blender-csv-animation
|
||||
A Blender extension that export paths of objects in blender animation to a csv files
|
||||
|
||||
## CSV file format
|
||||
First row is the animation filename.
|
||||
Every next row of the file contains following information about an object:
|
||||
- frame number,
|
||||
- x coordinate,
|
||||
- y coordinate,
|
||||
- z coordinate,
|
||||
- rotaion around z-axis angle (yaw for copter),
|
||||
- rgb.
|
||||
|
||||
## How to use it
|
||||
Clone or download this repository
|
||||
```bash
|
||||
git clone https://github.com/artem30801/CleverSwarm.git
|
||||
```
|
||||
Open Blender and install the addon:
|
||||
1) Open User Prerences windows using main menu or shortcut (Ctrl + Alt + U): Files - User Preferences
|
||||
2) Under Add-ons tab click Install Add-on from File...
|
||||
3) Choose addon.py file from the directory of this repository
|
||||
4) Enable the Add-on
|
||||
|
||||
Use [official docs](https://docs.blender.org/manual/en/latest/preferences/addons.html) for getting additional information
|
||||
213
blender-addon/addon.py
Normal file
213
blender-addon/addon.py
Normal file
@@ -0,0 +1,213 @@
|
||||
import os
|
||||
import csv
|
||||
import math
|
||||
|
||||
import bpy
|
||||
from bpy_extras.io_utils import ExportHelper
|
||||
from bpy.types import Operator
|
||||
from bpy.props import StringProperty, BoolProperty, FloatProperty, IntProperty
|
||||
|
||||
bl_info = {
|
||||
"name": "Export > CSV Drone Swarm Animation Exporter (.csv)",
|
||||
"author": "Artem Vasiunik",
|
||||
"version": (0, 4, 0),
|
||||
"blender": (2, 80, 0),
|
||||
#"api": 36079,
|
||||
"location": "File > Export > CSV Drone Swarm Animation Exporter (.csv)",
|
||||
"description": "Export > CSV Drone Swarm Animation Exporter (.csv)",
|
||||
"warning": "",
|
||||
"wiki_url": "https://github.com/artem30801/blender-csv-animation/blob/master/README.md",
|
||||
"tracker_url": "https://github.com/artem30801/blender-csv-animation/issues",
|
||||
"category": "Import-Export"
|
||||
}
|
||||
|
||||
|
||||
class ExportCsv(Operator, ExportHelper):
|
||||
bl_idname = "export_swarm_anim.folder"
|
||||
bl_label = "Export Drone Swarm animation"
|
||||
filename_ext = ''
|
||||
use_filter_folder = True
|
||||
|
||||
use_namefilter: bpy.props.BoolProperty(
|
||||
name="Use name filter for objects",
|
||||
default=True,
|
||||
)
|
||||
|
||||
drones_name: bpy.props.StringProperty(
|
||||
name="Name identifier",
|
||||
description="Name identifier for all drone objects",
|
||||
default="copter"
|
||||
)
|
||||
|
||||
show_warnings: bpy.props.BoolProperty(
|
||||
name="Show detailed animation warnings",
|
||||
default=False,
|
||||
)
|
||||
|
||||
speed_warning_limit: bpy.props.FloatProperty(
|
||||
name="Speed limit",
|
||||
description="Limit of drone movement speed (m/s)",
|
||||
unit='VELOCITY',
|
||||
default=3,
|
||||
min=0,
|
||||
)
|
||||
drone_distance_limit: bpy.props.FloatProperty(
|
||||
name="Distance limit",
|
||||
description="Closest possible distance between drones (m)",
|
||||
unit='LENGTH',
|
||||
default=1.5,
|
||||
min=0,
|
||||
)
|
||||
|
||||
filepath: StringProperty(
|
||||
name="File Path",
|
||||
description="File path used for exporting CSV files",
|
||||
maxlen=1024,
|
||||
subtype='DIR_PATH',
|
||||
default=""
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
create_folder_if_does_not_exist(self.filepath)
|
||||
scene = context.scene
|
||||
objects = context.visible_objects
|
||||
|
||||
drone_objects = []
|
||||
if self.use_namefilter:
|
||||
for drone_obj in objects:
|
||||
if self.drones_name.lower() in drone_obj.name.lower():
|
||||
drone_objects.append(drone_obj)
|
||||
else:
|
||||
drone_objects = objects
|
||||
|
||||
frame_start = scene.frame_start
|
||||
frame_end = scene.frame_end
|
||||
|
||||
for drone_obj in drone_objects:
|
||||
with open(os.path.join(self.filepath, '{}.csv'.format(drone_obj.name.lower())), 'w') as csv_file:
|
||||
animation_file_writer = csv.writer(
|
||||
csv_file,
|
||||
delimiter=',',
|
||||
quotechar='|',
|
||||
quoting=csv.QUOTE_MINIMAL
|
||||
)
|
||||
speed_exeeded = False
|
||||
distance_exeeded = False
|
||||
|
||||
prev_x, prev_y, prev_z = 0, 0, 0
|
||||
|
||||
animation_file_writer.writerow([
|
||||
os.path.splitext(bpy.path.basename(bpy.data.filepath))[0]
|
||||
])
|
||||
|
||||
for frame_number in range(frame_start, frame_end + 1):
|
||||
scene.frame_set(frame_number)
|
||||
rgb = get_rgb_from_object(drone_obj)
|
||||
x, y, z = drone_obj.matrix_world.to_translation()
|
||||
rot_z = drone_obj.matrix_world.to_euler('XYZ')[2]
|
||||
|
||||
speed = calc_speed((x, y, z), (prev_x, prev_y, prev_z)) if frame_number != frame_start else 1
|
||||
prev_x, prev_y, prev_z = x, y, z
|
||||
|
||||
if speed > self.speed_warning_limit:
|
||||
speed_exeeded = True
|
||||
if self.show_warnings:
|
||||
self.report({'WARNING'},
|
||||
"Speed of drone '%s' is greater than %s m/s (%s m/s) on frame %s" %
|
||||
(drone_obj.name, round(self.speed_warning_limit, 5), round(speed, 5), frame_number))
|
||||
|
||||
for second_drone_obj in drone_objects:
|
||||
if second_drone_obj is not drone_obj:
|
||||
x2, y2, z2 = second_drone_obj.matrix_world.to_translation()
|
||||
distance = calc_distance((x, y, z), (x2, y2, z2))
|
||||
if distance < self.drone_distance_limit:
|
||||
distance_exeeded = True
|
||||
if self.show_warnings:
|
||||
self.report({'WARNING'},
|
||||
"Distance beteween drones '%s' and '%s' is less than %s m (%s m) on frame %s" %
|
||||
(drone_obj.name, second_drone_obj.name,
|
||||
round(self.drone_distance_limit, 5), round(distance, 5), frame_number))
|
||||
|
||||
animation_file_writer.writerow([
|
||||
str(frame_number),
|
||||
round(x, 5), round(y, 5), round(z, 5),
|
||||
round(rot_z, 5),
|
||||
*rgb,
|
||||
])
|
||||
|
||||
|
||||
|
||||
if speed_exeeded:
|
||||
self.report({'WARNING'}, "Drone '%s' speed limits exeeded" % drone_obj.name)
|
||||
if distance_exeeded:
|
||||
self.report({'WARNING'}, "Drone '%s' distance limits exeeded" % drone_obj.name)
|
||||
self.report({'WARNING'}, "Animation file exported for drone '%s'" % drone_obj.name)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def create_folder_if_does_not_exist(folder_path):
|
||||
if os.path.isdir(folder_path):
|
||||
return
|
||||
os.mkdir(folder_path)
|
||||
|
||||
|
||||
def get_rgb_from_object(obj):
|
||||
rgb = [0, 0, 0]
|
||||
try:
|
||||
if len(obj.material_slots) > 0:
|
||||
print('material slots true')
|
||||
for slot in obj.material_slots:
|
||||
if "led_color" in slot.name.lower():
|
||||
print('led color')
|
||||
if slot.material.use_nodes:
|
||||
for node in slot.material.node_tree.nodes:
|
||||
if node.type in ('EMISSION', 'BSDF_DIFFUSE'):
|
||||
alpha = node.inputs[0].default_value[3]
|
||||
for component in range(3):
|
||||
rgb[component] = int(node.inputs[0].default_value[component] * alpha * 255)
|
||||
else:
|
||||
print('no led color')
|
||||
for component in range(3):
|
||||
rgb[component] = int(slot.material.diffuse_color[component] * 255)
|
||||
|
||||
except AttributeError:
|
||||
pass
|
||||
finally:
|
||||
return rgb
|
||||
|
||||
|
||||
def calc_speed(start_point, end_point):
|
||||
time_delta = 0.1
|
||||
distance = calc_distance(start_point, end_point)
|
||||
return distance / time_delta
|
||||
|
||||
|
||||
def calc_distance(start_point, end_point):
|
||||
distance = math.sqrt(
|
||||
(start_point[0] - end_point[0]) ** 2 +
|
||||
(start_point[1] - end_point[1]) ** 2 +
|
||||
(start_point[2] - end_point[2]) ** 2
|
||||
)
|
||||
return distance
|
||||
|
||||
|
||||
def menu_func(self, context):
|
||||
self.layout.operator(
|
||||
ExportCsv.bl_idname,
|
||||
text="CSV Drone Swarm Animation Exporter (.csv)"
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(ExportCsv)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(ExportCsv)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
@@ -1,25 +0,0 @@
|
||||
0 0.3375 0.0 4.6 0 0 0 0
|
||||
1 0.3375 1.15 4.6 0 0 0 0
|
||||
2 0.3375 2.3 4.6 0 0 0 0
|
||||
3 0.3375 3.45 4.6 0 0 0 0
|
||||
4 0.3375 4.6 4.6 0 0 0 0
|
||||
5 0.3375 0.0 3.45 0 0 0 0
|
||||
6 0.3375 1.15 3.45 0 0 0 0
|
||||
7 0.3375 2.3 3.45 0 0 0 0
|
||||
8 0.3375 3.45 3.45 0 0 0 0
|
||||
9 0.3375 4.6 3.45 0 0 0 0
|
||||
10 0.3375 0.0 2.3 0 0 0 0
|
||||
11 0.3375 1.15 2.3 0 0 0 0
|
||||
12 0.3375 2.3 2.3 0 0 0 0
|
||||
13 0.3375 3.45 2.3 0 0 0 0
|
||||
14 0.3375 4.6 2.3 0 0 0 0
|
||||
15 0.3375 0.0 1.15 0 0 0 0
|
||||
16 0.3375 1.15 1.15 0 0 0 0
|
||||
17 0.3375 2.3 1.15 0 0 0 0
|
||||
18 0.3375 3.45 1.15 0 0 0 0
|
||||
19 0.3375 4.6 1.15 0 0 0 0
|
||||
20 0.3375 0.0 0.0 0 0 0 0
|
||||
21 0.3375 1.15 0.0 0 0 0 0
|
||||
22 0.3375 2.3 0.0 0 0 0 0
|
||||
23 0.3375 3.45 0.0 0 0 0 0
|
||||
24 0.3375 4.6 0.0 0 0 0 0
|
||||
37
builder/clever-config/launch/aruco.launch
Normal file
37
builder/clever-config/launch/aruco.launch
Normal file
@@ -0,0 +1,37 @@
|
||||
<launch>
|
||||
<arg name="aruco_detect" default="true"/>
|
||||
<arg name="aruco_map" default="true"/>
|
||||
<arg name="aruco_vpe" default="true"/>
|
||||
|
||||
<!-- For additional help go to https://clever.copterexpress.com/aruco.html -->
|
||||
|
||||
<!-- aruco_detect: detect aruco markers, estimate poses -->
|
||||
<node name="aruco_detect" pkg="nodelet" if="$(arg aruco_detect)" type="nodelet" args="load aruco_pose/aruco_detect nodelet_manager" output="screen" clear_params="true">
|
||||
<remap from="image_raw" to="main_camera/image_raw"/>
|
||||
<remap from="camera_info" to="main_camera/camera_info"/>
|
||||
<param name="estimate_poses" value="true"/>
|
||||
<param name="send_tf" value="true"/>
|
||||
<param name="known_tilt" value="map"/>
|
||||
<param name="length" value="0.33"/>
|
||||
</node>
|
||||
|
||||
<!-- aruco_map: estimate aruco map pose -->
|
||||
<node name="aruco_map" pkg="nodelet" type="nodelet" if="$(arg aruco_map)" args="load aruco_pose/aruco_map nodelet_manager" output="screen" clear_params="true">
|
||||
<remap from="image_raw" to="main_camera/image_raw"/>
|
||||
<remap from="camera_info" to="main_camera/camera_info"/>
|
||||
<remap from="markers" to="aruco_detect/markers"/>
|
||||
<param name="map" value="$(find aruco_pose)/map/animation_map.txt"/>
|
||||
<param name="known_tilt" value="map"/>
|
||||
<param name="frame_id" value="aruco_map_detected" if="$(arg aruco_vpe)"/>
|
||||
<param name="frame_id" value="aruco_map" unless="$(arg aruco_vpe)"/>
|
||||
</node>
|
||||
|
||||
<!-- vpe publisher from aruco markers -->
|
||||
<node name="vpe_publisher" pkg="clever" type="vpe_publisher" if="$(arg aruco_vpe)" output="screen" clear_params="true">
|
||||
<remap from="~pose_cov" to="aruco_map/pose"/>
|
||||
<remap from="~vpe" to="mavros/vision_pose/pose"/>
|
||||
<param name="frame_id" value="aruco_map_detected"/>
|
||||
<param name="publish_zero" value="true"/>
|
||||
<param name="offset_frame_id" value="aruco_map"/>
|
||||
</node>
|
||||
</launch>
|
||||
71
builder/clever-config/launch/clever.launch
Normal file
71
builder/clever-config/launch/clever.launch
Normal file
@@ -0,0 +1,71 @@
|
||||
<launch>
|
||||
<arg name="fcu_conn" default="usb"/>
|
||||
<arg name="fcu_ip" default="127.0.0.1"/>
|
||||
<arg name="gcs_bridge" default="tcp"/>
|
||||
<arg name="web_video_server" default="true"/>
|
||||
<arg name="rosbridge" default="true"/>
|
||||
<arg name="main_camera" default="true"/>
|
||||
<arg name="optical_flow" default="true"/>
|
||||
<arg name="aruco" default="true"/>
|
||||
<arg name="rc" default="true"/>
|
||||
<arg name="rangefinder_vl53l1x" default="true"/>
|
||||
|
||||
<!-- mavros -->
|
||||
<include file="$(find clever)/launch/mavros.launch">
|
||||
<arg name="fcu_conn" value="$(arg fcu_conn)"/>
|
||||
<arg name="fcu_ip" value="$(arg fcu_ip)"/>
|
||||
<arg name="gcs_bridge" value="$(arg gcs_bridge)"/>
|
||||
</include>
|
||||
|
||||
<!-- web video server -->
|
||||
<node name="web_video_server" pkg="web_video_server" type="web_video_server" if="$(arg web_video_server)" required="false" respawn="true" respawn_delay="5">
|
||||
<param name="default_stream_type" value="ros_compressed"/>
|
||||
<param name="publish_rate" value="1.0"/>
|
||||
</node>
|
||||
|
||||
<!-- aruco markers -->
|
||||
<include file="$(find clever)/launch/aruco.launch" if="$(arg aruco)"/>
|
||||
|
||||
<!-- optical flow -->
|
||||
<node pkg="nodelet" type="nodelet" name="optical_flow" args="load clever/optical_flow nodelet_manager" if="$(arg optical_flow)" clear_params="true" output="screen">
|
||||
<remap from="image_raw" to="main_camera/image_raw"/>
|
||||
<remap from="camera_info" to="main_camera/camera_info"/>
|
||||
<param name="calc_flow_gyro" value="true"/>
|
||||
</node>
|
||||
|
||||
<!-- main nodelet manager -->
|
||||
<node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager" output="screen" clear_params="true">
|
||||
<param name="num_worker_threads" value="2"/>
|
||||
</node>
|
||||
|
||||
<node pkg="tf2_ros" type="static_transform_publisher" name="map_flipped_frame" args="0 0 0 3.1415926 3.1415926 0 map map_flipped"/>
|
||||
|
||||
<!-- simplified offboard control -->
|
||||
<node name="simple_offboard" pkg="clever" type="simple_offboard" output="screen" clear_params="true">
|
||||
<param name="reference_frames/body" value="map"/>
|
||||
<param name="reference_frames/base_link" value="map"/>
|
||||
</node>
|
||||
|
||||
<!-- Auxiliary frames -->
|
||||
<node name="frames" pkg="clever" type="frames" output="screen">
|
||||
<param name="body/frame_id" value="body"/>
|
||||
</node>
|
||||
|
||||
<!-- main camera -->
|
||||
<include file="$(find clever)/launch/main_camera.launch" if="$(arg main_camera)"/>
|
||||
|
||||
<!-- rosbridge -->
|
||||
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch" if="$(eval rosbridge or rc)"/>
|
||||
|
||||
<!-- tf2 republisher for web visualization -->
|
||||
<node name="tf2_web_republisher" pkg="tf2_web_republisher" type="tf2_web_republisher" output="screen" if="$(arg rosbridge)"/>
|
||||
|
||||
<!-- vl53l1x ToF rangefinder -->
|
||||
<node name="vl53l1x" pkg="vl53l1x" type="vl53l1x_node" output="screen" if="$(arg rangefinder_vl53l1x)">
|
||||
<param name="frame_id" value="rangefinder"/>
|
||||
<remap from="~range" to="mavros/distance_sensor/rangefinder_sub"/> <!-- redirect data to FCU -->
|
||||
</node>
|
||||
|
||||
<!-- rc backend -->
|
||||
<node name="rc" pkg="clever" type="rc" output="screen" if="$(arg rc)"/>
|
||||
</launch>
|
||||
37
builder/clever-config/launch/main_camera.launch
Normal file
37
builder/clever-config/launch/main_camera.launch
Normal file
@@ -0,0 +1,37 @@
|
||||
<launch>
|
||||
<!-- Camera position and orientation are represented by base_link -> main_camera_optical transform -->
|
||||
<!-- static_transform_publisher arguments: x y z yaw pitch roll frame_id child_frame_id -->
|
||||
|
||||
<!-- article about camera setup: https://clever.copterexpress.com/camera_frame.html -->
|
||||
|
||||
<!-- camera is oriented downward, camera cable goes backward [option 1] -->
|
||||
<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/>
|
||||
|
||||
<!-- camera is oriented downward, camera cable goes forward [option 2] -->
|
||||
<!--<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 1.5707963 0 3.1415926 base_link main_camera_optical"/>-->
|
||||
|
||||
<!-- camera is oriented upward, camera cable goes backward [option 3] -->
|
||||
<!--<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 0.07 1.5707963 0 0 base_link main_camera_optical"/>-->
|
||||
|
||||
<!-- camera is oriented upward, camera cable goes forward [option 4] -->
|
||||
<!--<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 0.07 -1.5707963 0 0 base_link main_camera_optical"/>-->
|
||||
|
||||
<!-- camera node -->
|
||||
<node pkg="nodelet" type="nodelet" name="main_camera" args="load cv_camera/CvCameraNodelet nodelet_manager" clear_params="true">
|
||||
<param name="frame_id" value="main_camera_optical"/>
|
||||
<param name="camera_info_url" value="file://$(find clever)/camera_info/fisheye_cam_320.yaml"/>
|
||||
|
||||
<param name="rate" value="100"/> <!-- poll rate -->
|
||||
<param name="cv_cap_prop_fps" value="40"/> <!-- camera FPS -->
|
||||
<param name="capture_delay" value="0.02"/> <!-- approximate delay on frame retrieving -->
|
||||
|
||||
<!-- camera resolution, NOTE: camera_info file should match it -->
|
||||
<param name="image_width" value="320"/>
|
||||
<param name="image_height" value="240"/>
|
||||
</node>
|
||||
|
||||
<!-- camera visualization markers -->
|
||||
<node pkg="clever" type="camera_markers" ns="main_camera" name="main_camera_markers">
|
||||
<param name="scale" value="3.0"/>
|
||||
</node>
|
||||
</launch>
|
||||
8
builder/clever-config/map/animation_map.txt
Normal file
8
builder/clever-config/map/animation_map.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
107 0.33 0 0 0 0 0 0
|
||||
106 0.33 0.77 0 0 0 0 0
|
||||
105 0.33 0 0.77 0 0 0 0
|
||||
104 0.33 0.77 0.77 0 0 0 0
|
||||
103 0.33 0 1.54 0 0 0 0
|
||||
102 0.33 0.77 1.54 0 0 0 0
|
||||
101 0.33 0 2.31 0 0 0 0
|
||||
100 0.33 0.77 2.31 0 0 0 0
|
||||
@@ -30,10 +30,12 @@ echo_stamp() {
|
||||
|
||||
REPO_DIR="/mnt"
|
||||
SCRIPTS_DIR="${REPO_DIR}/builder"
|
||||
CONFIG_DIR="${SCRIPTS_DIR}/clever-config"
|
||||
IMAGES_DIR="${REPO_DIR}/images"
|
||||
|
||||
[[ ! -d ${SCRIPTS_DIR} ]] && (echo_stamp "Directory ${SCRIPTS_DIR} doesn't exist" "ERROR"; exit 1)
|
||||
[[ ! -d ${IMAGES_DIR} ]] && mkdir ${IMAGES_DIR} && echo_stamp "Directory ${IMAGES_DIR} was created successful" "SUCCESS"
|
||||
[[ ! -d ${CONFIG_DIR} ]] && mkdir ${CONFIG_DIR} && echo_stamp "Directory ${CONFIG_DIR} was created successful" "SUCCESS"
|
||||
|
||||
if [[ -z ${TRAVIS_TAG} ]]; then IMAGE_VERSION="$(cd ${REPO_DIR}; git log --format=%h -1)"; else IMAGE_VERSION="${TRAVIS_TAG}"; fi
|
||||
# IMAGE_VERSION="${TRAVIS_TAG:=$(cd ${REPO_DIR}; git log --format=%h -1)}"
|
||||
@@ -105,7 +107,10 @@ git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
|
||||
|
||||
# Copy service file for clever show client
|
||||
img-chroot ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clever-show.service' '/lib/systemd/system/'
|
||||
img-chroot ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/animation_map.txt' '/home/pi/catkin_ws/src/clever/aruco_pose/map/'
|
||||
|
||||
# Copy config files for clever
|
||||
if [[ -d "${CONFIG_DIR}/launch" ]]; then img-chroot ${IMAGE_PATH} copy ${CONFIG_DIR}'/launch' '/home/pi/catkin_ws/src/clever/clever'; fi
|
||||
if [[ -d "${CONFIG_DIR}/map" ]]; then img-chroot ${IMAGE_PATH} copy ${CONFIG_DIR}'/map' '/home/pi/catkin_ws/src/clever/aruco_pose'; fi
|
||||
|
||||
# Shrink image
|
||||
img-resize ${IMAGE_PATH}
|
||||
|
||||
@@ -23,7 +23,7 @@ echo_stamp() {
|
||||
}
|
||||
|
||||
# rename wifi ssid
|
||||
sed -i "s/NEW_SSID='CLEVER/NEW_SSID='CleverShow/" /root/init_rpi.sh
|
||||
sed -i "s/NEW_SSID='CLEVER/NEW_SSID='CLEVERSHOW/" /root/init_rpi.sh
|
||||
|
||||
# add sudoers variables to make sudo works with ros (for led strip)
|
||||
grep -qxF 'Defaults env_keep += "ROS_LOG_DIR"' /etc/sudoers || cat << EOT >> /etc/sudoers
|
||||
@@ -38,13 +38,5 @@ Defaults env_keep += "ROS_HOME"
|
||||
Defaults env_keep += "ROS_LOG_DIR"
|
||||
EOT
|
||||
|
||||
# configure aruco.launch and clever.launch (for positioning with aruco map)
|
||||
sed -i '/<arg name="aruco_map"/c \ <arg name="aruco_map" default="true"/>' /home/pi/catkin_ws/src/clever/clever/launch/aruco.launch
|
||||
sed -i '/<arg name="aruco_vpe"/c \ <arg name="aruco_vpe" default="true"/>' /home/pi/catkin_ws/src/clever/clever/launch/aruco.launch
|
||||
sed -i '/<param name="map"/c \ <param name="map" value="\$\(find aruco_pose\)/map/animation_map.txt"/>' /home/pi/catkin_ws/src/clever/clever/launch/aruco.launch
|
||||
sed -i '/<arg name="aruco"/c \ <arg name="aruco" default="true"/>' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch
|
||||
sed -i '/<arg name="rangefinder_vl53l1x"/c \ <arg name="rangefinder_vl53l1x" default="true"/>' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch
|
||||
sed -i '/<arg name="optical_flow"/c \ <arg name="optical_flow" default="true"/>' /home/pi/catkin_ws/src/clever/clever/launch/clever.launch
|
||||
|
||||
echo_stamp "Image was configured!" "SUCCESS"
|
||||
|
||||
|
||||
23
docs/blender-addon.md
Normal file
23
docs/blender-addon.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Установка и настройка аддона
|
||||
## Установка
|
||||
1. Скачайте [аддон](https://github.com/artem30801/blender-csv-animation) для экспорта анимации из Blender в полётные пути для коптеров.
|
||||
2. Скачайте и установите согласно инструкциям последнюю версию Blender 2.8 (beta) с [оффициального сайта](https://builder.blender.org/download/) или при использовании OS Linux через команду терминала:
|
||||
```bash
|
||||
snap install blender --channel=beta --classic
|
||||
```
|
||||
3. Откройте Blender, в верхнем меню выберите `Edit > Preferences`. В открывшемся окне настроек в боковой панели выберите пункт `Add-ons`. Нажмите на кнопку `Install...` в верхнем правом углу окна. В диалоговом окне откройте путь к папке со склонированным репозиторием проекта и выберите файл `addon.py` по пути [`blender-csv-animation/addon.py`](https://github.com/artem30801/blender-csv-animation/blob/master/addon.py). Нажмите `Install Add-on from file...`. Аддон установлен.
|
||||
## Активация
|
||||
В выпадающем списке `All` выберите пункт `User`. Поставьте "галочку" напротив аддона `Import-Export: Export > CSV Drone Swarm Animation Exporter` для активации аддона. Аддон активирован и готов к работе. Выполнение этих операций не понадобится при дальнейших запусках Blender.
|
||||
## Дополнительно
|
||||
Для деактивации аддона уберите "галочку" напротив имени аддона, как описано в предыдущем пункте. Для получения дополнительных сведений (версия, путь к файлу...) нажмите знак стрелочки слева от поля активации. В развернувшемся блоке так же есть кнопки: `Documentation` - ведет на страницу документации аддона (вы тут); `Report a bug` - ведет на страницу багтрекера на репозитории аддона; `Remove` - удалят (деинсталлирует) аддон (перед установокой новой версии рекомендуется удалить старую).
|
||||
# Подготовка и создание анимации дронов
|
||||
...
|
||||
[Пример](https://github.com/artem30801/blender-csv-animation/blob/master/Examples/copter_base_animation.blend) можно использовать в качестве шаблона.
|
||||
# Экпорт при помощи аддона
|
||||
Для вызова диалогового окна экспорта нажмите в верхнем меню `File > Export > CSV Drone Swarm Animation Exporter`. В открывшемся окне экспорта необходимо выбрать целевой путь экспорта и название папки, которую создаст аддон в процессе экспорта. В боковом меню доступна панель параметров экспорта:
|
||||
* `Use name filter for objects` - при отключении этого параметра будут экспортированы _все видимые объекты_
|
||||
* `Name identifier`
|
||||
* `Show detailed animation warnings` -
|
||||
* `Speed limit` - при нарушении указанного ограничения по скорости передвижения дронов будут выведены предупреждения
|
||||
* `Distance limit` - при нарушении указанной минимальной дистанции между дронами будут выведены предупреждения
|
||||
После настройки (при необходимости) нужных параметров нажмите кнопку `Export Drone Swarm animation`
|
||||
0
docs/client.md
Normal file
0
docs/client.md
Normal file
45
docs/image-building.md
Normal file
45
docs/image-building.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Сборка модифицированного образа
|
||||
|
||||
Иногда возникает необходимость собрать образ с настройками коптера, отличными от релизной версии образа. Есть несколько способов это сделать.
|
||||
|
||||
## Подготовка к сборке
|
||||
Установите [docker](https://www.docker.com):
|
||||
```bash
|
||||
sudo apt install docker.io
|
||||
```
|
||||
|
||||
## Локальная сборка с изменением настроек Клевера
|
||||
|
||||
* Замените файлы настроек Клевера (launch файлы и карту) в [папке](../builder/clever-config) `builder/clever-config` в директории с исходным кодом CleverSwarm.
|
||||
* Соберите свой образ с помощью docker:
|
||||
```bash
|
||||
cd source-dir
|
||||
sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5
|
||||
```
|
||||
|
||||
## Ручная настройка образа
|
||||
|
||||
* Разархивируйте файл со скачанным образом, перейдите в директорию с этим образом, и войдите в консоль сборщика образа с помощью команды:
|
||||
```bash
|
||||
cd image-dir
|
||||
sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-chroot /mnt/<IMAGE>
|
||||
```
|
||||
где `<IMAGE>` - имя файла образа. В открывшемся терминале с помощью стандартных программ (nano, git, cp, apt-get) вы можете донастроить образ.
|
||||
* Внешние файлы вы можете перенести в образ с помощью команды:
|
||||
```bash
|
||||
sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-chroot /mnt/<IMAGE> copy /mnt/<MOVE_FILE> <MOVE_TO>
|
||||
```
|
||||
где `<MOVE_FILE>` - файл, который нужно перенести в образ (расположение относительно папки с образом, например `../builder/assets/clever-show.service`), а `<MOVE_TO>` - путь в образе, куда нужно переместить файл.
|
||||
* Если в образе не хватает места для всех необходимых файлов, можно расширить образ с помощью команды:
|
||||
```bash
|
||||
sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-resize /mnt/<IMAGE> max <SIZE>
|
||||
```
|
||||
где `<SIZE>` - размер в байтах. Например 5G будет означать 5GB, а 5M - 5MB.
|
||||
* После расширения образа его можно сжать до минимального размера + 10МB командой
|
||||
```bash
|
||||
sudo docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/mnt goldarte/img-tool:v0.5 img-resize /mnt/<IMAGE> min
|
||||
```
|
||||
|
||||
## Изменение скриптов сборки
|
||||
|
||||
Статья по изменению скриптов сборки образа и создания кастомной сборки написана [здесь](https://clever.copterexpress.com/ru/image_building.html)
|
||||
103
docs/server.md
Normal file
103
docs/server.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Настройка сервера
|
||||
## Файл конфигурации
|
||||
Конфигурация сервера задаётся в файле Server/server_config.ini, имеющем вид (по умолчанию):
|
||||
```ini
|
||||
[SERVER]
|
||||
port = 25000
|
||||
buffer_size = 1024
|
||||
|
||||
[BROADCAST]
|
||||
use_broadcast = True
|
||||
broadcast_port = 8181
|
||||
broadcast_delay = 5
|
||||
|
||||
[NTP]
|
||||
use_ntp = False
|
||||
host = ntp1.stratum2.ru
|
||||
port = 123
|
||||
```
|
||||
Конфигурация по умолчанию является полностью работоспособной и не требует изменений для быстрого начала работы системы.
|
||||
### Раздел 'Server'
|
||||
В этом разделе задаются параметры сетевого взаимодействия сервера, доступны следующие параметры:
|
||||
|
||||
* `port` - TCP порт, на котором будут приниматься входящие соединения от клиентов (коптеров). При использовании broadcast данный порт будет сконфигурирован у клиента автоматически. *Рекомендуется изменить значение по умолчанию в целях безопасности* (любое пятизначное и более число, если другое ПО не использует выбранный порт).
|
||||
* `buffer_size` - размер буфера при приёме и передаче данных. *Не рекомендуется изменять. Рекомендуется использовать единое значение у сервера и клиентов.*
|
||||
|
||||
### Раздел 'Broadcast'
|
||||
Сервер использует UDP broadcast (на адрес 255.255.255.255 с выбранным портом), чтобы передавать клиентам (коптерам) актуальную информацию о конфигурации сервера и собственном адресе сервера для подключения (IP адрес и порт сервера). Таким образом, обеспечивается автоматическое подключение клиентов к серверу без необходимости дополнительной ручной конфигурации. В данном разделе задаются параметры этого механизма.
|
||||
* `use_broadcast` - будут ли использованы broadcast'ы для передачи данных (при значении `False` broadcast'ы НЕ будут отправляться). Используйте `False` в случае повышенных требований безопасности, перегруженности сети или невозможности передачи по широковещательному каналу (из-за конфигурации брандмауэра или сети)
|
||||
* `broadcast_port` - UDP порт, по которому будет осуществляться отправка сообщений. *Рекомендуется изменить значение по умолчанию в целях безопасности.* **Внимание!** При изменении этого параметра клиенты НЕ смогут принимать сообщения автоконфигурации до изменения (вручную) соответствующего параметра в конфигурации клиента на равное значение.
|
||||
* `broadcast_delay` - Периодичность (в секундах, целочисленное значение), с которой будет происходить отправка broadcast сообщений. Увеличьте задержку для уменьшения нагрузки на сеть. *ИЛИ* Уменьшите задержку для уменьшения времени отклика и подключения при первом запуске клиентов.
|
||||
### Раздел 'NTP'
|
||||
Помимо синхронизации времени (с миллисекундной точностью) с помощью пакета chrony, предоставляется альтернатива - возможность использования внешних (при наличии соединения локальной сети с интернетом) или внутрисетевых NTP-серверов. **Внимание!** Для корректной работы системы, и сервер, *и* клиенты должны использовать единый способ синхронизации времени (набор параметров в этом разделе). Данный раздел полностью унифицирован и для сервера, и для клиентов.
|
||||
* `use_ntp` - Определяет, будет ли использоваться синхронизация времени с помощью NTP. (при значении `False` будет использовано локальное время ОС (синхронизируется автоматически при использовании chrony). *Рекомендуется использование crhony, а не NTP*
|
||||
* `host` - имя хоста или IP адрес NTP сервера (локального или удаленного)
|
||||
* `port` - порт, используемый NTP сервером
|
||||
|
||||
# Интерфейс сервера
|
||||
Сервер имеет визуальный графический интерфейс для удобства взаимодействия.
|
||||
## Глоссарий
|
||||
Некоторые термины, используемые для краткости записи:
|
||||
* Готовый [к полёту] коптер:
|
||||
Прошедший предполётную проверку (`Preflight check`) и имеющий удовлетворительные результаты по всем необходимым столбцам (зелёные ячейки в таблице). Учитываются проверки аккумулятора и сообщения selfcheck.
|
||||
* Не готовый [к полёту] коптер:
|
||||
НЕ прошедший предполётную проверку (`Preflight check`) (не имеющий её результатов в таблице - жёлтые ячейки) или же имеющий НЕудовлетворительные результаты (красные ячейки в таблице). Учитываются проверки аккумулятора и сообщения selfcheck.
|
||||
|
||||
## Меню
|
||||
### Раздел 'Actions'
|
||||
Данный раздел содержит несколько утилит по отправке различных данных на *выбранные* клиенты. **Внимание!** Не пытайтесь использовать данные команды во время полёта коптеров!
|
||||
* `Send Animations` - отправка файлов анимации (экспортированных аддоном к Blender) на выбранные клиенты (коптеры). В диалоговом окне необходимо выбрать *папку*, содержащую файлы анимации (автоматически создается аддоном). Каждый файл анимации будет отправлен на клиент с именем (copter ID), соответствующим имени файла без расширения.
|
||||
* `Send Configurations` - отправка *единого* файла конфигурации клиента на все выбранные клиенты. В диалоговом окне необходимо выбрать *один* файл конфигурации в установленном формате. Файл конфигурации может быть неполным, в таком случае будут перезаписаны лишь указанные в файле параметры. *Не рекомендуется использовать данное действие для массовой перезаписи `Copter ID`, кроме значения `/hostname`.* **Внимание!** НЕ отправляйте на клиенты файл конфигурации сервера.
|
||||
* `Send Aruco map` - отправка *единого* файла карты aruco маркеров на все выбранные клиенты. В диалоговом окне необходимо выбрать *один* файл карты в установленном формате. Файл на клиенте будет перезаписан. После получения и записи файла клиент автоматически перезапустит сервис `clever`. Для работоспособности полётных функция *необходимо подождать* некоторое время до полного запуска сервиса.
|
||||
|
||||
## Боковая панель инструментов (команд)
|
||||
### Управление
|
||||
Данный раздел команд предназначен для выскоуровневого управления роем дронов.
|
||||
* Кнопка `Preflight check` - Все выбранные клиенты выполняют самодиагностику и предполётную проверку. Результаты, вместе с другими параметрами клиента, будут отображены в таблице по мере поступления данных.
|
||||
* Спинбокс `Start after N seconds` - Задаёт время задержки до синхронного запуска выполнения анимаций коптерами. *Не рекомендуется использовать `0` (нулевую задержку). Для загруженных\подверженных помехам\имеющих большой пинг сетей рекомендуется использовать бо́льшие значения (>5 секунд).*
|
||||
* Кнопка `Start animation` - По истечению заданного в `Start after` времени, все выбранные коптеры совершат **взлёт**ные процедуры, перелетают на стартовые точки своих анимаций и *синхронно* выполнят полётное задание (анимацию). По окончанию анимации все коптеры выполнят посадку *на месте окончания своей анимации*. Кнопка деактивирована по умолчанию и если среди выбранных коптеров есть *не готовые коптеры* (все выбранные коптеры должны быть готовыми). *При нажатии запрашивается дополнительное предупреждение!*
|
||||
* Кнопка `Pause` - Ставит на 'паузу' все выбранные коптеры (их очередь заданий): приостанавливается выполнение любого полётного задания. *Используйте в чрезвычайных случаях.* **Внимание!** Данная команда НЕ прерывает полёт коптера в уже указанную точку (например: элементы взлёта, посадки; следование до начальной точки анимации и т.д.)
|
||||
* Кнопка `Resume` - Все выбранные коптеры *синхронизированно* продолжат выполнение своих очередей заданий (например: исполнение анимации)
|
||||
* Кнопка `Stop` - Прерывает выполнение полётных заданий *ВСЕХ* подключенных коптеров. Сбрасывает очередь заданий - *действие необратимо*. **Используйте в экстренных случаях как одно из средств перехвата.** **Внимание!** Данная команда НЕ прерывает полёт коптера в уже указанную точку (например: элементы взлёта, посадки; следование до начальной точки анимации и т.д.)
|
||||
* Кнопка `Emergency land` - Открывает диалоговое окно дополнительного модуля быстрого выбора коптера и его последующей экстренной посадки \ дизарма. *Смотреть далее.*
|
||||
### Полётные функции (команды)
|
||||
В данном разделе находятся команды, позволяющие напрямую управлять коптером(ами).
|
||||
* Кнопка `Test leds` - Все выбранные коптеры выполняют двухсекундную анимацию (бегущие точки) светодиодной лентой (белым цветом). Команда *безопасна* и может быть использована для проверки работы светодиодных лент \ качества и задержки подключения к серверу \ определения соответствия коптера и его `Copter ID` в таблице.
|
||||
* Кнопка `Takeoff` - Все выбранные коптеры **совершают взлёт**, после чего зависают над точкой взлёта. Аналогично `Start animation`, кнопка активна, *только* если все выбранные коптеры готовы. **Внимание!** Используйте осторожно, соблюдайте технику безопасности. Не применяйте во время выполнения других полётных функций!
|
||||
* Кнопка `Flip` - Все выбранные коптеры **совершают флип (flip)** - переворот на 360 градусов вокруг одной из *горизонтальных* осей. **Внимание!** Используйте осторожно, соблюдайте технику безопасности. *Для исполнения флипа коптер должен иметь минимальную высоту >2м.* Не применяйте во время выполнения других полётных функций!
|
||||
* Кнопка `Land` - ВСЕ коптеры прекращают выполнение своих полётных заданий, очищают очередь заданий и немедленно *переходят в режим посадки.* **Используйте в экстренных случаях как одно из средств перехвата.**
|
||||
* Кнопка `Diarm` - ВСЕ коптеры прекращают выполнение своих полётных заданий, очищают очередь заданий и немедленно *отключают моторы (disarm).* ==Это может привести к падению и повреждению коптеров== **Используйте в крайних случаях как последнее из средств перехвата.**
|
||||
|
||||
## Таблица состояния коптеров (клиентов)
|
||||
При первом подключении клиента к серверу в таблицу добавляется строка для отображения состояния клиента, содержащая начальные данные, переданные клиентом при подключении (`Copter ID`). Строки НЕ удаляются после зарегистрированного отключения клиента. Строки можно сортировать по возрастанию \ убыванию значений любого из столбцов (кликнув по заголовку столбца).
|
||||
|
||||
Ячейки таблицы подсвечиваются:
|
||||
* жёлтым, если необходимое значение отсутствует
|
||||
* красным, если значение (состояние) ячейки неудовлетворительно (согласно внутренним проверкам)
|
||||
* зелёным, если значение (состояние) ячейки удовлетворительно (согласно внутренним проверкам)
|
||||
### Столбцы таблицы
|
||||
* `copter ID` - имя (идентификатор) клиента. Может быт сконфигурирован на стороне клиента. Отображается сразу при подключении клиента. Рядом с каждым ID коптера расположен чекбокс - коптеры, чей ID отмечен чекбоксом положительно (галочка), считаются *выбранными*.
|
||||
* `animation ID` - внутреннее название файла анимации, подгруженного клиентом. Отображается после выполнения `selfcheck`. *Проверьте соответствие названий файлов анимаций у коптеров*
|
||||
* `battery V` - абсолютное значение напряжения на аккумуляторе коптера (в Вольтах, по данным полётного контроллера). *Убедитесь, что напряжение не ниже порогового для вашего аккумулятора.* **При критически низком значении коптер считается не готовым** - блокируется возможность взлёта и старта анимации.
|
||||
* `battery %` - относительное значение напряжения на аккумуляторе коптера. Значение рассчитывается по среднему напряжению (по данным полётного контроллера) на ячейку аккумулятора (банку). *Убедитесь, что уровень заряда перед вылетом не менее 30%* **При критически низком значении коптер считается не готовым** - блокируется возможность взлёта и старта анимации.
|
||||
* `selfcheck` - Все дополнительные сообщения и ошибки при самодиагностике (*Смотреть далее.*). При успешном прохождении самодиагностики без ошибок выводится значение `OK`, ячейка подсвечивается зелёным цветом. **При наличии ошибок коптер считается не готовым** - блокируется возможность взлёта и старта анимации.
|
||||
* `time delta` - Разница между временем на сервере и клиенте (в секундах). *При слишком больших значениях сигнализирует об отсутствии синхронизации времени между коптером и клиентом!* В это значение так же входит сетевая задержка.
|
||||
|
||||
# Дополнительные операции
|
||||
## Selfcheck
|
||||
..
|
||||
|
||||
## Emergency land
|
||||
Модуль экстренной посадки/дизарма, предназначенный для быстрого поиска оператором визуально неисправного коптера методом бинарного поиска
|
||||
### Интерфейс
|
||||
* Зелёная кнопка `1` - ...
|
||||
* Красная кнопка `2` - ...
|
||||
* Кнопка `Land` - все коптеры в выбранной ('зелёной') группе совершат процедуру экстренной посадки (аналогично кнопке `Land` в панели инструментов).
|
||||
* Кнопка `Disarm` - все коптеры в выбранной ('зелёной') группе *немедленно отключают моторы (disarm).* (аналогично кнопке `Disarm` в панели инструментов) ==Это может привести к падению и повреждению коптеров==.
|
||||
### Алгоритм использования
|
||||
* ...
|
||||
<!--stackedit_data:
|
||||
eyJoaXN0b3J5IjpbLTE1MDIyMDAwMjgsOTI1MDAyMDkwLC0xMz
|
||||
IzMTk2MzMzLC01MDIzODYyNjMsLTI5NDk3MDcyOCw5MzY1NzEz
|
||||
ODgsODcyNjgwNjE4XX0=
|
||||
-->
|
||||
57
docs/start-tutorial.md
Normal file
57
docs/start-tutorial.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Инструкция по настройке и запуску клиента и сервера
|
||||
|
||||
## Список оборудования
|
||||
Данное ПО предназначено для управления несколькими квадракоптерами с компьютера-сервера. Для полноценной работы необходимо следующее оборудование:
|
||||
* Один или несколько квадрокоптеров, работающих на базе ПО [Клевер](https://github.com/copterexpress/clever).
|
||||
* Компьютер с операционной системой Linux.
|
||||
* Wifi роутер, работающий на частоте 2.4 ГГц, либо 5.8 ГГц, если эту частоту поддерживают wifi модули коптеров и компьютера.
|
||||
|
||||
## Подготовка ПО
|
||||
Скачайте на компьютер последний образ (CleverSwarm-XXX.img.zip) и исходный код (Source code) из последнего [релиза](https://github.com/artem30801/CleverSwarm/releases/latest). Разархивируйте исходный код в удобную директорию.
|
||||
|
||||
## Настройка роутера
|
||||
Для управления одним или несколькими коптерами требуется подключение коптеров и сервера к одной сети. Для этого требуется отдельный wifi роутер с известным SSID и паролем. Подключите компьютер, который будет использоваться в качестве сервера, к сети роутера и узнайте его ip адрес - он понадобится для дальнейшей настройки.
|
||||
|
||||
## Настройка и запуск клиента
|
||||
|
||||
* Запишите образ на microSD карту, используя [Etcher](https://www.balena.io/etcher/).
|
||||
* Вставьте флешку в Raspberry Pi, включите коптер. Дождитесь появления сети `CLEVERSHOW-XXXX`.
|
||||
* Подключитесь к сети коптера, используя пароль `cleverwifi`.
|
||||
* Настройте коптер, чтобы корректно работал режим позиции. По-умолчанию образ сконфигурирован для получения позиции с камеры с помощью aruco-маркеров и optical flow. Камера направлена вниз и вперёд, загружена тестовая карта меток. Если ваш способ позиционирования отличается - можно либо настроить данный образ, либо [собрать образ](image-building.md) со своими настройками.
|
||||
* Перейдите в директорию клиента и запустите скрипт настройки клиента
|
||||
```bash
|
||||
cd ~/CleverSwarm/Drone
|
||||
sudo ./client_setup.sh
|
||||
```
|
||||
* Выполните скрипт настройки клиента с указанными параметрами - SSID, пароль точки доступа, имя коптера, ip сервера.
|
||||
* Коптер переключится в режим клиента указанной точки доступа и настроит автозапуск клиента copter_client.py
|
||||
|
||||
Документация по клиентской части находится [здесь](client.md).
|
||||
|
||||
## Настройка и запуск сервера
|
||||
* Установите [chrony](https://chrony.tuxfamily.org/index.html) и Python 3 на ваш компьютер:
|
||||
```bash
|
||||
sudo apt install chrony python3 python3-pip
|
||||
```
|
||||
* Установите необходимые python-пакеты с помощью команды (запущенной из директории с исходным кодом)
|
||||
```bash
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
* Подключитесь к wifi сети роутера, к которому подключены коптеры.
|
||||
* Скопируйте [файл настроек chrony](../Server/chrony.conf) в `/etc/chrony/chrony.conf`. Если ip адрес сети начинается не с `192.168.`, то исправьте адрес после слова allow в скопированном файле настроек.
|
||||
* Перезапустите сервис chrony
|
||||
```bash
|
||||
cd source-code-dir
|
||||
sudo systemctl restart chrony
|
||||
```
|
||||
* Перейдите в директорию сервера из директории с исходным кодом и запустите сервер
|
||||
```bash
|
||||
cd source-code-dir/Server
|
||||
python3 server_qt.py
|
||||
```
|
||||
|
||||
Документация по серверной части находится [здесь](server.md).
|
||||
<!--stackedit_data:
|
||||
eyJoaXN0b3J5IjpbLTIwNjI5MzIwMTFdfQ==
|
||||
-->
|
||||
2
install_requirements.bash
Normal file
2
install_requirements.bash
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
pip3 install -r requirements.txt
|
||||
2
install_requirements.bat
Normal file
2
install_requirements.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
pip3 install -r requirements.txt
|
||||
pause
|
||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
indexed.py==0.0.1
|
||||
numpy==1.16.4
|
||||
PyQt5==5.13.0
|
||||
PyQt5-sip==4.19.18
|
||||
selectors2==2.0.1
|
||||
Reference in New Issue
Block a user