Compare commits

...

226 Commits
v0.3 ... v0.6

Author SHA1 Message Date
Oleg Kalachev
a91f9e5a6b Change image size to from 8G to 7G 2018-05-10 16:40:05 +03:00
Oleg Kalachev
6b74f75616 Merge branch 'master' of github.com:CopterExpress/clever 2018-05-09 19:50:46 +03:00
Oleg Kalachev
9cd9babb83 simple_offboard: yaw_rate, pitch_rate, roll_rate in get_telemetry 2018-05-09 19:50:18 +03:00
Smirnov Artem
380c14da56 image_buider: enable hardware uart with raspi-config (#43)
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-05-05 20:36:22 +03:00
urpylka
32c1c18af2 image_builder: fix syntax
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-05-05 16:50:36 +03:00
urpylka
b7077339a1 image_builder: add sha256sum to release message
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-05-03 22:33:57 +03:00
urpylka
52fd505ffc image_builder: change spaces
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-05-03 22:33:57 +03:00
urpylka
b911b7a3dd image_builder: fix syntax
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-05-03 22:01:29 +03:00
Smirnov Artem
9b38d5135e image_builder: fix small mistake 2018-04-27 20:14:33 +03:00
Smirnov Artem
0346c48546 Merge pull request #39 from CopterExpress/image_builder_refactor_23042018
Image builder refactor 23042018
2018-04-27 13:49:16 +03:00
urpylka
212c6ca5ac image_config: fix output debug 2018-04-27 13:42:12 +03:00
urpylka
361c89d016 image_config: little fix & add more debug output 2018-04-27 13:35:32 +03:00
urpylka
b0cbc67799 image_config: add debug output 2018-04-27 13:26:28 +03:00
urpylka
18cfb08054 image_builder: fix comment 2018-04-26 23:43:55 +03:00
Smirnov Artem
66121e6d5d Rename jenkinsfile to Jenkinsfile 2018-04-26 23:41:30 +03:00
urpylka
a4841de17e image_builder: try fix with send big string as argument
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-26 23:37:37 +03:00
Oleg Kalachev
84aef97e37 docs: fixes 2018-04-26 00:11:20 +03:00
Oleg Kalachev
f14e1976e7 docs: fix 2018-04-26 00:10:20 +03:00
Oleg Kalachev
8c9acc98fb docs: qr example 2018-04-26 00:09:12 +03:00
Oleg Kalachev
bd36428bd4 docs: typo 2018-04-25 23:24:44 +03:00
urpylka
7f7276e34a image_builder: fix bug with GH credentials after parsing json
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 22:24:02 +03:00
urpylka
460761ef68 image_builder: fix small bug
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 21:27:12 +03:00
urpylka
9fefc6428e image_builder: fix small bugs
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 21:09:42 +03:00
urpylka
ffe4423c10 docs: remove duplicates after merge
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 20:46:16 +03:00
Smirnov Artem
3f02919cd9 Merge pull request #36 from Yuliya1404/master
Updated assemble and lessons
2018-04-24 20:19:48 +03:00
Yuliya1404
3075badf33 docs: update lessons & assemble article
* Update tb.md

* Update testConnection.md

* Update safety.md

* Delete brrc2205ondeck.png

* Add files via upload

* Create connectortypes.md

* Add files via upload

* Update connectortypes.md

* Update assemble.md

* Add files via upload

* Create metod.md

* Update metodmaterials.md

* Create tests.md

* Update SUMMARY.md

* Create lessons.md

* Update lessons.md
2018-04-24 20:06:20 +03:00
urpylka
29d66ee264 image_builder: add readme-file about builder
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
846ec3a430 image_builder: made absolute path in jenkinsfile
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
a65a50ffd3 image_builder: change ini to json in yadisk.py
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
c945bb9d03 image_builder: made var YA_SCRIPT
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
3dc9575c9e image_builder: refactor comment
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
f901167009 image_builder: replace ini to json, requests to curl
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
8519a6c6a4 image_builder: refactor path to execute-files
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
d8fc2c088f image_builder: fix bag with switch-case order in bash
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
679cd37ec6 image_builder: fix bag with IMAGE_VERSION
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
40be77f9c3 image_builder: refactor publish_image functions
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
1a0d762c4e image_builder: hardware configure by raspi-config
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
a7e0032225 image_builder: fix syntax
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
0b9df02faa image_builder: translate couple comments
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:03 +03:00
urpylka
0dcf7d1520 image_builder: remove not used code
Signed-off-by: Artem Smirnov <urpylka@gmail.com>
2018-04-24 19:02:02 +03:00
Smirnov Artem
b146057ca7 Merge pull request #35 from Svetk0/Svetk0-setup
docs: update
2018-04-24 19:01:01 +03:00
urpylka
2628d912cd image_builder: refactor 2018-04-16 21:24:03 +03:00
Oleg Kalachev
2e75d531a6 docs: small fix 2018-04-12 21:54:09 +03:00
Oleg Kalachev
be7607bc17 docs: small fix 2018-04-12 20:36:43 +03:00
Oleg Kalachev
5bd724141e docs: redice rc switch snippet + coding note 2018-04-12 20:34:46 +03:00
Oleg Kalachev
7b5538c104 docs: circle snippet 2018-04-12 20:20:26 +03:00
Oleg Kalachev
462e7d6ffe docs: angle to horizon 2018-04-12 18:38:34 +03:00
Svetk0
68a32e036e Rename calibratePID to calibratePID.md 2018-04-12 17:09:10 +03:00
Svetk0
dba5b63230 Update setup.md 2018-04-12 17:08:16 +03:00
Svetk0
26efccb110 Add files via upload 2018-04-12 17:06:10 +03:00
Svetk0
e0516663aa Create calibratePID 2018-04-12 17:05:45 +03:00
Svetk0
d737d91bc2 Update setup.md 2018-04-12 16:57:43 +03:00
Svetk0
1b10d59188 Add files via upload 2018-04-12 16:57:01 +03:00
Svetk0
a9ca13c55d Update setup.md 2018-04-12 16:34:45 +03:00
Svetk0
57fbe9cc09 Update setup.md 2018-04-12 14:57:35 +03:00
Svetk0
061b225690 Update setup.md 2018-04-12 14:55:20 +03:00
Svetk0
27189d559a Update setup.md 2018-04-12 12:52:56 +03:00
Oleg Kalachev
d9e0c94797 mavros.launch: change imu frame_id to fcu 2018-04-07 02:12:21 +03:00
Oleg Kalachev
e2e719a12e Merge branch 'master' of github.com:CopterExpress/clever 2018-04-06 22:44:56 +03:00
Oleg Kalachev
52ec97f11f mavros.launch: respawn argument 2018-04-06 22:43:28 +03:00
Arthur Golubtsov
d094386c4d Made some corrections 2018-04-06 18:57:26 +03:00
Arthur Golubtsov
515777bd96 Added pexample how to run program with remote control 2018-04-05 03:31:30 +03:00
Arthur Golubtsov
d56d0dfaaf Corrected picture names and minor changed the article 2018-04-04 21:58:32 +03:00
Svetk0
60b22d0df8 Create safety_assem.md 2018-03-28 12:45:55 +03:00
Svetk0
0072bf8330 Update SUMMARY.md 2018-03-28 12:45:49 +03:00
Svetk0
f36b4546a9 Create mount_antenna.md 2018-03-28 12:43:50 +03:00
Svetk0
c0a97fd263 Update SUMMARY.md 2018-03-28 12:42:22 +03:00
Svetk0
46932e4adf Rename mount_battcase.md to mount_batterycase.md 2018-03-28 12:41:55 +03:00
Svetk0
0c2675ec28 Update and rename mount_batterycase.md to prepare_batterycase.md 2018-03-28 12:40:22 +03:00
Svetk0
f4e5d7978a Update SUMMARY.md 2018-03-28 12:39:43 +03:00
Svetk0
cc7ba566c5 Create mount_battcase.md 2018-03-28 12:39:37 +03:00
Svetk0
d47e3f6bbf Create mount_frame.md 2018-03-28 12:37:56 +03:00
Svetk0
2335c74b55 Create mount_esc.md 2018-03-28 12:34:01 +03:00
Svetk0
ca4bab7bf8 Create mount_pixhawk.md 2018-03-28 12:32:56 +03:00
Svetk0
d4d84ea422 Update SUMMARY.md 2018-03-28 12:31:26 +03:00
Svetk0
f985e07be4 Create mount_receiver.md 2018-03-28 12:28:52 +03:00
Svetk0
bab62cf374 Update SUMMARY.md 2018-03-28 12:24:42 +03:00
Svetk0
4eb988c34d Create test_motors.md 2018-03-28 12:24:37 +03:00
Svetk0
3006d7e32e Create binding.md 2018-03-28 12:23:06 +03:00
Svetk0
3e9b7426bf Create soldering_power.md 2018-03-28 12:21:03 +03:00
Svetk0
e8f93782e0 Create mount_elements.md 2018-03-28 12:19:32 +03:00
Oleg Kalachev
839a8b4102 Fix link in readme 2018-03-28 03:54:36 +03:00
Oleg Kalachev
89a1b81ea2 docs: fix lessons file names 2018-03-27 19:49:52 +03:00
Oleg Kalachev
6306af3c4a Merge pull request #31 from Yuliya1404/master
Changed the numbers of lessons (#1)
2018-03-27 19:08:28 +03:00
Svetk0
910b24c460 Update SUMMARY.md 2018-03-27 17:55:22 +03:00
Svetk0
5dc580c76b Create mount_batterycase.md 2018-03-27 17:55:12 +03:00
Svetk0
c0705222f5 Create mount_connector.md 2018-03-27 17:54:06 +03:00
Svetk0
b51e8add55 Create mount_pdb.md 2018-03-27 17:53:24 +03:00
Yuliya1404
873785bb53 Changed the numbers of lessons (#1)
* Rename les1.md to lesson1.md

* Update lesson1.md

* Rename les2.md to lesson2.md

* Update and rename les4.md to lesson3.md

* Update and rename les7.md to lesson4.md

* Update and rename les8.md to lesson5.md

* Update and rename les11.md to lesson6.md

* Update and rename lesson6.md to lesson7.md

* Update and rename lesson5.md to lesson6.md

* Update and rename les9.md to lesson5.md

* Update and rename les13.md to lesson8.md

* Update and rename les15.md to lesson9.md

* Update and rename les16.md to lesson10.md
2018-03-27 17:48:55 +03:00
Svetk0
86211df4b3 Create kit.md 2018-03-27 17:18:19 +03:00
Svetk0
5ef5c6b641 Create mount_motors.md 2018-03-27 17:16:53 +03:00
Svetk0
5b96253146 Update SUMMARY.md 2018-03-27 17:14:30 +03:00
Svetk0
54111504ac Update SUMMARY.md 2018-03-27 17:05:53 +03:00
Oleg Kalachev
bc2a2895e0 docs: rename LED article filename 2018-03-27 02:15:07 +03:00
Oleg Kalachev
80833486cd Merge branch 'master' of github.com:CopterExpress/clever 2018-03-27 02:13:11 +03:00
Oleg Kalachev
e92c59bf25 docs: add info about inline aruco generator 2018-03-27 02:13:00 +03:00
goldarte
d511b2f65c Updates docs/rabota-so-svetodiodnoi-lentoi.md
Auto commit by GitBook Editor
2018-03-26 07:38:46 +00:00
Oleg Kalachev
921785c29d image: vim settings 2018-03-25 20:18:07 +03:00
Oleg Kalachev
1db42fd268 image: add tcpdump 2018-03-25 20:15:10 +03:00
Oleg Kalachev
6313cc8135 image: add libpoco 2018-03-25 19:54:30 +03:00
Oleg Kalachev
7abf7de71b docs: add info about yaw=nan 2018-03-23 15:55:04 +03:00
Oleg Kalachev
c5628cecc0 aruco_pose: publish debug image even where there is no board 2018-03-22 23:33:50 +03:00
Oleg Kalachev
5212d3bfe5 simple_offboard: PEP-8 + fixes 2018-03-19 23:27:44 +03:00
Oleg Kalachev
bed317a05b simple_offboard: warn no local position in /navigate 2018-03-19 23:06:40 +03:00
Oleg Kalachev
7644e29f71 docs: small fixes 2018-03-19 22:14:03 +03:00
Oleg Kalachev
3245d5fcf5 docs: fix example 2018-03-19 21:33:54 +03:00
Oleg Kalachev
9dbce4d08b docs: link to the reference of the old simple_offboard version 2018-03-19 21:25:29 +03:00
Oleg Kalachev
84a046ce82 gitbook: simple_offboard documentation improvements 2018-03-19 21:11:50 +03:00
Oleg Kalachev
d5c5a8723a Merge branch 'master' into simple-offboard-refactored 2018-03-19 20:45:20 +03:00
Oleg Kalachev
67051b21a0 Merge branch 'master' of github.com:CopterExpress/clever 2018-03-19 17:38:17 +03:00
Oleg Kalachev
f646f003c1 Update Clever 3 image 2018-03-19 17:37:55 +03:00
Andrei Korigodski
ad1a3925ff README: fix style 2018-03-19 15:13:44 +03:00
Oleg Kalachev
5ae686ac5f Clever 3 image 2018-03-19 14:47:13 +03:00
Oleg Kalachev
6a1429c2eb Fix readme 2018-03-19 14:37:08 +03:00
Oleg Kalachev
4645c0bc13 gitbook: transfer assets folder to /docs 2018-03-19 14:34:29 +03:00
Oleg Kalachev
51e5fa3b03 gitbook: fixing 2018-03-19 14:21:31 +03:00
Oleg Kalachev
c3ff38a310 gitbook: fix intro name 2018-03-19 14:18:16 +03:00
Oleg Kalachev
a547aacfa9 Transfer gitbook documentation to docs/ 2018-03-19 14:15:49 +03:00
Oleg Kalachev
06fc6ceeb6 Link to github 2018-03-19 14:04:34 +03:00
Oleg Kalachev
e8c3153ff5 Fix gitbook 2018-03-19 14:01:35 +03:00
Oleg Kalachev
84ac98cfe1 Merge pull request #28 from CopterExpress/english-readme
README: translate to English
2018-03-19 13:49:15 +03:00
Oleg Kalachev
9579342e95 Restore Russian intro 2018-03-19 13:48:35 +03:00
Andrei Korigodski
04ed4996e7 README: translate to English 2018-03-18 19:22:22 +03:00
Oleg Kalachev
f22b4cd39a docs: fix 2018-03-17 20:46:28 +03:00
Oleg Kalachev
4d2ea5478d Update docs 2018-03-15 21:56:03 +03:00
Oleg Kalachev
8ca722165a Add udp-b documentation 2018-03-15 21:53:41 +03:00
Oleg Kalachev
88a14a753e Add udp-b gcs type 2018-03-15 21:50:49 +03:00
urpylka
01bc387134 Fix: syntax
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-15 20:13:38 +03:00
urpylka
c692f4d393 Fix: 'echo -e' to 'echo' for execute in /bin/sh
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-15 19:09:23 +03:00
urpylka
fe9df2c34f Fix: syntax
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-15 19:09:14 +03:00
urpylka
a1968467de Add: zip & unzip to install
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-10 18:03:49 +04:00
urpylka
875698c926 Remove: assimp from install
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-10 18:03:33 +04:00
urpylka
f035d37243 Add: set -e
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-10 18:02:59 +04:00
urpylka
3f7dec4d79 Fix: change bash to sh
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-10 18:02:05 +04:00
urpylka
3d59c78ad8 Add: environment variables for sh scripts
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-10 17:59:15 +04:00
urpylka
d6b664e2f6 Add: united Jenkinsfile-release with image-config.sh functions
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-09 17:47:59 +04:00
urpylka
a387783287 Add: new structure of jobs Jenkins CI
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-09 17:47:59 +04:00
urpylka
a2d610133a Add: debug message of seven arg
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-09 17:47:59 +04:00
urpylka
62fb15e58f Add: debug message after uploads
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-09 17:47:59 +04:00
urpylka
05c22bb839 Fix: replace $JENKINS_HOME to $BUILD_DIRECTORY
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-09 17:47:59 +04:00
urpylka
08eae11f25 Fix: replace single quotes to double quotes
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-09 17:47:59 +04:00
urpylka
fb90bc8c1f Fix: remove duplicated agent
Signed-off-by: urpylka <urpylka@gmail.com>
2018-03-09 17:47:59 +04:00
urpylka
0c275dce98 Fix: change BUID to BUILD 2018-03-09 16:31:46 +04:00
Oleg Kalachev
97b8eb435a simple_offboard: refactor api, remove */yaw_rate services 2018-03-09 02:28:52 +03:00
goldarte
7ebc57b659 Updates docs/rabota-so-svetodiodnoi-lentoi.md
Auto commit by GitBook Editor
2018-03-06 20:54:13 +00:00
goldarte
2036e7e3ec Updates docs/rabota-so-svetodiodnoi-lentoi.md
Auto commit by GitBook Editor
2018-03-06 20:48:53 +00:00
Oleg Kalachev
bf054ef9f5 docs: comma 2018-03-06 04:05:07 +03:00
Oleg Kalachev
26e67edafe docs: small addition 2018-03-06 04:03:49 +03:00
Oleg Kalachev
5ab31f5133 gitbook: versions plugin added 2018-03-06 03:34:03 +03:00
Oleg Kalachev
2ec6930099 aruco_pose: undocumented possibility to set custom markers board
parameters:
~type=custom
~markers
2018-03-06 02:40:35 +03:00
Oleg Kalachev
4aa8f3f5dc docs fixes 2018-03-06 01:06:55 +03:00
Oleg Kalachev
2506c8420f simple_offboard: /navigate_global service 2018-03-06 01:01:59 +03:00
Oleg Kalachev
90a04c04d2 aruco_vpe/reset_timeout parameter added 2018-03-05 22:59:04 +03:00
Oleg Kalachev
48c800fd5a Fixes 2018-03-05 22:27:08 +03:00
Oleg Kalachev
dafce44c0a simple_offboard: /land service added (set copter’s mode to AUTO.LAND) 2018-03-05 22:24:56 +03:00
Oleg Kalachev
a70885ad18 Small fix 2018-03-05 22:04:18 +03:00
Oleg Kalachev
b5110d9df3 simple_offboard: rospy.sleep to some while’s added 2018-03-05 21:58:48 +03:00
Oleg Kalachev
1391ffa2a5 simple_offboard/local_frame parameter for configuring local origin frame name 2018-03-05 21:54:19 +03:00
Oleg Kalachev
ce8b52f684 Merge branch 'master' of github.com:CopterExpress/clever 2018-03-05 21:43:54 +03:00
Oleg Kalachev
0256deef66 Experimental simple_offboard/navigate_after_armed parameter
If this parameter is on, /navigate service waits until copter is armed, before starts to move the position setpoint
2018-03-05 21:42:48 +03:00
Oleg Kalachev
f05a47d636 Merge pull request #25 from CopterExpress/add-license-1
Create LICENSE.md
2018-03-03 14:13:47 +03:00
Oleg Kalachev
db4d84e1c0 Create LICENSE.md 2018-03-03 14:11:49 +03:00
Arthur Golubtsov
adfde391ab Merge 512b4c2e09 into master 2018-02-27 22:25:52 +03:00
goldarte
512b4c2e09 Updates docs/aruco.md
Auto commit by GitBook Editor
2018-02-27 19:34:50 +00:00
Arthur Golubtsov
e56143c508 Upload param file for Clever 2 with LPE 2018-02-27 22:25:52 +03:00
Arthur Golubtsov
f9aa441ce8 Upload param file for Clever 3 with LPE
for 1.7.0 firmware with LPE
2018-02-27 22:17:46 +03:00
Smirnov Artem
37e0185d25 Fix: Delete empty file 2018-02-27 19:04:03 +03:00
Smirnov Artem
29070efc06 Fix: Syntax 2018-02-27 19:02:39 +03:00
Oleg Kalachev
3ddd37b843 Updates docs/arduino.md
Auto commit by GitBook Editor
2018-02-27 16:55:00 +03:00
Oleg Kalachev
409b603530 Updates docs/arduino.md
Auto commit by GitBook Editor
2018-02-27 12:38:28 +03:00
Oleg Kalachev
0458de2fb0 Updates docs/arduino.md
Auto commit by GitBook Editor
2018-02-26 16:58:14 +03:00
Oleg Kalachev
7c74ce3212 Updates docs/arduino.md
Auto commit by GitBook Editor
2018-02-26 16:52:06 +03:00
Oleg Kalachev
624162a3ec Conflict resolution 2018-02-26 15:33:13 +03:00
Oleg Kalachev
612b222887 Updates docs/arduino.md
Auto commit by GitBook Editor
2018-02-26 15:32:15 +03:00
Oleg Kalachev
d4efa58388 Merge branch 'master' of github.com:CopterExpress/clever 2018-02-22 02:45:17 +03:00
Oleg Kalachev
04ba342542 Add disqus comments for gitbook 2018-02-22 02:45:03 +03:00
Oleg Kalachev
3105ce109c Track 4 files into repository.
- untracked assets/timing_with_thumbs.png
- untracked docs/rabota-so-svetodiodnoi-lentoi.md
- untracked drugoe.md
- modified SUMMARY.md

Auto commit by GitBook Editor
2018-02-22 02:42:33 +03:00
Oleg Kalachev
757b829a17 Updates book.json
Auto commit by GitBook Editor
2018-02-22 02:41:37 +03:00
goldarte
ea16ef847e Updates docs/rabota-so-svetodiodnoi-lentoi.md
Auto commit by GitBook Editor
2018-02-21 23:33:37 +00:00
goldarte
294ccfe3f9 Creates assets/timing_with_thumbs.png
Auto commit by GitBook Editor
2018-02-21 23:01:36 +00:00
Oleg Kalachev
6ef5298b8b Updates docs/aruco.md
Auto commit by GitBook Editor
2018-02-22 01:48:28 +03:00
Oleg Kalachev
d31b41ed9e Updates docs/aruco.md
Auto commit by GitBook Editor
2018-02-22 01:48:07 +03:00
Oleg Kalachev
2100ca222c Updates docs/aruco.md
Auto commit by GitBook Editor
2018-02-22 01:46:41 +03:00
Oleg Kalachev
2dcb929089 Merge branch 'master' of github.com:CopterExpress/clever 2018-02-21 22:48:07 +03:00
Oleg Kalachev
7a95cbdf62 Track 3 files into repository.
- modified apps/ios/cleverrc/telemetry.js
- modified clever/launch/clever.launch
- modified clever/src/rc.cpp

Auto commit by GitBook Editor
2018-02-21 22:47:52 +03:00
Oleg Kalachev
1ab251af6a Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 22:12:23 +03:00
Oleg Kalachev
d1c5e847da mobile rc: add DROPPED to notifications blacklist 2018-02-21 21:48:52 +03:00
Oleg Kalachev
dc501bb2e6 Merge branch 'master' of github.com:CopterExpress/clever 2018-02-21 21:43:26 +03:00
Oleg Kalachev
e3e722a972 rc argument in clever.launch 2018-02-21 21:40:59 +03:00
Oleg Kalachev
f7b47afae7 mobile rc: publish initial /state_latched 2018-02-21 21:40:40 +03:00
Oleg Kalachev
74d1eeca24 mobile rc: blacklist for /rosout messages 2018-02-21 21:40:25 +03:00
Oleg Kalachev
fa8f5ba41e Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:33:03 +03:00
Oleg Kalachev
1ee279bc5a Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:32:37 +03:00
Oleg Kalachev
d724f93e36 Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:32:31 +03:00
Oleg Kalachev
96783c1ee2 Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:32:12 +03:00
Oleg Kalachev
db5c6d0865 Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:31:56 +03:00
Oleg Kalachev
5f6df5569e Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:30:19 +03:00
Oleg Kalachev
661a121d6f Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:29:46 +03:00
Oleg Kalachev
25856e4675 Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:29:34 +03:00
Oleg Kalachev
cedf3f8364 Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:22:14 +03:00
Oleg Kalachev
0a66d3f3e3 Updates docs/rc.md
Auto commit by GitBook Editor
2018-02-21 21:14:04 +03:00
Oleg Kalachev
10251c3c43 Set udp interface for iOS rc 2018-02-21 00:33:17 +03:00
Oleg Kalachev
3cd9973fc1 Fixes for RC 2018-02-20 23:38:32 +03:00
Oleg Kalachev
2c68dd1a31 Merge branch 'master' of github.com:CopterExpress/clever 2018-02-20 04:11:22 +03:00
Oleg Kalachev
34cfb3548a Mode "UNKNOWN" in /state_latched, when state is timed out 2018-02-20 04:11:12 +03:00
Oleg Kalachev
fc3e98bdc6 Updates docs/snippets.md
Auto commit by GitBook Editor
2018-02-19 22:26:49 +03:00
Oleg Kalachev
bb6226f420 Updates docs/snippets.md
Auto commit by GitBook Editor
2018-02-19 22:24:27 +03:00
Oleg Kalachev
79c4d0d128 Merge branch 'master' of github.com:CopterExpress/clever 2018-02-19 22:22:41 +03:00
Oleg Kalachev
571c12061e Track 411 files into repository.
- untracked .gitattributes
- untracked .gitignore
- untracked apps/ios/.gitignore
- untracked apps/ios/cleverrc.xcodeproj/project.pbxproj
- untracked apps/ios/cleverrc.xcodeproj/project.xcworkspace/contents.xcworkspacedata
- untracked apps/ios/cleverrc.xcworkspace/contents.xcworkspacedata
- untracked apps/ios/cleverrc/AppDelegate.swift
- untracked apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/cleverios180-1.png
- untracked apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/cleverios180.png
- untracked apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Contents.json
- untracked apps/ios/cleverrc/Assets.xcassets/Contents.json
- untracked apps/ios/cleverrc/Assets.xcassets/Image.imageset/Contents.json
- untracked apps/ios/cleverrc/Base.lproj/LaunchScreen.storyboard
- untracked apps/ios/cleverrc/Base.lproj/Main.storyboard
- untracked apps/ios/cleverrc/BinUtils.swift
- untracked apps/ios/cleverrc/clever.svg
- untracked apps/ios/cleverrc/index.html
- untracked apps/ios/cleverrc/Info.plist
- untracked apps/ios/cleverrc/main.css
- untracked apps/ios/cleverrc/main.js
- untracked apps/ios/cleverrc/README.md
- untracked apps/ios/cleverrc/roslib.js
- untracked apps/ios/cleverrc/telemetry.js
- untracked apps/ios/cleverrc/ViewController.swift
- untracked apps/ios/Podfile
- untracked apps/ios/Podfile.lock
- untracked apps/ios/README.md
- untracked aruco_pose/CMakeLists.txt
- untracked aruco_pose/nodelet_plugins.xml
- untracked aruco_pose/package.xml
- untracked aruco_pose/src/aruco_pose.cpp
- untracked aruco_pose/src/fix.cpp
- untracked assets/11_1.png
- untracked assets/11_2.png
- untracked assets/11_3.png
- untracked assets/11_4.png
- untracked assets/11_5.png
- untracked assets/13_1.png
- untracked assets/13_10.png
- untracked assets/13_11.png
- untracked assets/13_2.png
- untracked assets/13_3.jpg
- untracked assets/13_4.png
- untracked assets/13_5.png
- untracked assets/13_6.png
- untracked assets/13_7.png
- untracked assets/13_8.png
- untracked assets/13_9.png
- untracked assets/15_1.png
- untracked assets/15_2.png
- untracked assets/15_3.png
- untracked assets/15_4.png
- untracked assets/15_5.png
- untracked assets/15_6.png
- untracked assets/15_7.png
- untracked assets/16_1.png
- untracked assets/16_2.png
- untracked assets/16_3.png
- untracked assets/16_4.png
- untracked assets/1_1.png
- untracked assets/1_10.png
- untracked assets/1_11.png
- untracked assets/1_12.png
- untracked assets/1_13.png
- untracked assets/1_2.png
- untracked assets/1_3.png
- untracked assets/1_4.png
- untracked assets/1_5.png
- untracked assets/1_6.png
- untracked assets/1_7.png
- untracked assets/1_8.png
- untracked assets/1_9.png
- untracked assets/2_1.png
- untracked assets/2_2.png
- untracked assets/2_3.png
- untracked assets/2_4.png
- untracked assets/2_5.png
- untracked assets/2_6.png
- untracked assets/2_7.png
- untracked assets/2_8.png
- untracked assets/2_9.png
- untracked assets/4_1.png
- untracked assets/4_2.png
- untracked assets/4_3.png
- untracked assets/4_4.png
- untracked assets/4_5.png
- untracked assets/4_6.png
- untracked assets/7_1.png
- untracked assets/7_2.png
- untracked assets/7_3.png
- untracked assets/7_4.png
- untracked assets/8_1.png
- untracked assets/8_2.png
- untracked assets/8_3.png
- untracked assets/8_4.png
- untracked assets/8_5.png
- untracked assets/8_6.png
- untracked assets/9_1.png
- untracked assets/9_2.png
- untracked assets/addEqipment.jpg
- untracked assets/airframeSetup.jpg
- untracked assets/allElements.png
- untracked assets/attentionSave.jpg
- untracked assets/brrc2205.png
- untracked assets/brrc2205on.png
- untracked assets/brrc2205ondeck.png
- untracked assets/calibrateaxcel.jpg
- untracked assets/calibrateaxcelstart.jpg
- untracked assets/calibratecompass.jpg
- untracked assets/calibrateESC.jpg
- untracked assets/calibrategyro.jpg
- untracked assets/calibratePIDparams.jpg
- untracked assets/calibrateView.jpg
- untracked assets/calibrateViewStart.jpg
- untracked assets/casebattery.png
- untracked assets/chooseSwitch.jpg
- untracked assets/Clever main.png
- untracked assets/clever.jpg
- untracked assets/Clevermain.png
- untracked assets/connectBattery.png
- untracked assets/connectingRadio.png
- untracked assets/connectionESCtoReceiver.png
- untracked assets/connectionLost.jpg
- untracked assets/connectionOK.jpg
- untracked assets/connectionPixhawk.png
- untracked assets/consistofTransmitter.jpg
- untracked assets/cutwire14AWG.jpg
- untracked assets/escDYSzap.png
- untracked assets/escWires.png
- untracked assets/explosion.png
- untracked assets/firmwarePX4.jpg
- untracked assets/flightModes.jpg
- untracked assets/helphand.jpg
- untracked assets/holderLegs.png
- untracked assets/isoViewmountHolder.png
- untracked assets/jumper.png
- untracked assets/keep.png
- untracked assets/lockradio.jpg
- untracked assets/lockradio.png
- untracked assets/lowsafeDeck.png
- untracked assets/mainWindow.jpg
- untracked assets/motorsTopview.png
- untracked assets/mount5vconnector.png
- untracked assets/mountAntenna.png
- untracked assets/mountBeams.png
- untracked assets/mountBottomDeck.png
- untracked assets/mountHolder.png
- untracked assets/mountPDB.png
- untracked assets/mountReceiverDeck.png
- untracked assets/mountReceiverStud.png
- untracked assets/mountxt60pinsocket.png
- untracked assets/notmoveslider.jpg
- untracked assets/pixhawk.png
- untracked assets/radioTransmitter.png
- untracked assets/readyBatteryholder.png
- untracked assets/receiver5V.png
- untracked assets/receiverPPM.png
- untracked assets/resolderingESC.png
- untracked assets/safehighRadial.png
- untracked assets/safeLegs.png
- untracked assets/safelowRadial.png
- untracked assets/safetybyassem.png
- untracked assets/safetyINflight.png
- untracked assets/safetyPower.png
- untracked assets/safetyPreflight.png
- untracked assets/soldering5VTOpdb.png
- untracked assets/solderingBrrc2205ondeckTOescDYSzap.png
- untracked assets/solderingPowerwires.png
- untracked assets/solderingxt60socketTOpdb.png
- untracked assets/stand.jpg
- untracked assets/startPDBtest.jpg
- untracked assets/testMotors.png
- untracked assets/topESCcaseview.png
- untracked assets/topPreview.png
- untracked assets/topviewmountPDB.png
- untracked assets/topviewpixhawk.png
- untracked assets/turnoffSafetyswitch.jpg
- untracked assets/xt60pinsocket.jpg
- untracked assets/zap.jpg
- untracked assets/zapPDBtest.jpg
- untracked clever/camera_info/fisheye_cam_320.yaml
- untracked clever/camera_info/fisheye_cam_640.yaml
- untracked clever/CMakeLists.txt
- untracked clever/launch/arduino.launch
- untracked clever/launch/aruco.launch
- untracked clever/launch/clever.launch
- untracked clever/launch/copter_visualization.launch
- untracked clever/launch/fpv_camera.launch
- untracked clever/launch/main_camera.launch
- untracked clever/launch/mavros.launch
- untracked clever/launch/sitl.launch
- untracked clever/launch/web_server.launch
- untracked clever/nodelet_plugins.xml
- untracked clever/package.xml
- untracked clever/requirements.txt
- untracked clever/src/aruco_vpe.cpp
- untracked clever/src/fcu_horiz.cpp
- untracked clever/src/fpv_camera
- untracked clever/src/global_local.py
- untracked clever/src/rc.cpp
- untracked clever/src/simple_offboard.py
- untracked clever/src/util.h
- untracked clever/src/util.py
- untracked clever/src/web_server.py
- untracked clever/srv/GetTelemetry.srv
- untracked clever/srv/Navigate.srv
- untracked clever/srv/SetAttitude.srv
- untracked clever/srv/SetAttitudeYawRate.srv
- untracked clever/srv/SetPosition.srv
- untracked clever/srv/SetPositionGlobal.srv
- untracked clever/srv/SetPositionGlobalYawRate.srv
- untracked clever/srv/SetPositionYawRate.srv
- untracked clever/srv/SetRates.srv
- untracked clever/srv/SetRatesYaw.srv
- untracked clever/srv/SetVelocity.srv
- untracked clever/srv/SetVelocityYawRate.srv
- untracked deploy/clever.service
- untracked deploy/clever_arudino.tar.gz
- untracked deploy/generate_ros_lib
- untracked deploy/roscore.env
- untracked deploy/roscore.service
- modified docs/3g.md
- modified docs/assemble.md
- untracked docs/deck.md
- modified docs/etcher.md
- modified docs/frames.md
- modified docs/les1.md
- modified docs/les11.md
- modified docs/les13.md
- modified docs/les15.md
- modified docs/les16.md
- modified docs/les2.md
- modified docs/les4.md
- modified docs/les7.md
- modified docs/les8.md
- modified docs/les9.md
- modified docs/modes.md
- untracked docs/powerConnection.md
- modified docs/radioerrors.md
- modified docs/radioerrors1.md
- modified docs/safety.md
- modified docs/setup.md
- modified docs/simple_offboard.md
- modified docs/tb.md
- untracked docs/testConnection.md
- modified docs/wifi.md
- untracked docs/zap.md
- removed gpsmd.md
- untracked image/apps.sh
- untracked image/git_release.py
- untracked image/iface.sh
- untracked image/image-config.sh
- untracked image/Jenkinsfile
- untracked image/ros.sh
- untracked image/yadisk.py
- removed img/11_1.png
- removed img/11_2.png
- removed img/11_3.png
- removed img/11_4.png
- removed img/11_5.png
- removed img/13_1.png
- removed img/13_10.png
- removed img/13_11.png
- removed img/13_2.png
- removed img/13_3.jpg
- removed img/13_4.png
- removed img/13_5.png
- removed img/13_6.png
- removed img/13_7.png
- removed img/13_8.png
- removed img/13_9.png
- removed img/15_1.png
- removed img/15_2.png
- removed img/15_3.png
- removed img/15_4.png
- removed img/15_5.png
- removed img/15_6.png
- removed img/15_7.png
- removed img/16_1.png
- removed img/16_2.png
- removed img/16_3.png
- removed img/16_4.png
- removed img/1_1.png
- removed img/1_10.png
- removed img/1_11.png
- removed img/1_12.png
- removed img/1_13.png
- removed img/1_2.png
- removed img/1_3.png
- removed img/1_4.png
- removed img/1_5.png
- removed img/1_6.png
- removed img/1_7.png
- removed img/1_8.png
- removed img/1_9.png
- removed img/2_1.png
- removed img/2_2.png
- removed img/2_3.png
- removed img/2_4.png
- removed img/2_5.png
- removed img/2_6.png
- removed img/2_7.png
- removed img/2_8.png
- removed img/2_9.png
- removed img/4_1.png
- removed img/4_2.png
- removed img/4_3.png
- removed img/4_4.png
- removed img/4_5.png
- removed img/4_6.png
- removed img/7_1.png
- removed img/7_2.png
- removed img/7_3.png
- removed img/7_4.png
- removed img/8_1.png
- removed img/8_2.png
- removed img/8_3.png
- removed img/8_4.png
- removed img/8_5.png
- removed img/8_6.png
- removed img/9_1.png
- removed img/9_2.png
- removed img/addEqipment.jpg
- removed img/airframeSetup.jpg
- removed img/allElements.png
- removed img/attentionSave.jpg
- removed img/brrc2205.png
- removed img/brrc2205on.png
- removed img/brrc2205ondeck.png
- removed img/calibrateaxcel.jpg
- removed img/calibrateaxcelstart.jpg
- removed img/calibratecompass.jpg
- removed img/calibrateESC.jpg
- removed img/calibrategyro.jpg
- removed img/calibratePIDparams.jpg
- removed img/calibrateView.jpg
- removed img/calibrateViewStart.jpg
- removed img/casebattery.png
- removed img/chooseSwitch.jpg
- removed img/Clever main.png
- removed img/clever.jpg
- removed img/Clevermain.png
- removed img/connectBattery.png
- removed img/connectingRadio.png
- removed img/connectionESCtoReceiver.png
- removed img/connectionLost.jpg
- removed img/connectionOK.jpg
- removed img/connectionPixhawk.png
- removed img/consistofTransmitter.jpg
- removed img/cutwire14AWG.jpg
- removed img/escDYSzap.png
- removed img/escWires.png
- removed img/explosion.png
- removed img/firmwarePX4.jpg
- removed img/flightModes.jpg
- removed img/helphand.jpg
- removed img/holderLegs.png
- removed img/isoViewmountHolder.png
- removed img/jumper.png
- removed img/keep.png
- removed img/lockradio.jpg
- removed img/lockradio.png
- removed img/lowsafeDeck.png
- removed img/mainWindow.jpg
- removed img/motorsTopview.png
- removed img/mount5vconnector.png
- removed img/mountAntenna.png
- removed img/mountBeams.png
- removed img/mountBottomDeck.png
- removed img/mountHolder.png
- removed img/mountPDB.png
- removed img/mountReceiverDeck.png
- removed img/mountReceiverStud.png
- removed img/mountxt60pinsocket.png
- removed img/notmoveslider.jpg
- removed img/pixhawk.png
- removed img/radioTransmitter.png
- removed img/readyBatteryholder.png
- removed img/receiver5V.png
- removed img/receiverPPM.png
- removed img/resolderingESC.png
- removed img/safehighRadial.png
- removed img/safeLegs.png
- removed img/safelowRadial.png
- removed img/safetybyassem.png
- removed img/safetyINflight.png
- removed img/safetyPower.png
- removed img/safetyPreflight.png
- removed img/soldering5VTOpdb.png
- removed img/solderingBrrc2205ondeckTOescDYSzap.png
- removed img/solderingPowerwires.png
- removed img/solderingxt60socketTOpdb.png
- removed img/stand.jpg
- removed img/startPDBtest.jpg
- removed img/testMotors.png
- removed img/topESCcaseview.png
- removed img/topPreview.png
- removed img/topviewmountPDB.png
- removed img/topviewpixhawk.png
- removed img/turnoffSafetyswitch.jpg
- removed img/xt60pinsocket.jpg
- removed img/zap.jpg
- removed img/zapPDBtest.jpg
- removed notes/deck.md
- removed notes/powerConnection.md
- removed notes/testConnection.md
- removed notes/zap.md
- removed primeri-programm.md
- modified README.md
- removed sborka.md
- removed sitl.md

Auto commit by GitBook Editor
2018-02-19 22:22:08 +03:00
Oleg Kalachev
786dd72b82 Updates SUMMARY.md
Auto commit by GitBook Editor
2018-02-19 22:21:26 +03:00
Oleg Kalachev
e53d318e22 Updates docs/snippets.md
Auto commit by GitBook Editor
2018-02-19 22:21:04 +03:00
Oleg Kalachev
2d0e06f22c Move .gitattributes file to the root 2018-02-19 15:47:31 +03:00
Oleg Kalachev
f544c32d6d Mark vendored files 2018-02-19 15:17:43 +03:00
Oleg Kalachev
c56b1040d4 Remove static submodule 2018-02-19 07:01:46 +03:00
Oleg Kalachev
51e4cbef32 Remove submodules 2018-02-19 07:00:57 +03:00
Oleg Kalachev
8a60e4e467 Merge branch 'master' of github.com:CopterExpress/clever 2018-02-19 06:46:16 +03:00
Oleg Kalachev
bb792206cc Add readme-file for ios-app 2018-02-19 06:45:45 +03:00
Oleg Kalachev
6448e6b928 Add readme-file for ios-app 2018-02-19 06:44:53 +03:00
Oleg Kalachev
7b7d53c97a Merge branch 'master' of github.com:CopterExpress/clever 2018-02-19 06:38:29 +03:00
Oleg Kalachev
431b97a011 Add mobile remote control for iOS 2018-02-19 06:38:24 +03:00
Oleg Kalachev
5ccf4fac48 Update README.md 2018-02-19 05:17:38 +03:00
Oleg Kalachev
ba21ed7cf9 Update README.md 2018-02-19 05:15:48 +03:00
Oleg Kalachev
1db6453fd2 Update simple_offboard.md 2018-02-19 01:19:54 +03:00
Oleg Kalachev
713b2fef0d Updates docs/simple_offboard.md
Auto commit by GitBook Editor
2018-02-19 01:18:27 +03:00
Oleg Kalachev
05aa5cc8c1 Add vim to apps 2018-02-19 01:10:17 +03:00
yuliya1404
9e5eec4e3b Updates docs/simple_offboard.md
Auto commit by GitBook Editor
2018-02-18 17:53:48 +00:00
338 changed files with 11299 additions and 1753 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
apps/ios/cleverrc/roslib.js linguist-vendored
apps/ios/cleverrc/BinUtils.swift linguist-vendored

4
.gitmodules vendored
View File

@@ -1,4 +0,0 @@
[submodule "clever/static"]
path = clever/static
url = https://github.com/CopterExpress/clever-rc.git
branch = build

21
LICENSE.md Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Copter Express
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,62 +1,68 @@
Клевер
======
# CLEVER
<img src="assets/clever.jpg" align="right" width="300px" alt="Клевер">
<img src="docs/assets/clever3.png" align="right" width="300px" alt="CLEVER drone">
«Клевер» — это учебный конструктор программируемого квадрокоптера, состоящего из популярных открытых компонентов, а также набор необходимой документации и библиотек для работы с ним.
CLEVER is an educational programmable drone kit consisting of an unassembled quadcopter, open source software and documentation. The kit includes Pixhawk/Pixracer autopilot running PX4 firmware, Raspberry Pi 3 as companion computer, a camera for computer vision navigation as well as additional sensors and peripheral devices.
Набор включает в себя полетный контроллер PixHawk/PixRacer с полетным стеком PX4, Raspberry Pi 3 в качестве управлящего бортового компьютера, модуль камеры для реализации полетов с использованием компьютерного зрения, а также набор различных датчиков и другой периферии.
Copter Express has implemented a large number of different autonomous drone projects using exactly the same platform: [automated pizza delivery](https://www.youtube.com/watch?v=hmkAoZOtF58) in Samara and Kazan, coffee delivery in Skolkovo Innovation Center, [autonomous quadcopter with charging station](https://www.youtube.com/watch?v=RjX6nUqw1mI) for site monitoring and security, winning drones on [Robokross-2016](https://www.youtube.com/watch?v=dGbDaz_VmYU) and [Robokross-2017](https://youtu.be/AQnd2CRczbQ) competitions and many others.
На базе точно такой же платформы были созданы многие «большие» проекты компании Copter Express, например, дроны для [пиар-акций по автономной доставке пиццы](https://www.youtube.com/watch?v=hmkAoZOtF58) (Самара, Казань); дрон-доставщик кофе в Сколково, мониторинговый дрон с зарядной станцией, дроны-победители на полевых испытаниях «[Робокросс-2016](https://www.youtube.com/watch?v=dGbDaz_VmYU)», «[Робокросс-2017](https://youtu.be/AQnd2CRczbQ)» и многие другие.
**The main documentation in Russian is available on our Gitbook:**
**https://copterexpress.gitbooks.io/clever/content/**
Для того, чтобы научиться собирать, настраивать, пилотировать и программировать автономный дрон «Клевер», воспользуйтесь этим учебником.
Use it to learn how to assemble, configure, pilot and program autonomous CLEVER drone.
Основная документация
---------------------
## Preconfigured RPi 3 image
https://copterexpress.gitbooks.io/clever/content/
Preconfigured image for Raspberry Pi 3 with installed and configured software, ready to fly, is available [here](https://copterexpress.gitbooks.io/clever/content/docs/microsd_images.html).
**Готовый образ ОС** для RPi 3 с предустановленным и преднастроенным ПО можно скачать [здесь](https://copterexpress.gitbooks.io/clever/content/docs/microsd_images.html).
Image includes:
[Описание API](https://copterexpress.gitbooks.io/clever/content/docs/simple_offboard.html) для автономных полетов.
* Raspbian Stretch
* ROS Kinetic
* Configured networking
* OpenCV
* mavros
* CLEVER software bundle for autonomous drone control
Ручная установка
---------
API description in Russian for autonomous flights is available [here](https://copterexpress.gitbooks.io/clever/simple_offboard.html).
Склонировать репозиторий в папку `/home/pi/catkin_ws/src/clever` (**важно**):
## Manual installation
Install ROS Kinetic according to the [documentation](http://wiki.ros.org/kinetic/Installation).
Clone repo to directory `/home/pi/catkin_ws/src/clever`:
```bash
cd ~/catkin_ws/src
git clone https://github.com/CopterExpress/clever_bundle.git clever
git clone https://github.com/CopterExpress/clever.git clever
```
Пересобрать ROS-пакеты:
Build ROS packages:
```bash
cd ~/catkin_ws
catkin_make -j1
```
Включить сервис roscore (если он не включен):
Enable systemd service `roscore` (if not enabled):
```bash
sudo systemctl enable /home/pi/catkin_ws/src/clever/deploy/roscore.service
sudo systemctl start roscore
```
Включить сервис clever:
Enable systemd service `clever`:
```bash
sudo systemctl enable /home/pi/catkin_ws/src/clever/deploy/clever.service
sudo systemctl start clever
```
Зависимости
-----------
### Dependencies
[ROS Kinetic](http://wiki.ros.org/kinetic).
Необходимые для работы ROS-пакеты:
Necessary ROS packages:
* `opencv3`
* `mavros`
@@ -65,8 +71,6 @@ sudo systemctl start clever
* `cv_camera`
* `nodelet`
* `dynamic_reconfigure`
* `bondcpp`, ветка `master`
* `bondcpp`, branch `master`
* `roslint`
* `rosserial`
TODO: внести в package.xml

View File

@@ -1,44 +0,0 @@
# Summary
* [Введение](README.md)
* [Сборка](docs/assemble.md)
* [Первоначальная настройка](docs/setup.md)
* [Полетные режимы](docs/modes.md)
* [Raspberry Pi](docs/raspberry.md)
* [Образ операционной системы на RPi](docs/microsd_images.md)
* [Подключение Raspberry Pi к PixHawk](docs/connection.md)
* [Подключение по Wi-Fi](docs/wifi.md)
* [Работа с QGroundControl через Wi-Fi](docs/gcs_bridge.md)
* [SSH-доступ](docs/ssh.md)
* [Неисправности радиоаппаратуры](docs/radioerrors.md)
* [Безопасность](docs/safety.md)
* [Техника безопасности по пайке](docs/tb.md)
* [Просмотр видеострима с камер](docs/web_video_server.md)
* [Работа с ROS](docs/ros.md)
* [MAVROS](docs/mavros.md)
* [Автономный полет в OFFBOARD](docs/simple_offboard.md)
* [Навигация по ArUco-маркерам](docs/aruco.md)
* [Взаимодействие с Arduino](docs/arduino.md)
* [Системы координат](docs/frames.md)
* [Работа с камерой \(компьютерное зрение\)](docs/camera.md)
* [Ориентация камеры](docs/camera_frame.md)
* [Визуализация с помощью rviz](docs/rviz.md)
* [Работа с SITL](docs/sitl.md)
* [Подключение GPS](docs/gps.md)
* [Использование 3G-модема](docs/3g.md)
* [Примеры программ](primeri-programm.md)
* Учебник
* [Урок 1](docs/les1.md)
* [Урок 2](docs/les2.md)
* [Урок 7](docs/les7.md)
* [Урок 8](docs/les8.md)
* [Урок 9](docs/les9.md)
* [Урок 11](docs/les11.md)
* [Урок 13](docs/les13.md)
* [Урок 15](docs/les15.md)
* [Урок 16](docs/les16.md)
* Другое
* [CopterHack-2017](docs/copterhack2017.md)
* [Прошивка ESC контроллеров с помощью Arduino](docs/esc_firmware.md)
* [Полезные ссылки](docs/links.md)

17
apps/ios/.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
# Xcode
.DS_Store
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
!default.xcworkspace
xcuserdata
profile
*.moved-aside
DerivedData
Pods/

14
apps/ios/Podfile Normal file
View File

@@ -0,0 +1,14 @@
project 'cleverrc.xcodeproj/'
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'cleverrc' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for cleverrc
pod 'SwiftSocket', '~> 2.0'
pod 'NotificationBannerSwift'
end

21
apps/ios/Podfile.lock Normal file
View File

@@ -0,0 +1,21 @@
PODS:
- MarqueeLabel/Swift (3.1.4)
- NotificationBannerSwift (1.5.4):
- MarqueeLabel/Swift
- SnapKit (~> 4.0)
- SnapKit (4.0.0)
- SwiftSocket (2.0.2)
DEPENDENCIES:
- NotificationBannerSwift
- SwiftSocket (~> 2.0)
SPEC CHECKSUMS:
MarqueeLabel: bf768455fe88d427f71476ebb23f9092b660f40b
NotificationBannerSwift: 4f6666c8421dcf11be0812dd1093d932c15921af
SnapKit: a42d492c16e80209130a3379f73596c3454b7694
SwiftSocket: 6f4c9c63fbc5c1d61188936bb3c599fd546f40ae
PODFILE CHECKSUM: fd5199f69c3ee8c1fbc0dd582477d890c8b2a24f
COCOAPODS: 1.4.0

10
apps/ios/README.md Normal file
View File

@@ -0,0 +1,10 @@
iOS-приложение для управления Клевером
--------------------------------------
Для установки зависимостей необходим [CocoaPods](https://cocoapods.org):
```bash
pod install
```
Для разработки и сборки откройте в XCode файл `cleverrc.xcworkspace`.

View File

@@ -0,0 +1,446 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
7C0AB7AB202A744400BAED27 /* BinUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C0AB7AA202A744400BAED27 /* BinUtils.swift */; };
7C51654120139237004D1F4D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C51654020139237004D1F4D /* AppDelegate.swift */; };
7C51654320139237004D1F4D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C51654220139237004D1F4D /* ViewController.swift */; };
7C51654620139237004D1F4D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7C51654420139237004D1F4D /* Main.storyboard */; };
7C51654820139237004D1F4D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7C51654720139237004D1F4D /* Assets.xcassets */; };
7C51654B20139237004D1F4D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7C51654920139237004D1F4D /* LaunchScreen.storyboard */; };
7C516553201526BA004D1F4D /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = 7C516552201526BA004D1F4D /* index.html */; };
7C51655520153180004D1F4D /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 7C51655420153180004D1F4D /* main.js */; };
7C7DECC2203CBCC4000C1C51 /* roslib.js in Resources */ = {isa = PBXBuildFile; fileRef = 7C45DCE9203A75A2009C73F5 /* roslib.js */; };
7CA401E22033CE17009FAA3B /* main.css in Resources */ = {isa = PBXBuildFile; fileRef = 7CA401E12033CE17009FAA3B /* main.css */; };
7CA401E42033FA34009FAA3B /* telemetry.js in Resources */ = {isa = PBXBuildFile; fileRef = 7CA401E32033FA34009FAA3B /* telemetry.js */; };
7CA401E6203471D9009FAA3B /* clever.svg in Resources */ = {isa = PBXBuildFile; fileRef = 7CA401E5203471D8009FAA3B /* clever.svg */; };
C25141CAF1A7125F3CE29DDC /* Pods_cleverrc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C38C04523251039FF13DDCD /* Pods_cleverrc.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
5C38C04523251039FF13DDCD /* Pods_cleverrc.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_cleverrc.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7C0AB7AA202A744400BAED27 /* BinUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinUtils.swift; sourceTree = "<group>"; };
7C45DCE9203A75A2009C73F5 /* roslib.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = roslib.js; sourceTree = "<group>"; };
7C51653D20139237004D1F4D /* cleverrc.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = cleverrc.app; sourceTree = BUILT_PRODUCTS_DIR; };
7C51654020139237004D1F4D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7C51654220139237004D1F4D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
7C51654520139237004D1F4D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
7C51654720139237004D1F4D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
7C51654A20139237004D1F4D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
7C51654C20139237004D1F4D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7C516552201526BA004D1F4D /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = "<group>"; };
7C51655420153180004D1F4D /* main.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = main.js; sourceTree = "<group>"; };
7CA401E12033CE17009FAA3B /* main.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = main.css; sourceTree = "<group>"; };
7CA401E32033FA34009FAA3B /* telemetry.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = telemetry.js; sourceTree = "<group>"; };
7CA401E5203471D8009FAA3B /* clever.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = clever.svg; sourceTree = "<group>"; };
AAC9195BF3A9BF6942EF4D0B /* Pods-cleverrc.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-cleverrc.release.xcconfig"; path = "Pods/Target Support Files/Pods-cleverrc/Pods-cleverrc.release.xcconfig"; sourceTree = "<group>"; };
CB200F4B933204EA97E0E2E4 /* Pods-cleverrc.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-cleverrc.debug.xcconfig"; path = "Pods/Target Support Files/Pods-cleverrc/Pods-cleverrc.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
7C51653A20139237004D1F4D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C25141CAF1A7125F3CE29DDC /* Pods_cleverrc.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
4FA3968F2242239E15A656D2 /* Pods */ = {
isa = PBXGroup;
children = (
CB200F4B933204EA97E0E2E4 /* Pods-cleverrc.debug.xcconfig */,
AAC9195BF3A9BF6942EF4D0B /* Pods-cleverrc.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
66C638F0021EBE07741B26F3 /* Frameworks */ = {
isa = PBXGroup;
children = (
5C38C04523251039FF13DDCD /* Pods_cleverrc.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
7C51653420139237004D1F4D = {
isa = PBXGroup;
children = (
66C638F0021EBE07741B26F3 /* Frameworks */,
4FA3968F2242239E15A656D2 /* Pods */,
7C51653E20139237004D1F4D /* Products */,
7C51653F20139237004D1F4D /* cleverrc */,
);
sourceTree = "<group>";
};
7C51653E20139237004D1F4D /* Products */ = {
isa = PBXGroup;
children = (
7C51653D20139237004D1F4D /* cleverrc.app */,
);
name = Products;
sourceTree = "<group>";
};
7C51653F20139237004D1F4D /* cleverrc */ = {
isa = PBXGroup;
children = (
7C45DCE9203A75A2009C73F5 /* roslib.js */,
7C51654020139237004D1F4D /* AppDelegate.swift */,
7C51654720139237004D1F4D /* Assets.xcassets */,
7C0AB7AA202A744400BAED27 /* BinUtils.swift */,
7C51654C20139237004D1F4D /* Info.plist */,
7C51654920139237004D1F4D /* LaunchScreen.storyboard */,
7C51654420139237004D1F4D /* Main.storyboard */,
7C51654220139237004D1F4D /* ViewController.swift */,
7CA401E5203471D8009FAA3B /* clever.svg */,
7C516552201526BA004D1F4D /* index.html */,
7CA401E12033CE17009FAA3B /* main.css */,
7C51655420153180004D1F4D /* main.js */,
7CA401E32033FA34009FAA3B /* telemetry.js */,
);
path = cleverrc;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
7C51653C20139237004D1F4D /* cleverrc */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7C51654F20139237004D1F4D /* Build configuration list for PBXNativeTarget "cleverrc" */;
buildPhases = (
9F096121C4A02BCE9D4FD1B9 /* [CP] Check Pods Manifest.lock */,
7C51653920139237004D1F4D /* Sources */,
7C51653A20139237004D1F4D /* Frameworks */,
7C51653B20139237004D1F4D /* Resources */,
A37DBBAD5E44E632F8A8A204 /* [CP] Embed Pods Frameworks */,
9BAB41D26FC0095C7C86B9DE /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = cleverrc;
productName = cleverrc;
productReference = 7C51653D20139237004D1F4D /* cleverrc.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
7C51653520139237004D1F4D /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0920;
ORGANIZATIONNAME = "Copter Express";
TargetAttributes = {
7C51653C20139237004D1F4D = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 7C51653820139237004D1F4D /* Build configuration list for PBXProject "cleverrc" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 7C51653420139237004D1F4D;
productRefGroup = 7C51653E20139237004D1F4D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
7C51653C20139237004D1F4D /* cleverrc */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
7C51653B20139237004D1F4D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7C51654B20139237004D1F4D /* LaunchScreen.storyboard in Resources */,
7CA401E6203471D9009FAA3B /* clever.svg in Resources */,
7CA401E42033FA34009FAA3B /* telemetry.js in Resources */,
7C7DECC2203CBCC4000C1C51 /* roslib.js in Resources */,
7C516553201526BA004D1F4D /* index.html in Resources */,
7C51654820139237004D1F4D /* Assets.xcassets in Resources */,
7CA401E22033CE17009FAA3B /* main.css in Resources */,
7C51654620139237004D1F4D /* Main.storyboard in Resources */,
7C51655520153180004D1F4D /* main.js in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
9BAB41D26FC0095C7C86B9DE /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-cleverrc/Pods-cleverrc-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9F096121C4A02BCE9D4FD1B9 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-cleverrc-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
A37DBBAD5E44E632F8A8A204 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-cleverrc/Pods-cleverrc-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/MarqueeLabel/MarqueeLabel.framework",
"${BUILT_PRODUCTS_DIR}/NotificationBannerSwift/NotificationBannerSwift.framework",
"${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework",
"${BUILT_PRODUCTS_DIR}/SwiftSocket/SwiftSocket.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MarqueeLabel.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NotificationBannerSwift.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftSocket.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-cleverrc/Pods-cleverrc-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
7C51653920139237004D1F4D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7C51654320139237004D1F4D /* ViewController.swift in Sources */,
7C51654120139237004D1F4D /* AppDelegate.swift in Sources */,
7C0AB7AB202A744400BAED27 /* BinUtils.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
7C51654420139237004D1F4D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
7C51654520139237004D1F4D /* Base */,
);
name = Main.storyboard;
path = .;
sourceTree = "<group>";
};
7C51654920139237004D1F4D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
7C51654A20139237004D1F4D /* Base */,
);
name = LaunchScreen.storyboard;
path = .;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
7C51654D20139237004D1F4D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
7C51654E20139237004D1F4D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
7C51655020139237004D1F4D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = CB200F4B933204EA97E0E2E4 /* Pods-cleverrc.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 7QY6KJ2672;
INFOPLIST_FILE = cleverrc/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = coex.cleverrc;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
7C51655120139237004D1F4D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = AAC9195BF3A9BF6942EF4D0B /* Pods-cleverrc.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 7QY6KJ2672;
INFOPLIST_FILE = cleverrc/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = coex.cleverrc;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
7C51653820139237004D1F4D /* Build configuration list for PBXProject "cleverrc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7C51654D20139237004D1F4D /* Debug */,
7C51654E20139237004D1F4D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7C51654F20139237004D1F4D /* Build configuration list for PBXNativeTarget "cleverrc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7C51655020139237004D1F4D /* Debug */,
7C51655120139237004D1F4D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 7C51653520139237004D1F4D /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:cleverrc.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:cleverrc.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,46 @@
//
// AppDelegate.swift
// cleverrc
//
// Created by Oleg Kalachev on 20.01.2018.
// Copyright © 2018 Copter Express. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}

View File

@@ -0,0 +1,100 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "cleverios180.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "cleverios180-1.png",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,20 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.10586584359407425" green="0.10589186102151871" blue="0.10586420446634293" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="landscape">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="cleverrc" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<wkWebView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dtJ-LN-BYT">
<rect key="frame" x="0.0" y="0.0" width="667" height="375"/>
<color key="backgroundColor" red="0.12939286231994629" green="0.12942266464233398" blue="0.12939092516899109" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<wkWebViewConfiguration key="configuration">
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
<wkPreferences key="preferences"/>
</wkWebViewConfiguration>
</wkWebView>
</subviews>
<color key="backgroundColor" red="0.1097869947552681" green="0.10981365293264389" blue="0.10978532582521439" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="dtJ-LN-BYT" firstAttribute="height" secondItem="8bC-Xf-vdC" secondAttribute="height" id="KRn-ag-67x"/>
<constraint firstItem="dtJ-LN-BYT" firstAttribute="width" secondItem="8bC-Xf-vdC" secondAttribute="width" id="qOr-gg-e4M"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
<connections>
<outlet property="webView" destination="dtJ-LN-BYT" id="bQ3-jy-o6E"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="138.0809595202399" y="124"/>
</scene>
</scenes>
</document>

453
apps/ios/cleverrc/BinUtils.swift vendored Normal file
View File

@@ -0,0 +1,453 @@
//
// BinUtils.swift
// BinUtils
//
// Created by Nicolas Seriot on 12/03/16.
// Copyright © 2016 Nicolas Seriot. All rights reserved.
//
import Foundation
import CoreFoundation
// MARK: protocol UnpackedType
public protocol Unpackable {}
extension NSString: Unpackable {}
extension Bool: Unpackable {}
extension Int: Unpackable {}
extension Double: Unpackable {}
// MARK: protocol DataConvertible
protocol DataConvertible {}
extension DataConvertible {
init?(data: Data) {
guard data.count == MemoryLayout<Self>.size else { return nil }
self = data.withUnsafeBytes { $0.pointee }
}
init?(bytes: [UInt8]) {
let data = Data(bytes:bytes)
self.init(data:data)
}
var data: Data {
var value = self
return Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
}
extension Bool : DataConvertible { }
extension Int8 : DataConvertible { }
extension Int16 : DataConvertible { }
extension Int32 : DataConvertible { }
extension Int64 : DataConvertible { }
extension UInt8 : DataConvertible { }
extension UInt16 : DataConvertible { }
extension UInt32 : DataConvertible { }
extension UInt64 : DataConvertible { }
extension Float32 : DataConvertible { }
extension Float64 : DataConvertible { }
// MARK: String extension
extension String {
subscript (from:Int, to:Int) -> String {
return NSString(string: self).substring(with: NSMakeRange(from, to-from))
}
}
// MARK: Data extension
extension Data {
var bytes : [UInt8] {
return self.withUnsafeBytes {
[UInt8](UnsafeBufferPointer(start: $0, count: self.count))
}
}
}
// MARK: functions
public func hexlify(_ data:Data) -> String {
// similar to hexlify() in Python's binascii module
// https://docs.python.org/2/library/binascii.html
var s = String()
var byte: UInt8 = 0
for i in 0 ..< data.count {
NSData(data: data).getBytes(&byte, range: NSMakeRange(i, 1))
s = s.appendingFormat("%02x", byte)
}
return s as String
}
public func unhexlify(_ string:String) -> Data? {
// similar to unhexlify() in Python's binascii module
// https://docs.python.org/2/library/binascii.html
let s = string.uppercased().replacingOccurrences(of: " ", with: "")
let nonHexCharacterSet = CharacterSet(charactersIn: "0123456789ABCDEF").inverted
if let range = s.rangeOfCharacter(from: nonHexCharacterSet) {
print("-- found non hex character at range \(range)")
return nil
}
var data = Data(capacity: s.count / 2)
for i in stride(from: 0, to:s.count, by:2) {
let byteString = s[i, i+2]
let byte = UInt8(byteString.withCString { strtoul($0, nil, 16) })
data.append([byte] as [UInt8], count: 1)
}
return data
}
func readIntegerType<T:DataConvertible>(_ type:T.Type, bytes:[UInt8], loc:inout Int) -> T {
let size = MemoryLayout<T>.size
let sub = Array(bytes[loc..<(loc+size)])
loc += size
return T(bytes: sub)!
}
func readFloatingPointType<T:DataConvertible>(_ type:T.Type, bytes:[UInt8], loc:inout Int, isBigEndian:Bool) -> T {
let size = MemoryLayout<T>.size
let sub = Array(bytes[loc..<(loc+size)])
loc += size
let sub_ = isBigEndian ? sub.reversed() : sub
return T(bytes: sub_)!
}
func isBigEndianFromMandatoryByteOrderFirstCharacter(_ format:String) -> Bool {
guard let firstChar = format.first else { assertionFailure("empty format"); return false }
let s = NSString(string: String(firstChar))
let c = s.substring(to: 1)
if c == "@" { assertionFailure("native size and alignment is unsupported") }
if c == "=" || c == "<" { return false }
if c == ">" || c == "!" { return true }
assertionFailure("format '\(format)' first character must be among '=<>!'")
return false
}
// akin to struct.calcsize(fmt)
func numberOfBytesInFormat(_ format:String) -> Int {
var numberOfBytes = 0
var n = 0 // repeat counter
var mutableFormat = format
while !mutableFormat.isEmpty {
let c = mutableFormat.remove(at: mutableFormat.startIndex)
if let i = Int(String(c)) , 0...9 ~= i {
if n > 0 { n *= 10 }
n += i
continue
}
if c == "s" {
numberOfBytes += max(n,1)
n = 0
continue
}
for _ in 0..<max(n,1) {
switch(c) {
case "@", "<", "=", ">", "!", " ":
()
case "c", "b", "B", "x", "?":
numberOfBytes += 1
case "h", "H":
numberOfBytes += 2
case "i", "l", "I", "L", "f":
numberOfBytes += 4
case "q", "Q", "d":
numberOfBytes += 8
case "P":
numberOfBytes += MemoryLayout<Int>.size
default:
assertionFailure("-- unsupported format \(c)")
}
}
n = 0
}
return numberOfBytes
}
func formatDoesMatchDataLength(_ format:String, data:Data) -> Bool {
let sizeAccordingToFormat = numberOfBytesInFormat(format)
let dataLength = data.count
if sizeAccordingToFormat != dataLength {
print("format \"\(format)\" expects \(sizeAccordingToFormat) bytes but data is \(dataLength) bytes")
return false
}
return true
}
/*
pack() and unpack() should behave as Python's struct module https://docs.python.org/2/library/struct.html BUT:
- native size and alignment '@' is not supported
- as a consequence, the byte order specifier character is mandatory and must be among "=<>!"
- native byte order '=' assumes a little-endian system (eg. Intel x86)
- Pascal strings 'p' and native pointers 'P' are not supported
*/
public enum BinUtilsError: Error {
case formatDoesMatchDataLength(format:String, dataSize:Int)
case unsupportedFormat(character:Character)
}
public func pack(_ format:String, _ objects:[Any], _ stringEncoding:String.Encoding=String.Encoding.windowsCP1252) -> Data {
var objectsQueue = objects
var mutableFormat = format
var mutableData = Data()
var isBigEndian = false
let firstCharacter = mutableFormat.remove(at: mutableFormat.startIndex)
switch(firstCharacter) {
case "<", "=":
isBigEndian = false
case ">", "!":
isBigEndian = true
case "@":
assertionFailure("native size and alignment '@' is unsupported'")
default:
assertionFailure("unsupported format chacracter'")
}
var n = 0 // repeat counter
while !mutableFormat.isEmpty {
let c = mutableFormat.remove(at: mutableFormat.startIndex)
if let i = Int(String(c)) , 0...9 ~= i {
if n > 0 { n *= 10 }
n += i
continue
}
var o : Any = 0
if c == "s" {
o = objectsQueue.remove(at: 0)
guard let stringData = (o as! String).data(using: .utf8) else { assertionFailure(); return Data() }
var bytes = stringData.bytes
let expectedSize = max(1, n)
// pad ...
while bytes.count < expectedSize { bytes.append(0x00) }
// ... or trunk
if bytes.count > expectedSize { bytes = Array(bytes[0..<expectedSize]) }
assert(bytes.count == expectedSize)
if isBigEndian { bytes = bytes.reversed() }
mutableData.append(bytes, count: bytes.count)
n = 0
continue
}
for _ in 0..<max(n,1) {
var bytes : [UInt8] = []
if c != "x" {
o = objectsQueue.removeFirst()
}
switch(c) {
case "?":
bytes = (o as! Bool) ? [0x01] : [0x00]
case "c":
let charAsString = (o as! NSString).substring(to: 1)
guard let data = charAsString.data(using: stringEncoding) else {
assertionFailure("cannot decode character \(charAsString) using encoding \(stringEncoding)")
return Data()
}
bytes = data.bytes
case "b":
bytes = Int8(truncatingIfNeeded:o as! Int).data.bytes
case "h":
bytes = Int16(truncatingIfNeeded:o as! Int).data.bytes
case "i", "l":
bytes = Int32(truncatingIfNeeded:o as! Int).data.bytes
case "q", "Q":
bytes = Int64(o as! Int).data.bytes
case "B":
bytes = UInt8(truncatingIfNeeded:o as! Int).data.bytes
case "H":
bytes = UInt16(truncatingIfNeeded:o as! Int).data.bytes
case "I", "L":
bytes = UInt32(truncatingIfNeeded:o as! Int).data.bytes
case "f":
bytes = Float32(o as! Double).data.bytes
case "d":
bytes = Float64(o as! Double).data.bytes
case "x":
bytes = [0x00]
default:
assertionFailure("Unsupported packing format: \(c)")
}
if isBigEndian { bytes = bytes.reversed() }
let data = Data(bytes)
mutableData.append(data)
}
n = 0
}
return mutableData
}
public func unpack(_ format:String, _ data:Data, _ stringEncoding:String.Encoding=String.Encoding.windowsCP1252) throws -> [Unpackable] {
assert(CFByteOrderGetCurrent() == 1 /* CFByteOrderLittleEndian */, "\(#file) assumes little endian, but host is big endian")
let isBigEndian = isBigEndianFromMandatoryByteOrderFirstCharacter(format)
if formatDoesMatchDataLength(format, data: data) == false {
throw BinUtilsError.formatDoesMatchDataLength(format:format, dataSize:data.count)
}
var a : [Unpackable] = []
var loc = 0
let bytes = data.bytes
var n = 0 // repeat counter
var mutableFormat = format
mutableFormat.remove(at: mutableFormat.startIndex) // consume byte-order specifier
while !mutableFormat.isEmpty {
let c = mutableFormat.remove(at: mutableFormat.startIndex)
if let i = Int(String(c)) , 0...9 ~= i {
if n > 0 { n *= 10 }
n += i
continue
}
if c == "s" {
let length = max(n,1)
let sub = Array(bytes[loc..<loc+length])
guard let s = NSString(bytes: sub, length: length, encoding: stringEncoding.rawValue) else {
assertionFailure("-- not a string: \(sub)")
return []
}
a.append(s)
loc += length
n = 0
continue
}
for _ in 0..<max(n,1) {
var o : Unpackable?
switch(c) {
case "c":
let optionalString = NSString(bytes: [bytes[loc]], length: 1, encoding: String.Encoding.utf8.rawValue)
loc += 1
guard let s = optionalString else { assertionFailure(); return [] }
o = s
case "b":
let r = readIntegerType(Int8.self, bytes:bytes, loc:&loc)
o = Int(r)
case "B":
let r = readIntegerType(UInt8.self, bytes:bytes, loc:&loc)
o = Int(r)
case "?":
let r = readIntegerType(Bool.self, bytes:bytes, loc:&loc)
o = r ? true : false
case "h":
let r = readIntegerType(Int16.self, bytes:bytes, loc:&loc)
o = Int(isBigEndian ? Int16(bigEndian: r) : r)
case "H":
let r = readIntegerType(UInt16.self, bytes:bytes, loc:&loc)
o = Int(isBigEndian ? UInt16(bigEndian: r) : r)
case "i":
fallthrough
case "l":
let r = readIntegerType(Int32.self, bytes:bytes, loc:&loc)
o = Int(isBigEndian ? Int32(bigEndian: r) : r)
case "I":
fallthrough
case "L":
let r = readIntegerType(UInt32.self, bytes:bytes, loc:&loc)
o = Int(isBigEndian ? UInt32(bigEndian: r) : r)
case "q":
let r = readIntegerType(Int64.self, bytes:bytes, loc:&loc)
o = Int(isBigEndian ? Int64(bigEndian: r) : r)
case "Q":
let r = readIntegerType(UInt64.self, bytes:bytes, loc:&loc)
o = Int(isBigEndian ? UInt64(bigEndian: r) : r)
case "f":
let r = readFloatingPointType(Float32.self, bytes:bytes, loc:&loc, isBigEndian:isBigEndian)
o = Double(r)
case "d":
let r = readFloatingPointType(Float64.self, bytes:bytes, loc:&loc, isBigEndian:isBigEndian)
o = Double(r)
case "x":
loc += 1
case " ":
()
default:
throw BinUtilsError.unsupportedFormat(character:c)
}
if let o = o { a.append(o) }
}
n = 0
}
return a
}

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Clever RC</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,10 @@
iOS-приложение для управления Клевером
--------------------------------------
Для установки зависимостей необходим [CocoaPods](https://cocoapods.org):
```bash
pod install
```
Для разработки и сборки откройте в XCode файл `cleverrc.xcworkspace`.

View File

@@ -0,0 +1,74 @@
//
// ViewController.swift
// cleverrc
//
// Created by Oleg Kalachev on 20.01.2018.
// Copyright © 2018 Copter Express. All rights reserved.
//
import UIKit
import WebKit
import SwiftSocket
import NotificationBannerSwift
class ViewController: UIViewController, WKScriptMessageHandler {
@IBOutlet weak var webView: WKWebView!
let impactGenerator = UIImpactFeedbackGenerator(style: .medium)
let notificationGenerator = UINotificationFeedbackGenerator()
let udpSocket = UDPClient(address:"255.255.255.255", port: 35602)
override func viewDidLoad() {
super.viewDidLoad()
// Don't lock screen
UIApplication.shared.isIdleTimerDisabled = true
// Setup webview event handlers
webView.configuration.userContentController.add(self, name: "control")
webView.configuration.userContentController.add(self, name: "controlStart")
webView.configuration.userContentController.add(self, name: "lowBattery")
webView.configuration.userContentController.add(self, name: "notification")
// Load the main page
let url = Bundle.main.url(forResource: "index", withExtension: "html")
let requestObj = URLRequest(url: url!)
webView.load(requestObj)
// Setup UDP broadcasting
udpSocket.enableBroadcast()
// Set UDP broadcasting interface
var wifiInterface = if_nametoindex("en0");
setsockopt(udpSocket.fd!, IPPROTO_IP, IP_BOUND_IF, &wifiInterface, socklen_t(MemoryLayout<UInt32>.size));
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if (message.name == "control") {
// Send UDP control message
let m = message.body as! NSDictionary;
let d = pack("<hhhh", [m["x"]!, m["y"]!, m["z"]!, m["r"]!])
_ = udpSocket.send(data: d)
} else if (message.name == "lowBattery") {
// Got low battery notification
print("Low battery notification")
notificationGenerator.notificationOccurred(.warning)
} else if (message.name == "notification") {
// Got notification message
print(message)
let m = message.body as! NSDictionary;
let level = m["level"] as! Int
if level == 4 {
let banner = NotificationBanner(title: m["msg"] as! String, style: .warning)
banner.show()
} else {
let banner = NotificationBanner(title: m["msg"] as! String, style: .danger)
banner.show()
}
}
}
}

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 52.5 52.5" enable-background="new 0 0 52.5 52.5" xml:space="preserve">
<g>
<path fill="white" fill-opacity="0.5" d="M35.7,17.2c0.3-0.3,0.5-0.7,0.7-1.1c0.2-0.4,0.3-0.9,0.3-1.4c0-0.5-0.1-1-0.3-1.4c-0.2-0.5-0.5-0.9-0.8-1.3
c-0.4-0.4-0.9-0.7-1.4-0.9c-0.6-0.2-1.2-0.3-1.8-0.2c-0.5,0.1-0.9,0.2-1.3,0.4c-0.2,0.1-0.4,0.3-0.6,0.4L30.2,12
c-0.1,0.1-0.1,0.1-0.2,0.1c-0.1,0.1-0.3,0.2-0.4,0.2c-0.1,0.1-0.3,0.1-0.4,0.2c-0.1,0-0.2,0.1-0.4,0.1c-0.1,0-0.2,0-0.3,0
c-0.6,0.1-1.3-0.1-1.9-0.4c-0.2-0.1-0.4-0.2-0.6-0.4c0,0-0.1-0.1-0.1-0.1c0,0-0.1-0.1-0.1-0.1c0,0,0,0-0.1-0.1
c-0.1-0.1-0.1-0.2-0.1-0.3c0,0,0,0,0-0.1l0-6.5c-0.5-0.6-1.1-1.1-1.7-1.6c-0.9-0.7-1.9-1.4-3-1.8c-0.9-0.4-1.8-0.7-2.7-1
c-0.9-0.2-1.7-0.3-2.6-0.4c-0.9-0.1-1.8,0-2.7,0.1c-0.7,0.1-1.5,0.2-2.2,0.5C9.4,0.9,8.1,1.5,7,2.2C6.2,2.7,5.4,3.3,4.7,3.9
C4,4.6,3.4,5.3,2.8,6c-0.5,0.7-1,1.4-1.3,2.2C1.1,9,0.8,9.8,0.6,10.6c-0.2,0.7-0.4,1.4-0.4,2.1C0,13.7,0,14.6,0,15.6
c0,0.8,0.2,1.7,0.4,2.5c0.2,0.9,0.5,1.7,0.8,2.5C1.8,21.8,2.5,23,3.4,24c0.3,0.4,0.7,0.8,1,1.1c0.2,0.2,0.3,0.3,0.5,0.5H11
c0.1-0.1,0.1-0.2,0.1-0.2c0-0.1,0.1-0.1,0.1-0.2c0-0.1,0.1-0.1,0.1-0.2c0.1-0.4,0.2-0.8,0.1-1.1c0-0.1,0-0.1,0-0.2
c0-0.1-0.1-0.1-0.1-0.2c0-0.1-0.1-0.2-0.2-0.2c0,0-0.1-0.1-0.1-0.1l0,0c0,0,0-0.1-0.1-0.1c0,0,0,0,0,0l-0.1-0.1
c-0.1-0.1-0.2-0.3-0.3-0.4c-0.2-0.3-0.4-0.7-0.5-1c-0.1-0.3-0.2-0.7-0.3-1c-0.1-0.6-0.1-1.1,0-1.7c0.1-0.5,0.3-1,0.5-1.5
c0.3-0.5,0.6-0.9,1-1.3c0.4-0.4,0.9-0.7,1.4-0.9c0.6-0.2,1.2-0.4,1.8-0.4c0.7,0,1.3,0.1,1.9,0.3c0.7,0.2,1.3,0.6,1.8,1.1
c0.5,0.5,1,1.1,1.3,1.8c0.2,0.4,0.3,0.7,0.3,1.1c0.1,0.4,0.1,0.8,0.1,1.3c0,0.4-0.1,0.8-0.2,1.1c-0.1,0.3-0.3,0.7-0.4,1
c-0.1,0.2-0.2,0.3-0.3,0.5c0,0.1-0.1,0.1-0.1,0.2l0,0l0,0l0,0.1c0,0,0,0.1-0.1,0.1l-0.1,0.1c0,0-0.1,0.1-0.1,0.1
c-0.1,0.1-0.1,0.1-0.1,0.2c0,0.1-0.1,0.1-0.1,0.2c0,0.1,0,0.1,0,0.2c-0.1,0.3-0.1,0.7,0.1,1.1c0,0.1,0,0.1,0.1,0.2
c0,0.1,0.1,0.1,0.1,0.2c0,0.1,0.1,0.2,0.2,0.3h7.2l0-7.5c0,0,0,0,0-0.1c0-0.1,0-0.1,0.1-0.2c0-0.1,0.1-0.1,0.1-0.2
c0,0,0.1-0.1,0.1-0.1l0.1,0c0.1-0.1,0.2-0.1,0.3-0.2c0.5-0.3,1-0.5,1.6-0.6c0.2,0,0.3,0,0.5,0c0,0,0.1,0,0.1,0c0.1,0,0.1,0,0.2,0
c0.1,0,0.2,0,0.4,0.1c0.3,0.1,0.7,0.2,0.9,0.4c0.1,0.1,0.2,0.1,0.3,0.2c0,0,0.1,0.1,0.1,0.1l0,0l-0.1,0.1c0,0,0,0,0,0l0.1-0.1
l0.2,0.2c0.1,0.1,0.2,0.2,0.4,0.2c0.2,0.1,0.5,0.3,0.8,0.4c0.7,0.2,1.4,0.3,2,0.1c0.4-0.1,0.7-0.2,1.1-0.4
C35.1,17.7,35.4,17.5,35.7,17.2z"/>
<g>
<polygon points="41.6,29.7 41.6,29.7 41.6,29.6 41.6,29.6 "/>
<path fill="white" fill-opacity="0.5" d="M28.6,49.2c0.9,0.8,2,1.4,3,1.9c0.8,0.4,1.7,0.7,2.6,0.9c0.9,0.2,1.8,0.4,2.7,0.4c0.9,0.1,1.9,0,2.8-0.1
c0.7-0.1,1.4-0.2,2.1-0.4c1.3-0.4,2.5-0.9,3.6-1.6c0.8-0.5,1.6-1.1,2.3-1.7c0.7-0.7,1.4-1.4,2-2.2c0.5-0.6,0.9-1.3,1.2-2
c0.4-0.8,0.7-1.7,1-2.5c0.2-0.6,0.3-1.3,0.4-1.9c0.1-1,0.2-2,0.1-3c0-0.8-0.2-1.6-0.3-2.4c-0.2-0.9-0.5-1.7-0.8-2.6
c-0.5-1.2-1.2-2.4-2.1-3.4c-0.3-0.4-0.6-0.8-1-1.1l-0.5-0.5h-6.1l-0.2,0.3c0,0.1-0.1,0.1-0.1,0.2c0,0.1-0.1,0.1-0.1,0.2
c-0.1,0.4-0.2,0.8-0.1,1.1c0,0.1,0,0.1,0,0.2c0,0.1,0.1,0.1,0.1,0.2c0,0.1,0.1,0.2,0.2,0.3c0,0,0.1,0.1,0.1,0.1l0,0
c0,0,0,0.1,0.1,0.1l0,0.1l0.1-0.1l0,0l0,0l0,0l0,0l0,0l0.1,0.1c0.2,0.2,0.3,0.4,0.5,0.7c0.3,0.5,0.5,1,0.6,1.5
c0.1,0.7,0.1,1.5,0,2.2c-0.2,0.6-0.4,1.2-0.8,1.8c-0.3,0.4-0.7,0.8-1.1,1.1c-0.4,0.3-0.8,0.5-1.3,0.7c-0.5,0.2-1,0.3-1.5,0.3
c-0.5,0-0.9,0-1.3-0.1c-0.5-0.1-1-0.3-1.4-0.6c-0.5-0.3-1-0.7-1.3-1.1c-0.4-0.5-0.7-1-0.9-1.6c-0.2-0.6-0.3-1.3-0.2-2
c0-0.4,0.1-0.7,0.2-1c0.1-0.4,0.3-0.8,0.5-1.1c0.1-0.2,0.2-0.3,0.3-0.5c0-0.1,0.1-0.1,0.1-0.2l0.1,0c0,0,0,0,0,0l-0.1-0.1l0.1-0.1
c0,0,0-0.1,0.1-0.1l0.1-0.1c0,0,0.1-0.1,0.1-0.1c0-0.1,0.1-0.1,0.1-0.2c0-0.1,0.1-0.1,0.1-0.2c0-0.1,0-0.1,0-0.2
c0.1-0.3,0.1-0.7-0.1-1.1c0-0.1,0-0.1-0.1-0.2c0-0.1-0.1-0.2-0.1-0.2c0-0.1-0.1-0.2-0.1-0.2h-7.2l0,7.5c0,0,0,0,0,0.1
c0,0.1-0.1,0.2-0.1,0.3c0,0,0,0.1-0.1,0.1c0,0-0.1,0.1-0.1,0.1c0,0,0,0-0.1,0c-0.1,0.1-0.3,0.2-0.4,0.3c-0.6,0.4-1.3,0.6-1.9,0.6
c-0.1,0-0.2,0-0.3,0c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.2-1-0.4c-0.1-0.1-0.2-0.2-0.3-0.2c0,0-0.1-0.1-0.1-0.1h0l0,0l0,0
c0,0-0.1-0.1-0.1-0.1L22,34.8c-0.2-0.2-0.4-0.3-0.6-0.4c-0.4-0.2-0.9-0.3-1.3-0.4c-0.3,0-0.7,0-1,0.1c-0.3,0.1-0.5,0.1-0.8,0.2
c-0.5,0.2-1,0.5-1.3,0.9c-0.3,0.4-0.6,0.8-0.8,1.3C16,37,15.9,37.5,15.9,38c0,0.5,0.1,0.9,0.3,1.3c0.2,0.4,0.4,0.7,0.7,1
c0.3,0.3,0.6,0.5,1,0.7c0.3,0.2,0.7,0.3,1,0.4c0.4,0.1,0.9,0.1,1.4,0c0.2,0,0.5-0.1,0.7-0.2c0.3-0.1,0.5-0.2,0.7-0.4
c0.1-0.1,0.2-0.2,0.3-0.3l0.1-0.1l0,0l0,0c0,0,0,0,0,0l0.1-0.1c0.1,0,0.1-0.1,0.2-0.1c0.1-0.1,0.2-0.2,0.3-0.2
c0.3-0.2,0.6-0.3,0.9-0.3c0.2,0,0.3,0,0.5,0h0.1c0.2,0,0.3,0,0.5,0c0.5,0.1,1,0.3,1.5,0.6c0.1,0.1,0.2,0.1,0.3,0.2l0.1,0
c0,0,0.1,0.1,0.1,0.1c0,0.1,0.1,0.1,0.1,0.2c0,0.1,0,0.1,0.1,0.2c0,0,0,0,0,0.1l0,0v6.5C27.4,48.2,28,48.7,28.6,49.2z"/>
<polygon points="22.3,34.9 22.3,34.9 22.3,34.9 22.3,34.9 "/>
</g>
<g>
<polygon points="40.7,30.2 40.7,30.2 40.7,30.2 "/>
<path fill="white" fill-opacity="0.5" d="M49.2,24c0.7-0.9,1.3-1.8,1.8-2.9c0.4-0.7,0.7-1.5,0.9-2.3c0.2-0.8,0.4-1.7,0.5-2.6c0.2-1.7,0.1-3.4-0.3-5
c-0.3-1.3-0.8-2.6-1.5-3.8c-0.4-0.7-0.9-1.4-1.4-2.1c-0.6-0.7-1.3-1.4-2-2c-0.6-0.5-1.3-1-2-1.4c-0.8-0.4-1.5-0.8-2.3-1.1
c-1-0.4-2-0.6-3.1-0.7C39.3,0.1,38.9,0,38.5,0c-0.2,0-0.4,0-0.6,0h-0.1c-0.5,0-0.9,0-1.4,0.1c-0.8,0.1-1.7,0.2-2.5,0.4
c-0.9,0.2-1.7,0.6-2.5,0.9c-0.8,0.4-1.5,0.8-2.2,1.3c-0.6,0.4-1.1,0.9-1.6,1.4c-0.2,0.2-0.5,0.5-0.7,0.7V11
c0.1,0.1,0.2,0.1,0.2,0.1c0.1,0,0.1,0.1,0.2,0.1c0.1,0,0.1,0.1,0.2,0.1c0.4,0.1,0.8,0.2,1.1,0.1c0.1,0,0.1,0,0.2,0
c0.1,0,0.1-0.1,0.2-0.1c0.1,0,0.2-0.1,0.3-0.2c0,0,0.1-0.1,0.1-0.1l0,0c0,0,0.1,0,0.1-0.1l0.1-0.1c0.2-0.1,0.3-0.2,0.5-0.3
c0.3-0.2,0.7-0.4,1-0.5c0.3-0.1,0.6-0.2,1-0.2c0.6-0.1,1.1-0.1,1.7,0c0.5,0.1,1,0.3,1.5,0.5c0.5,0.3,0.9,0.6,1.3,1
c0.4,0.4,0.7,0.9,0.9,1.4c0.2,0.6,0.4,1.2,0.4,1.8c0,0.6-0.1,1.3-0.3,1.9c-0.2,0.7-0.6,1.3-1,1.8c-0.5,0.5-1.1,1-1.8,1.3
c-0.4,0.1-0.7,0.3-1.1,0.3c-0.4,0.1-0.8,0.1-1.3,0.1c-0.4,0-0.7-0.1-1.1-0.2c-0.4-0.1-0.7-0.3-1-0.5c-0.2-0.1-0.3-0.2-0.5-0.3
c-0.1,0-0.1-0.1-0.2-0.1l-0.1-0.1c0,0-0.1,0-0.1-0.1c0,0-0.1-0.1-0.1-0.1c0,0-0.1-0.1-0.1-0.1c-0.1-0.1-0.1-0.1-0.2-0.1
c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1,0-0.2,0C28.4,18,28,18,27.6,18.1c-0.1,0-0.1,0-0.2,0.1c-0.1,0-0.2,0.1-0.2,0.1
c-0.1,0-0.2,0.1-0.2,0.1v7.2l7.5,0c0,0,0,0,0.1,0c0.1,0,0.2,0.1,0.3,0.1c0,0,0.1,0,0.1,0.1c0,0,0.1,0.1,0.1,0.1l0.1,0.1
c0.1,0.1,0.2,0.3,0.3,0.4c0.4,0.6,0.6,1.3,0.6,1.9c0,0.1,0,0.2,0,0.3c0,0.1,0,0.2,0,0.3c-0.1,0.4-0.2,0.7-0.4,1
c-0.1,0.1-0.2,0.2-0.2,0.3c0,0-0.1,0.1-0.1,0.1l0,0l0,0l-0.2,0.2c-0.1,0.1-0.2,0.2-0.2,0.3c-0.1,0.2-0.3,0.5-0.3,0.7
c-0.2,0.7-0.3,1.4-0.1,2c0.1,0.4,0.2,0.7,0.4,1.1c0.2,0.4,0.5,0.7,0.8,0.9c0.3,0.3,0.7,0.5,1.1,0.7c0.4,0.2,0.9,0.3,1.4,0.3
c0,0,0,0,0,0c0.5,0,1-0.1,1.4-0.3c0.5-0.2,0.9-0.5,1.3-0.8c0.4-0.4,0.7-0.9,0.9-1.4c0.2-0.6,0.3-1.2,0.2-1.8
c-0.1-0.5-0.2-0.9-0.5-1.3c-0.1-0.2-0.3-0.4-0.4-0.6l-0.1-0.1l0,0l0,0l0,0l0,0l0-0.1l0,0l-0.1,0.1l-0.1-0.1
c-0.1-0.1-0.1-0.1-0.1-0.2c-0.1-0.1-0.2-0.3-0.2-0.4c-0.1-0.1-0.1-0.3-0.2-0.4c0-0.1-0.1-0.2-0.1-0.4c0-0.1,0-0.2,0-0.3
c-0.1-0.6,0.1-1.3,0.4-1.9c0.1-0.2,0.2-0.4,0.4-0.6c0,0,0.1-0.1,0.1-0.1c0,0,0.1-0.1,0.1-0.1c0,0,0.1,0,0.1-0.1
c0.1-0.1,0.2-0.1,0.3-0.1c0,0,0,0,0.1,0l0,0h6.5C48.2,25.1,48.7,24.5,49.2,24z"/>
</g>
</g>
<g id="XMLID_14_">
</g>
<g id="XMLID_15_">
</g>
<g id="XMLID_16_">
</g>
<g id="XMLID_17_">
</g>
<g id="XMLID_18_">
</g>
<g id="XMLID_19_">
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -0,0 +1,23 @@
<html>
<head>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="main.css">
<script src="roslib.js"></script>
</head>
<body>
<div class="telemetry"><span class="mode">DISCONNECTED</span></div>
<div class="battery"></div>
<div class="logo"></div>
<div class="container">
<div class="stick stick-left">
<div class="stick-pointer"></div>
</div>
<div class="stick stick-right">
<div class="stick-pointer"></div>
</div>
</div>
<script src="main.js" type="text/javascript"></script>
<script src="telemetry.js" type="text/javascript"></script>
</body>
</html>

View File

@@ -0,0 +1,91 @@
html, body {
margin: 0;
padding: 0;
user-select: none;
font-family: sans-serif;
background: #212121;
color: rgba(255, 255, 255, 0.9);
}
.stick {
border-radius: 50%;
width: 5cm;
height: 5cm;
position: relative;
transform: translateZ(0);
border: 4px solid rgba(255,255,255,.4);
box-shadow: 0 0 0 1px rgba(0,0,0,.2), inset 0 0 0 1px rgba(0,0,0,.2);
}
.stick-pointer {
position: absolute;
border-radius: 50%;
background-color: rgba(255,255,255,.25);
box-shadow: 0 0 10px rgba(0,0,0,.3);
width: 3cm;
height: 3cm;
margin-left: -1.5cm;
margin-top: -1.5cm;
top: 2.5cm;
left: 2.5cm;
pointer-events: none;
transform: translateZ(0);
}
.container {
display: flex;
justify-content: space-around;
align-items: center;
width: 100%;
height: 100%;
}
.telemetry {
position: absolute;
text-align: center;
width: 100%;
top: 30px;
font-size: 20px;
user-select: none;
pointer-events: none;
}
body.armed .telemetry .mode {
font-weight: bold;
}
@keyframes scale {
0% { transform: scale(1.0); }
50% { transform: scale(1.2); }
100% { transform: scale(1.0); }
}
.battery {
position: absolute;
text-align: center;
width: 100%;
bottom: 30px;
font-size: 20px;
user-select: none;
pointer-events: none;
}
body.low-battery .battery {
color: #ff554b;
animation: scale 0.3s 1 ease-in-out}
.logo {
position: absolute;
background: url(clever.svg);
-webkit-background-size: 50px;
background-size: 50px;
width: 50px;
height: 50px;
top: 50%;
left: 50%;
margin-top: -25px;
margin-left: -25px;
font-size: 20px;
user-select: none;
pointer-events: none;
}

126
apps/ios/cleverrc/main.js Normal file
View File

@@ -0,0 +1,126 @@
function throttle(func, ms) {
var isThrottled = false,
savedArgs,
savedThis;
function wrapper() {
if (isThrottled) {
savedArgs = arguments;
savedThis = this;
return;
}
func.apply(this, arguments);
isThrottled = true;
setTimeout(function() {
isThrottled = false;
if (savedArgs) {
wrapper.apply(savedThis, savedArgs);
savedArgs = savedThis = null;
}
}, ms);
}
return wrapper;
}
function callNativeApp(name, msg) {
try {
webkit.messageHandlers[name].postMessage(msg);
return true;
} catch(err) {
console.warn('The native context does not exist yet');
return false;
}
}
var rcLastPublish = null;
function rcPublish() {
callNativeApp('control', controlMessage);
rcLastPublish = new Date();
}
rcPublishThrottled = throttle(rcPublish, 30);
setInterval(function() {
if (rcLastPublish !== null && new Date() - rcLastPublish > 800) {
rcPublishThrottled();
}
}, 50);
var body = document.querySelector('body');
var stickLeft = document.querySelector('.stick-left');
var stickRight = document.querySelector('.stick-right');
var controlMessage = { x: 0, y: 0, z: 0, r: 0 };
function onStickTouchMove(touch) {
var target = touch.target;
var targetRect = target.getBoundingClientRect();
var stickPointer = target.querySelector('.stick-pointer');
var offsetX = touch.clientX - targetRect.left;
var offsetY = touch.clientY - targetRect.top;
var x = 2 * offsetX / targetRect.width;
var y = 2 * offsetY / targetRect.height;
x = Math.max(0, x);
x = Math.min(2, x);
y = Math.max(0, y);
y = Math.min(2, y);
stickPointer.style.left = (x * 50) + '%';
stickPointer.style.top = (y * 50) + '%';
x -= 1;
y = 1 - y;
if (target.matches('.stick-left')) {
controlMessage.z = Math.round((y + 1) * 500);
controlMessage.r = Math.round(x * 1000);
} else if (target.matches('.stick-right')) {
controlMessage.x = Math.round(y * 1000);
controlMessage.y = Math.round(x * 1000);
}
}
body.addEventListener('touchmove', function (e) {
e.preventDefault();
});
function stickTouchStart(e) {
setControlMode();
callNativeApp('controlStart');
onStickTouchMove(e.changedTouches[0]);
rcPublishThrottled();
e.stopPropagation();
e.preventDefault();
}
function stickTouchMove(e) {
onStickTouchMove(e.changedTouches[0]);
rcPublishThrottled();
e.stopPropagation();
e.preventDefault();
}
function stickTouchEnd(e) {
var pointer = e.target.querySelector('.stick-pointer');
if (e.target.matches('.stick-left')) {
controlMessage.r = 0;
pointer.style.left = '50%';
} else if (e.target.matches('.stick-right')) {
controlMessage.x = 0;
controlMessage.y = 0;
pointer.style.left = '50%';
pointer.style.top = '50%';
}
rcPublishThrottled();
}
stickLeft.addEventListener('touchmove', stickTouchMove);
stickRight.addEventListener('touchmove', stickTouchMove);
stickLeft.addEventListener('touchstart', stickTouchStart);
stickRight.addEventListener('touchstart', stickTouchStart);
stickLeft.addEventListener('touchend', stickTouchEnd);
stickRight.addEventListener('touchend', stickTouchEnd);

3693
apps/ios/cleverrc/roslib.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
var url = 'ws://192.168.11.1:9090';
var modeEl = document.querySelector('.telemetry .mode');
var batteryEl = document.querySelector('.battery');
var ros = new ROSLIB.Ros({ url: url });
ros.on('connection', function () {
body.classList.add('connected');
});
ros.on('close', function () {
body.classList.remove('connected');
modeEl.classList.remove('armed');
modeEl.innerHTML = 'DISCONNECTED';
batteryEl.innerHTML = '';
setTimeout(function() {
modeEl.innerHTML = 'RECONNECTING';
ros.connect(url);
}, 2000);
});
var fcuState;
new ROSLIB.Topic({
ros: ros,
name: '/state_latched',
messageType: 'mavros_msgs/State'
}).subscribe(function(message) {
body.classList.toggle('fcu-disconnected', !message.connected);
body.classList.toggle('armed', message.armed);
fcuState = message;
modeEl.classList.toggle('armed', fcuState.armed);
modeEl.innerHTML = message.connected ? fcuState.mode : 'DISCONNECTED FROM FCU';
console.log('state', message);
});
function notifyLowBattery() {
callNativeApp('lowBattery');
}
notifyLowBatteryThrottled = throttle(notifyLowBattery, 10000);
new ROSLIB.Topic({
ros: ros,
name: '/mavros/battery',
messageType: 'sensor_msgs/BatteryState',
throttle_rate: 5000
}).subscribe(function(message) {
var LOW_BATTERY = 3.8;
batteryEl.innerHTML = (message.cell_voltage[0].toFixed(2) + ' V') || '';
if (message.cell_voltage[0] < LOW_BATTERY) {
console.log('low battery');
callNativeApp('lowBattery');
body.classList.remove('low-battery');
void body.offsetWidth; // trick for repeating animation
body.classList.add('low-battery');
} else {
body.classList.remove('low-battery');
}
});
new ROSLIB.Topic({
ros: ros,
name: '/rosout_agg',
messageType: 'rosgraph_msgs/Log'
}).subscribe(function(message) {
var BLACKLIST = ['CMD: ', 'PR: ', 'DROPPED'];
if(message.level >= 4) {
if (BLACKLIST.some(function(e) {
return message.msg.indexOf(e) != -1;
})) {
console.log('Filtered out message ' + message.msg);
return;
}
callNativeApp('notification', message);
}
});
var setMode = new ROSLIB.Service({
ros: ros,
name : '/mavros/set_mode',
serviceType : 'mavros_msgs/SetMode'
});
function setControlMode() {
var CONTROL_MODE = 'STABILIZED';
setMode.callService(new ROSLIB.ServiceRequest({ custom_mode: CONTROL_MODE }));
}

View File

@@ -16,6 +16,11 @@
#include <stdio.h>
#include <tf/transform_broadcaster.h>
#include "util.h"
using std::vector;
using std::string;
namespace aruco_pose {
class ArucoPose : public nodelet::Nodelet {
@@ -100,6 +105,45 @@ cv::Ptr<cv::aruco::Board> createCustomGridBoard(int markersX, int markersY, floa
return res;
}
cv::Ptr<cv::aruco::Board> createCustomBoard(std::map<string, string> markers, const cv::Ptr<cv::aruco::Dictionary> &dictionary) {
cv::Ptr<cv::aruco::Board> res = cv::makePtr<cv::aruco::Board>();
res->dictionary = dictionary;
size_t total_markers = markers.size();
res->ids.reserve(total_markers);
res->objPoints.reserve(total_markers);
// Generate ids and objPoints
for(auto const &marker : markers) {
res->ids.push_back(std::stoi(marker.first));
vector<string> parts;
parts = strSplit(marker.second, " ");
float size = std::stof(parts.at(0));
float x = std::stof(parts.at(1));
float y = std::stof(parts.at(2));
float z = std::stof(parts.at(3));
float yaw = std::stof(parts.at(4));
float pitch = std::stof(parts.at(5));
float roll = std::stof(parts.at(6));
vector<cv::Point3f> corners;
corners.resize(4);
corners[0] = cv::Point3f(x - size / 2, y + size / 2, 0);
corners[1] = corners[0] + cv::Point3f(size, 0, 0);
corners[2] = corners[0] + cv::Point3f(size, -size, 0);
corners[3] = corners[0] + cv::Point3f(0, -size, 0);
// TODO: process yaw, pitch, roll
res->objPoints.push_back(corners);
}
return res;
}
#include "fix.cpp"
void ArucoPose::createBoard()
@@ -178,8 +222,22 @@ void ArucoPose::createBoard()
}
else if (type == "custom")
{
// Not implemented yet
ROS_FATAL("Custom boards are not implemented yet.");
ROS_INFO("Initialize a custom board");
std::map<string, string> markers;
nh_priv_.getParam("markers", markers);
board = createCustomBoard(markers, dictionary);
ROS_INFO("Draw a custom board");
// Publish map image for debugging
_drawPlanarBoard(board, cv::Size(2000, 2000), map_image, 50, 1);
cv::cvtColor(map_image, map_image, CV_GRAY2BGR);
map_image_msg.encoding = sensor_msgs::image_encodings::BGR8;
map_image_msg.image = map_image;
map_image_pub.publish(map_image_msg.toImageMsg());
}
else
{
@@ -214,10 +272,12 @@ void ArucoPose::detect(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs:
cv::Mat distCoeffs(8, 1, CV_64F);
parseCameraInfo(cinfo, cameraMatrix, distCoeffs);
int valid = 0;
cv::Mat rvec, tvec, objPoints;
if (markerIds.size() > 0) {
cv::Mat rvec, tvec, objPoints;
int valid = _estimatePoseBoard(markerCorners, markerIds, board, cameraMatrix, distCoeffs,
valid = _estimatePoseBoard(markerCorners, markerIds, board, cameraMatrix, distCoeffs,
rvec, tvec, false, objPoints);
if (valid) {
@@ -243,18 +303,16 @@ void ArucoPose::detect(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs:
ref_transform.setOrigin(ref_vector3);
ref_transform.setRotation(q);
br.sendTransform(ref_transform);
if(img_pub.getNumSubscribers() > 0)
{
// Publish debug image
cv::aruco::drawDetectedMarkers(image, markerCorners, markerIds);
cv::aruco::drawAxis(image, cameraMatrix, distCoeffs, rvec, tvec, 0.3);
}
}
}
if (img_pub.getNumSubscribers() > 0)
{
cv::aruco::drawDetectedMarkers(image, markerCorners, markerIds); // draw markers
if (valid)
{
cv::aruco::drawAxis(image, cameraMatrix, distCoeffs, rvec, tvec, 0.3); // draw board axis
}
cv_bridge::CvImage out_msg;
out_msg.header.frame_id = msg->header.frame_id;
out_msg.header.stamp = msg->header.stamp;

20
aruco_pose/src/util.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include <vector>
#include <string>
std::vector<std::string> strSplit(const std::string& str, const std::string& delim)
{
std::vector<std::string> tokens;
size_t prev = 0, pos = 0;
do
{
pos = str.find(delim, prev);
if (pos == std::string::npos) pos = str.length();
std::string token = str.substr(prev, pos-prev);
if (!token.empty()) tokens.push_back(token);
prev = pos + delim.length();
}
while (pos < str.length() && prev < str.length());
return tokens;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 467 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 552 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 KiB

View File

@@ -3,5 +3,14 @@
"description": "Конструктор квадрокоптера «Клевер»",
"author": "Copter Express",
"language": "ru",
"plugins": ["youtube", "richquotes"]
}
"root": "docs/",
"plugins": ["youtube", "richquotes", "disqus", "versions"],
"pluginsConfig": {
"disqus": {
"shortName": "coex-clever"
},
"versions": {
"type": "tags"
}
}
}

View File

@@ -11,6 +11,7 @@ find_package(catkin REQUIRED COMPONENTS
nodelet
pluginlib
roscpp
genmsg
rospy
std_msgs
message_generation
@@ -68,15 +69,11 @@ add_service_files(
FILES
GetTelemetry.srv
Navigate.srv
NavigateGlobal.srv
SetPosition.srv
SetPositionYawRate.srv
SetPositionGlobal.srv
SetPositionGlobalYawRate.srv
SetVelocity.srv
SetVelocityYawRate.srv
SetAttitude.srv
SetAttitudeYawRate.srv
SetRatesYaw.srv
SetRates.srv
)
@@ -157,7 +154,9 @@ add_library(aruco_vpe
## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/clever_node.cpp)
add_executable(rc src/rc.cpp)
target_link_libraries(rc ${catkin_LIBRARIES})
## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the

View File

@@ -8,6 +8,7 @@
<arg name="rosbridge" default="true"/>
<arg name="main_camera" default="true"/>
<arg name="aruco" default="false"/>
<arg name="rc" value="true"/>
<arg name="fpv_camera" default="false"/>
<arg name="fpv_camera_device" default="/dev/v4l/by-id/usb-HD_Camera_Manufacturer_USB_2.0_Camera-video-index0"/>
<arg name="arduino" default="false"/>
@@ -46,7 +47,10 @@
<include file="$(find clever)/launch/main_camera.launch" if="$(arg main_camera)"/>
<!-- rosbridge -->
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch" if="$(arg rosbridge)"/>
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch" if="$(eval rosbridge or rc)"/>
<!-- rc backend -->
<node name="rc" pkg="clever" type="rc" output="screen" if="$(arg rc)"/>
<!-- FPV video streaming -->
<include file="$(find clever)/launch/fpv_camera.launch" if="$(arg fpv_camera)">

View File

@@ -3,8 +3,9 @@
<arg name="fcu_ip" default="127.0.0.1"/>
<arg name="gcs_bridge" default="tcp"/>
<arg name="viz" default="true"/>
<arg name="respawn" default="false"/>
<node pkg="mavros" type="mavros_node" name="mavros" required="false" clear_params="true" output="screen">
<node pkg="mavros" type="mavros_node" name="mavros" required="false" clear_params="true" respawn="$(arg respawn)" respawn_delay="3" output="screen">
<!-- UART connection -->
<param name="fcu_url" value="/dev/ttyAMA0:921600" if="$(eval fcu_conn is None or fcu_conn == 'uart')"/>
@@ -17,6 +18,7 @@
<!-- gcs bridge -->
<param name="gcs_url" value="tcp-l://0.0.0.0:5760" if="$(eval gcs_bridge == 'tcp')"/>
<param name="gcs_url" value="udp://@192.168.11.14:14550" if="$(eval gcs_bridge == 'udp')"/> <!-- TODO: fix -->
<param name="gcs_url" value="udp-b://192.168.11.1:14550@" if="$(eval gcs_bridge == 'udp-b')"/>
<param name="gcs_url" value="" if="$(eval not gcs_bridge)"/>
<!-- default px4 params -->
@@ -28,6 +30,7 @@
<param name="local_position/tf/frame_id" value="local_origin"/>
<param name="local_position/tf/child_frame_id" value="fcu"/>
<param name="global_position/tf/send" value="false"/>
<param name="imu/frame_id" value="fcu"/>
<rosparam param="plugin_blacklist">
- safety_area
- image_pub
@@ -37,7 +40,6 @@
- 3dr_radio
- actuator_control
- hil_controls
- manual_control
- vfr_hud
- px4flow
- vision_speed_estimate

View File

@@ -20,14 +20,15 @@ using std::string;
class ArucoVPE : public nodelet::Nodelet
{
public:
ArucoVPE() :
ArucoVPE() :
last_published_(0),
lookup_timeout_(0.05)
{}
private:
private:
ros::Time last_published_;
ros::Duration lookup_timeout_;
ros::Duration reset_timeout_;
ros::Publisher vision_position_pub_;
ros::Timer dummy_vision_timer_;
string aruco_orientation_;
@@ -42,6 +43,9 @@ private:
bool use_mocap;
nh_priv.param<bool>("use_mocap", use_mocap, false);
nh_priv.param<bool>("reset_vpe", reset_vpe_, !use_mocap);
double reset_timeout;
nh_priv.param("reset_timeout", reset_timeout, 2.0);
reset_timeout_ = ros::Duration(reset_timeout);
static ros::Subscriber pose_sub = nh.subscribe("mavros/local_position/pose", 1, &ArucoVPE::handlePose, this);
static ros::Subscriber aruco_pose_sub = nh.subscribe("aruco_pose/pose", 1, &ArucoVPE::handleArucoPose, this);
@@ -100,7 +104,7 @@ private:
br.sendTransform(t);
if (last_published_.toSec() == 0 || // no vpe has been posted
(reset_vpe_ && (ros::Time::now() - last_published_ > ros::Duration(2)))) // vpe origin outdated
(reset_vpe_ && (ros::Time::now() - last_published_ > reset_timeout_))) // vpe origin outdated
{
ROS_INFO("Reset VPE");
t = tf_buffer.lookupTransform("local_origin", "aruco_map_vision", stamp, lookup_timeout_);

View File

@@ -9,8 +9,15 @@ from sensor_msgs.msg import NavSatFix
def global_to_local(lat, lon):
# TODO: refactor
position_global = rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=5)
pose = rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=5)
try:
position_global = rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=0.5)
except rospy.exceptions.ROSException:
raise Exception('No global position')
try:
pose = rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=0.5)
except rospy.exceptions.ROSException:
raise Exception('No local position')
d = math.hypot(pose.pose.position.x, pose.pose.position.y)

135
clever/src/rc.cpp Normal file
View File

@@ -0,0 +1,135 @@
// CLEVER mobile remote control support:
// * Send ManualControl messages through UDP
// * `latched_state` topic
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <thread>
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "mavros_msgs/State.h"
#include "mavros_msgs/ManualControl.h"
struct ControlMessage
{
int16_t x, y, z, r;
} __attribute__((packed));
class RC
{
public:
RC():
nh(),
nh_priv("~")
{
// Create socket thread
std::thread t(&RC::socketThread, this);
t.detach();
initLatchedState();
}
private:
ros::NodeHandle nh, nh_priv;
ros::Subscriber state_sub;
ros::Publisher state_pub;
ros::Timer state_timeout_timer;
mavros_msgs::StateConstPtr state_msg;
void handleState(const mavros_msgs::StateConstPtr& state)
{
state_timeout_timer.setPeriod(ros::Duration(3), true);
state_timeout_timer.start();
if (!state_msg ||
state->connected != state_msg->connected ||
state->mode != state_msg->mode ||
state->armed != state_msg->armed) {
state_msg = state;
state_pub.publish(state_msg);
}
}
void stateTimedOut(const ros::TimerEvent&)
{
ROS_INFO("State timeout");
mavros_msgs::State unknown_state;
state_pub.publish(unknown_state);
state_msg = nullptr;
}
void initLatchedState()
{
state_sub = nh.subscribe("mavros/state", 1, &RC::handleState, this);
state_pub = nh.advertise<mavros_msgs::State>("state_latched", 1, true);
state_timeout_timer = nh.createTimer(ros::Duration(0), &RC::stateTimedOut, this, true, false);
// Publish initial state
mavros_msgs::State unknown_state;
state_pub.publish(unknown_state);
}
int createSocket(int port)
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(port);
if (bind(sockfd, (sockaddr *)&sin, sizeof(sin)) < 0) {
ROS_FATAL("socket bind error: %s", strerror(errno));
close(sockfd);
ros::shutdown();
}
return sockfd;
}
void socketThread()
{
int port;
nh_priv.param("port", port, 35602);
int sockfd = createSocket(port);
char buff[9999];
ros::Publisher manual_control_pub = nh.advertise<mavros_msgs::ManualControl>("mavros/manual_control/send", 1);
mavros_msgs::ManualControl manual_control_msg;
sockaddr_in client_addr;
socklen_t client_addr_size = sizeof(client_addr);
ROS_INFO("UDP RC initialized on port %d", port);
while (true) {
// read next UDP packet
int bsize = recvfrom(sockfd, &buff[0], sizeof(buff) - 1, 0, (sockaddr *) &client_addr, &client_addr_size);
if (bsize < 0) {
ROS_ERROR("recvfrom() error: %s", strerror(errno));
} else if (bsize != sizeof(ControlMessage)) {
ROS_ERROR_THROTTLE(30, "Wrong UDP packet size: %d", bsize);
}
// unpack message
// warning: ignore endianness, so the code is platform-dependent
ControlMessage *msg = (ControlMessage *)buff;
manual_control_msg.x = msg->x;
manual_control_msg.y = msg->y;
manual_control_msg.z = msg->z;
manual_control_msg.r = msg->r;
manual_control_pub.publish(manual_control_msg);
}
}
};
int main(int argc, char **argv)
{
ros::init(argc, argv, "rc");
RC rc;
ros::spin();
}

View File

@@ -2,7 +2,8 @@
from __future__ import division
import rospy
from geometry_msgs.msg import TransformStamped, PoseStamped, Point, PointStamped, Vector3, Vector3Stamped, TwistStamped, QuaternionStamped
from geometry_msgs.msg import TransformStamped, PoseStamped, Point, PointStamped, Vector3, \
Vector3Stamped, TwistStamped, QuaternionStamped
from sensor_msgs.msg import NavSatFix, BatteryState
import tf2_ros
import tf2_geometry_msgs
@@ -75,12 +76,19 @@ rospy.Subscriber('/mavros/global_position/global', NavSatFix, global_position_up
rospy.Subscriber('/mavros/battery', BatteryState, battery_update)
PT = PositionTarget
AT = AttitudeTarget
AUTO_OFFBOARD = rospy.get_param('~auto_offboard', True)
AUTO_ARM = AUTO_OFFBOARD and rospy.get_param('~auto_arm', True)
OFFBOARD_TIMEOUT = rospy.Duration(rospy.get_param('~offboard_timeout', 3))
ARM_TIMEOUT = rospy.Duration(rospy.get_param('~arm_timeout', 5))
LOCAL_POSITION_TIMEOUT = rospy.Duration(rospy.get_param('~local_position_timeout', 0.5))
NAVIGATE_AFTER_ARMED = rospy.Duration(rospy.get_param('~navigate_after_armed', False))
TRANSFORM_TIMEOUT = rospy.Duration(rospy.get_param('~transform_timeout', 3))
SETPOINT_RATE = rospy.get_param('~setpoint_rate', 30)
LOCAL_FRAME = rospy.get_param('~local_frame', 'local_origin')
LAND_MODE = rospy.get_param('~land_mode', 'AUTO.LAND')
LAND_TIMEOUT = rospy.Duration(rospy.get_param('~land_timeout', 2))
def offboard_and_arm():
@@ -95,6 +103,7 @@ def offboard_and_arm():
break
if rospy.get_rostime() - start > OFFBOARD_TIMEOUT:
raise Exception('OFFBOARD request timed out')
rospy.sleep(0.1)
if AUTO_ARM and not state.armed:
rospy.loginfo('Arming')
@@ -104,9 +113,9 @@ def offboard_and_arm():
while True:
if state.armed:
return True
if rospy.get_rostime() - start > ARM_TIMEOUT:
raise Exception('Arming timed out')
rospy.sleep(0.1)
ps = PoseStamped()
@@ -149,143 +158,84 @@ def get_publisher_and_message(req, stamp, continued=True, update_frame=True):
ps.header.stamp = stamp
vs.header.stamp = stamp
if isinstance(req, srv.NavigateRequest):
if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)):
global current_nav_start, current_nav_start_stamp, current_nav_finish
if update_frame:
ps.header.frame_id = req.frame_id or 'local_origin'
ps.pose.position = Point(req.x, req.y, req.z)
ps.header.frame_id = req.frame_id or LOCAL_FRAME
ps.pose.position = Point(getattr(req, 'x', 0), getattr(req, 'y', 0), req.z)
ps.pose.orientation = orientation_from_euler(0, 0, req.yaw)
current_nav_finish = tf_buffer.transform(ps, 'local_origin', TRANSFORM_TIMEOUT)
current_nav_finish = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT)
if isinstance(req, srv.NavigateGlobalRequest):
# Recalculate x and y from lat and lon
current_nav_finish.pose.position.x, current_nav_finish.pose.position.y = \
global_to_local(req.lat, req.lon)
if not continued:
current_nav_start = pose.pose.position
current_nav_start_stamp = stamp
if NAVIGATE_AFTER_ARMED and not state.armed:
current_nav_start_stamp = stamp
setpoint = get_navigate_setpoint(stamp, current_nav_start, current_nav_finish.pose.position,
current_nav_start_stamp, req.speed)
msg = PositionTarget(coordinate_frame=PositionTarget.FRAME_LOCAL_NED,
type_mask=PositionTarget.IGNORE_VX + PositionTarget.IGNORE_VY + PositionTarget.IGNORE_VZ +
PositionTarget.IGNORE_AFX + PositionTarget.IGNORE_AFY + PositionTarget.IGNORE_AFZ +
PositionTarget.IGNORE_YAW_RATE,
yaw_rate_flag = math.isnan(req.yaw)
msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED,
type_mask=PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ +
PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ +
(PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE),
position=setpoint,
yaw=euler_from_orientation(current_nav_finish.pose.orientation)[2] - math.pi / 2)
return position_pub, msg
elif isinstance(req, srv.SetPositionRequest):
ps.header.frame_id = req.frame_id or 'local_origin'
ps.pose.position = Point(req.x, req.y, req.z)
ps.pose.orientation = orientation_from_euler(0, 0, req.yaw)
pose_local = tf_buffer.transform(ps, 'local_origin', TRANSFORM_TIMEOUT)
msg = PositionTarget(coordinate_frame=PositionTarget.FRAME_LOCAL_NED,
type_mask=PositionTarget.IGNORE_VX + PositionTarget.IGNORE_VY + PositionTarget.IGNORE_VZ +
PositionTarget.IGNORE_AFX + PositionTarget.IGNORE_AFY + PositionTarget.IGNORE_AFZ +
PositionTarget.IGNORE_YAW_RATE,
position=pose_local.pose.position,
yaw=euler_from_orientation(pose_local.pose.orientation)[2] - math.pi / 2)
return position_pub, msg
elif isinstance(req, srv.SetPositionYawRateRequest):
ps.header.frame_id = req.frame_id or 'local_origin'
ps.pose.position = Point(req.x, req.y, req.z)
pose_local = tf_buffer.transform(ps, 'local_origin', TRANSFORM_TIMEOUT)
msg = PositionTarget(coordinate_frame=PositionTarget.FRAME_LOCAL_NED,
type_mask=PositionTarget.IGNORE_VX + PositionTarget.IGNORE_VY + PositionTarget.IGNORE_VZ +
PositionTarget.IGNORE_AFX + PositionTarget.IGNORE_AFY + PositionTarget.IGNORE_AFZ +
PositionTarget.IGNORE_YAW,
position=pose_local.pose.position,
yaw=euler_from_orientation(current_nav_finish.pose.orientation)[2] - math.pi / 2,
yaw_rate=req.yaw_rate)
return position_pub, msg
elif isinstance(req, srv.SetPositionGlobalRequest):
x, y = global_to_local(req.lat, req.lon)
ps.header.frame_id = req.frame_id or 'local_origin'
ps.pose.position = Point(0, 0, req.z)
elif isinstance(req, (srv.SetPositionRequest, srv.SetPositionGlobalRequest)):
ps.header.frame_id = req.frame_id or LOCAL_FRAME
ps.pose.position = Point(getattr(req, 'x', 0), getattr(req, 'y', 0), req.z)
ps.pose.orientation = orientation_from_euler(0, 0, req.yaw)
pose_local = tf_buffer.transform(ps, 'local_origin', TRANSFORM_TIMEOUT)
pose_local.pose.position.x = x
pose_local.pose.position.y = y
pose_local = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT)
msg = PositionTarget(coordinate_frame=PositionTarget.FRAME_LOCAL_NED,
type_mask=PositionTarget.IGNORE_VX + PositionTarget.IGNORE_VY + PositionTarget.IGNORE_VZ +
PositionTarget.IGNORE_AFX + PositionTarget.IGNORE_AFY + PositionTarget.IGNORE_AFZ +
PositionTarget.IGNORE_YAW_RATE,
position=pose_local.pose.position,
yaw=euler_from_orientation(pose_local.pose.orientation)[2] - math.pi / 2)
return position_pub, msg
elif isinstance(req, srv.SetPositionGlobalYawRateRequest):
x, y = global_to_local(req.lat, req.lon)
ps.header.frame_id = req.frame_id or 'local_origin'
ps.pose.position = Point(0, 0, req.z)
pose_local = tf_buffer.transform(ps, 'local_origin', TRANSFORM_TIMEOUT)
pose_local.pose.position.x = x
pose_local.pose.position.y = y
msg = PositionTarget(coordinate_frame=PositionTarget.FRAME_LOCAL_NED,
type_mask=PositionTarget.IGNORE_VX + PositionTarget.IGNORE_VY + PositionTarget.IGNORE_VZ +
PositionTarget.IGNORE_AFX + PositionTarget.IGNORE_AFY + PositionTarget.IGNORE_AFZ +
PositionTarget.IGNORE_YAW,
if isinstance(req, srv.SetPositionGlobalRequest):
pose_local.pose.position.x, pose_local.pose.position.y = global_to_local(req.lat, req.lon)
yaw_rate_flag = math.isnan(req.yaw)
msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED,
type_mask=PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ +
PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ +
(PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE),
position=pose_local.pose.position,
yaw=euler_from_orientation(pose_local.pose.orientation)[2] - math.pi / 2,
yaw_rate=req.yaw_rate)
return position_pub, msg
elif isinstance(req, srv.SetVelocityRequest):
vs.vector = Vector3(req.vx, req.vy, req.vz)
vs.header.frame_id = req.frame_id or 'local_origin'
ps.header.frame_id = req.frame_id or 'local_origin'
vs.header.frame_id = req.frame_id or LOCAL_FRAME
ps.header.frame_id = req.frame_id or LOCAL_FRAME
ps.pose.orientation = orientation_from_euler(0, 0, req.yaw)
pose_local = tf_buffer.transform(ps, 'local_origin', TRANSFORM_TIMEOUT)
vector_local = tf_buffer.transform(vs, 'local_origin', TRANSFORM_TIMEOUT)
msg = PositionTarget(coordinate_frame=PositionTarget.FRAME_LOCAL_NED,
type_mask=PositionTarget.IGNORE_PX + PositionTarget.IGNORE_PY + PositionTarget.IGNORE_PZ +
PositionTarget.IGNORE_AFX + PositionTarget.IGNORE_AFY + PositionTarget.IGNORE_AFZ +
PositionTarget.IGNORE_YAW_RATE,
velocity=vector_local.vector,
yaw=euler_from_orientation(pose_local.pose.orientation)[2] - math.pi / 2)
return position_pub, msg
pose_local = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT)
vector_local = tf_buffer.transform(vs, LOCAL_FRAME, TRANSFORM_TIMEOUT)
elif isinstance(req, srv.SetVelocityYawRateRequest):
vs.vector = Vector3(req.vx, req.vy, req.vz)
vs.header.frame_id = req.frame_id or 'local_origin'
vector_local = tf_buffer.transform(vs, 'local_origin', TRANSFORM_TIMEOUT)
msg = PositionTarget(coordinate_frame=PositionTarget.FRAME_LOCAL_NED,
type_mask=PositionTarget.IGNORE_PX + PositionTarget.IGNORE_PY + PositionTarget.IGNORE_PZ +
PositionTarget.IGNORE_AFX + PositionTarget.IGNORE_AFY + PositionTarget.IGNORE_AFZ +
PositionTarget.IGNORE_YAW,
yaw_rate_flag = math.isnan(req.yaw)
msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED,
type_mask=PT.IGNORE_PX + PT.IGNORE_PY + PT.IGNORE_PZ +
PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ +
(PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE),
velocity=vector_local.vector,
yaw=euler_from_orientation(pose_local.pose.orientation)[2] - math.pi / 2,
yaw_rate=req.yaw_rate)
return position_pub, msg
elif isinstance(req, srv.SetAttitudeRequest):
ps.header.frame_id = req.frame_id or 'local_origin'
ps.header.frame_id = req.frame_id or LOCAL_FRAME
ps.pose.orientation = orientation_from_euler(req.roll, req.pitch, req.yaw)
pose_local = tf_buffer.transform(ps, 'local_origin', TRANSFORM_TIMEOUT)
pose_local = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT)
msg = AttitudeTarget(orientation=pose_local.pose.orientation,
thrust=req.thrust,
type_mask=AttitudeTarget.IGNORE_YAW_RATE + AttitudeTarget.IGNORE_PITCH_RATE +
AttitudeTarget.IGNORE_ROLL_RATE)
return attitude_pub, msg
elif isinstance(req, srv.SetAttitudeYawRateRequest):
msg = AttitudeTarget(orientation=orientation_from_euler(req.roll, req.pitch, 0),
thrust=req.thrust,
type_mask=AttitudeTarget.IGNORE_PITCH_RATE + AttitudeTarget.IGNORE_ROLL_RATE)
msg.body_rate.z = req.yaw_rate
return attitude_pub, msg
elif isinstance(req, srv.SetRatesYawRequest):
ps.header.frame_id = req.frame_id or 'local_origin'
ps.pose.orientation = orientation_from_euler(0, 0, req.yaw)
pose_local = tf_buffer.transform(ps, 'local_origin', TRANSFORM_TIMEOUT)
msg = AttitudeTarget(orientation=pose_local.pose.orientation,
thrust=req.thrust,
type_mask=AttitudeTarget.IGNORE_YAW_RATE,
body_rate=Vector3(req.roll_rate, req.pitch_rate, 0))
type_mask=AT.IGNORE_YAW_RATE + AT.IGNORE_PITCH_RATE + AT.IGNORE_ROLL_RATE)
return attitude_pub, msg
elif isinstance(req, srv.SetRatesRequest):
@@ -311,10 +261,23 @@ def handle(req):
rospy.logwarn('No connection to the FCU')
return {'message': 'No connection to the FCU'}
if isinstance(req, srv.NavigateRequest) and req.speed <= 0:
if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)) and req.speed <= 0:
rospy.logwarn('Navigate speed must be greater than zero, %s passed')
return {'message': 'Navigate speed must be greater than zero, %s passed' % req.speed}
if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)) and \
(pose is None or rospy.get_rostime() - pose.header.stamp > LOCAL_POSITION_TIMEOUT):
rospy.logwarn('No local position')
return {'message': 'No local position'}
if getattr(req, 'yaw_rate', 0) != 0 and not math.isnan(getattr(req, 'yaw')):
rospy.logwarn('Yaw value should be NaN for setting yaw rate')
return {'message': 'Yaw value should be NaN for setting yaw rate'}
if math.isnan(getattr(req, 'yaw', 0)) and math.isnan(getattr(req, 'yaw_rate', 0)):
rospy.logwarn('Both yaw and yaw_rate cannot be NaN')
return {'message': 'Both yaw and yaw_rate cannot be NaN'}
try:
with handle_lock:
stamp = rospy.get_rostime()
@@ -340,6 +303,25 @@ def handle(req):
return {'success': False, 'message': str(e)}
def land(req):
if not state or not state.connected:
rospy.logwarn('No connection to the FCU')
return {'message': 'No connection to the FCU'}
rospy.loginfo('Set %s mode', LAND_MODE)
res = set_mode(custom_mode=LAND_MODE)
if not res.mode_sent:
return {'message': 'Cannot send %s mode request' % LAND_MODE}
start = rospy.get_rostime()
while True:
if state.mode == LAND_MODE:
return {'success': True}
if rospy.get_rostime() - start > LAND_TIMEOUT:
return {'message': '%s mode request timed out' % LAND_MODE}
rospy.sleep(0.1)
def release(req):
global current_pub
current_pub = None
@@ -348,22 +330,19 @@ def release(req):
rospy.Service('navigate', srv.Navigate, handle)
rospy.Service('navigate_global', srv.NavigateGlobal, handle)
rospy.Service('set_position', srv.SetPosition, handle)
rospy.Service('set_position/yaw_rate', srv.SetPositionYawRate, handle)
rospy.Service('set_position_global', srv.SetPositionGlobal, handle)
rospy.Service('set_position_global/yaw_rate', srv.SetPositionGlobalYawRate, handle)
rospy.Service('set_velocity', srv.SetVelocity, handle)
rospy.Service('set_velocity/yaw_rate', srv.SetVelocityYawRate, handle)
rospy.Service('set_attitude', srv.SetAttitude, handle)
rospy.Service('set_attitude/yaw_rate', srv.SetAttitudeYawRate, handle)
rospy.Service('set_rates', srv.SetRates, handle)
rospy.Service('set_rates/yaw', srv.SetRatesYaw, handle)
rospy.Service('land', Trigger, land)
rospy.Service('release', Trigger, release)
def get_telemetry(req):
res = {
'frame_id': req.frame_id or 'local_origin',
'frame_id': req.frame_id or LOCAL_FRAME,
'x': float('nan'),
'y': float('nan'),
'z': float('nan'),
@@ -381,7 +360,7 @@ def get_telemetry(req):
'voltage': float('nan'),
'cell_voltage': float('nan')
}
frame_id = req.frame_id or 'local_origin'
frame_id = req.frame_id or LOCAL_FRAME
stamp = rospy.get_rostime()
if pose:
@@ -404,7 +383,10 @@ def get_telemetry(req):
res['vx'] = linear.vector.x
res['vy'] = linear.vector.y
res['vz'] = linear.vector.z
# TODO pitch_rate, roll_rate, yaw_rate
res['yaw_rate'] = velocity.twist.angular.z
res['pitch_rate'] = velocity.twist.angular.y
res['roll_rate'] = velocity.twist.angular.x
if global_position and stamp - global_position.header.stamp < rospy.Duration(5):
res['lat'] = global_position.latitude
@@ -441,7 +423,8 @@ def start_loop():
try:
stamp = rospy.get_rostime()
if getattr(current_req, 'update_frame', False) or isinstance(current_req, srv.NavigateRequest):
if getattr(current_req, 'update_frame', False) or \
isinstance(current_req, (srv.NavigateRequest, srv.NavigateGlobalRequest)):
current_pub, current_msg = get_publisher_and_message(current_req, stamp, True,
getattr(current_req, 'update_frame', False))
@@ -451,7 +434,7 @@ def start_loop():
# For monitoring
if isinstance(current_msg, PositionTarget):
p = PoseStamped()
p.header.frame_id = 'local_origin'
p.header.frame_id = LOCAL_FRAME
p.header.stamp = stamp
p.pose.position = current_msg.position
p.pose.orientation = orientation_from_euler(0, 0, current_msg.yaw + math.pi / 2)

View File

@@ -2,6 +2,7 @@ float32 x
float32 y
float32 z
float32 yaw
float32 yaw_rate
float32 speed
string frame_id
bool update_frame

View File

@@ -1,7 +1,9 @@
float32 lat
float32 lon
float32 z
float32 yaw
float32 yaw_rate
float32 speed
string frame_id
bool update_frame
bool auto_arm

View File

@@ -1,8 +0,0 @@
float32 roll
float32 pitch
float32 yaw_rate
float32 thrust
bool auto_arm
---
bool success
string message

View File

@@ -2,6 +2,7 @@ float32 x
float32 y
float32 z
float32 yaw
float32 yaw_rate
string frame_id
bool update_frame
bool auto_arm

View File

@@ -2,6 +2,7 @@ float32 lat
float32 lon
float32 z
float32 yaw
float32 yaw_rate
string frame_id
bool update_frame
bool auto_arm

View File

@@ -1,10 +0,0 @@
float32 x
float32 y
float32 z
float32 yaw_rate
string frame_id
bool update_frame
bool auto_arm
---
bool success
string message

View File

@@ -1,10 +0,0 @@
float32 pitch_rate
float32 roll_rate
float32 yaw
float32 thrust
string frame_id
bool update_frame
bool auto_arm
---
bool success
string message

View File

@@ -2,6 +2,7 @@ float32 vx
float32 vy
float32 vz
float32 yaw
float32 yaw_rate
string frame_id
bool update_frame
bool auto_arm

View File

@@ -1,10 +0,0 @@
float32 vx
float32 vy
float32 vz
float32 yaw_rate
string frame_id
bool update_frame
bool auto_arm
---
bool success
string message

Submodule clever/static deleted from 54c530431f

30
docs/README.md Normal file
View File

@@ -0,0 +1,30 @@
Клевер
======
<img src="assets/clever3.png" align="right" width="300px" alt="Клевер">
«Клевер» — это учебный конструктор программируемого квадрокоптера, состоящего из популярных открытых компонентов, а также набор необходимой документации и библиотек для работы с ним.
Набор включает в себя полетный контроллер PixHawk/PixRacer с полетным стеком PX4, Raspberry Pi 3 в качестве управлящего бортового компьютера, модуль камеры для реализации полетов с использованием компьютерного зрения, а также набор различных датчиков и другой периферии.
На базе точно такой же платформы были созданы многие «большие» проекты компании Copter Express, например, дроны для [пиар-акций по автономной доставке пиццы](https://www.youtube.com/watch?v=hmkAoZOtF58) (Самара, Казань); дрон-доставщик кофе в Сколково, мониторинговый дрон с зарядной станцией, дроны-победители на полевых испытаниях «[Робокросс-2016](https://www.youtube.com/watch?v=dGbDaz_VmYU)», «[Робокросс-2017](https://youtu.be/AQnd2CRczbQ)» и многие другие.
Для того, чтобы научиться собирать, настраивать, пилотировать и программировать автономный дрон «Клевер», воспользуйтесь этим учебником.
Образ для Raspberry Pi
----------------------
**Образ ОС** для RPi 3 с предустановленным и преднастроенным ПО можно скачать [здесь](microsd_images.html).
Образ включает в себя:
* Raspbian Stretch
* ROS Kinetic
* Настроенную работу с сетью
* OpenCV
* mavros
* Набор ПО для работы с Клевером
[Описание API](simple_offboard.html) для автономных полетов.
Исходный код сборщика образа и всего ПО можно найти на [GitHub](https://github.com/CopterExpress/clever).

38
docs/SUMMARY.md Normal file
View File

@@ -0,0 +1,38 @@
# Summary
* [Введение](README.md)
* [Сборка](assemble.md)
* [Первоначальная настройка](setup.md)
* [Полетные режимы](modes.md)
* [Raspberry Pi](raspberry.md)
* [Образ операционной системы на RPi](microsd_images.md)
* [Подключение Raspberry Pi к PixHawk](connection.md)
* [Подключение по Wi-Fi](wifi.md)
* [Работа с QGroundControl через Wi-Fi](gcs_bridge.md)
* [SSH-доступ](ssh.md)
* [Неисправности радиоаппаратуры](radioerrors.md)
* [Безопасность](safety.md)
* [Техника безопасности по пайке](tb.md)
* [Просмотр видеострима с камер](web_video_server.md)
* [Работа с ROS](ros.md)
* [MAVROS](mavros.md)
* [Автономный полет в OFFBOARD](simple_offboard.md)
* [Примеры программ](snippets.md)
* [Навигация по ArUco-маркерам](aruco.md)
* [Взаимодействие с Arduino](arduino.md)
* [Системы координат](frames.md)
* [Работа с камерой \(компьютерное зрение\)](camera.md)
* [Ориентация камеры](camera_frame.md)
* [Визуализация с помощью rviz](rviz.md)
* [Работа с SITL](sitl.md)
* [Подключение GPS](gps.md)
* [Использование 3G-модема](3g.md)
* Учебник
* [Уроки](lessons.md)
* [Учебно-методическое пособие](metod.md)
* [Контрольные и проверочные материалы](tests.md)
* [Другое](drugoe.md)
* [CopterHack-2017](copterhack2017.md)
* [Прошивка ESC контроллеров с помощью Arduino](esc_firmware.md)
* [Работа со светодиодной лентой](leds.md)
* [Полезные ссылки](links.md)

View File

@@ -33,10 +33,34 @@ roslaunch clever arduino.launch
sudo systemctl restart clever
```
Задержки
---
При использовании `rosserial_arduino` микроконтроллер Arduino не должен быть заблокирован больше чем на несколько секунд (например, с использованием функции `delay`); иначе связь между Raspberry Pi и Arduino будет разорвана.
При реализации долгих циклов `while` обеспечьте периодический вызов функции `hn.spinOnce`:
```cpp
while(/* условие */) {
// ... Произвести необходимые действия
nh.spinOnce();
}
```
Для огранизации долгих задержек используйте задержки в цикле с периодическим вызовом функции `hn.spinOnce()`:
```cpp
// Задержка на 8 секунд
for(int i=0; i<8; i++) {
delay(1000);
nh.spinOnce();
}
```
Работа с Клевером
---
Набор сервисов и топиков аналогичен обычному набору в [simple_offboard](/docs/simple_offboard.md) и [mavros](/docs/mavros.md).
Набор сервисов и топиков аналогичен обычному набору в [simple_offboard](simple_offboard.md) и [mavros](mavros.md).
Пример программы, контролирующей коптер по позиции, с использованием сервисов `navigate` и `set_mode`:
@@ -90,8 +114,11 @@ void setup()
navigate.call(nav_req, nav_res);
// Ждем 5 секунд
delay(5000);
for(int i=0; i<5; i++) {
delay(1000);
nh.spinOnce();
}
nav_req.auto_arm = false;
// Пролет вперед на 3 метра:
@@ -105,7 +132,10 @@ void setup()
navigate.call(nav_req, nav_res);
// Ждем 5 секунд
delay(5000);
for(int i=0; i<5; i++) {
delay(1000);
nh.spinOnce();
}
// Полет в точку 1:0:2 по маркерному полю
nh.loginfo("Fly on point");
@@ -119,7 +149,10 @@ void setup()
navigate.call(nav_req, nav_res);
// Ждем 5 секунд
delay(5000);
for(int i=0; i<5; i++) {
delay(1000);
nh.spinOnce();
}
// Посадка
nh.loginfo("Land");
@@ -132,6 +165,45 @@ void loop()
}
```
Получение телеметрии
---
С Arduino можно использовать [сервис](simple_offboard.md) `get_telemetry`. Для этого надо объявить его по аналогии с сервисами `navigate` и `set_mode`:
```cpp
#include <ros.h>
// ...
#include <clever/GetTelemetry.h>
// ...
ros::ServiceClient<GetTelemetry::Request, GetTelemetry::Response> getTelemetry("/get_telemetry");
// ...
nh.serviceClient(getTelemetry);
// ...
GetTelemetry::Request gt_req;
GetTelemetry::Response gt_res;
// ...
gt_req.frame_id = "aruco_map"; // фрейм для значений x, y, z
getTelemetry.call(gt_req, gt_res);
// gt_res.x - положение коптера по x
// gt_res.y - положение коптера по y
// gt_res.z - положение коптера по z
```
Проблемы
---
При использовании Arudino Nano может не хватать оперативной памяти (RAM). В таком случае в Aruino IDE будут появляться сообщения, типа:
```
@@ -144,3 +216,16 @@ void loop()
```cpp
#define __AVR_ATmega168__ 1
```
Можно уменьшить количество занятой памяти еще сильнее, если вручную настроить количество publisher'ов и subscriber'ов, а также размеры буферов памяти, выделяемой для сообщений, например:
```cpp
#include <ros.h>
// ...
typedef ros::NodeHandle_<ArduinoHardware, 3, 3, 100, 100> NodeHandle;
// ...
NodeHandle nh;
```

View File

@@ -1,23 +1,25 @@
Навигация с использованием ArUco-маркеров
===
# Навигация с использованием ArUco-маркеров
[ArUco-маркеры](https://docs.opencv.org/3.2.0/d5/dae/tutorial_aruco_detection.html) — это популярная технология для позиционирования
[ArUco-маркеры](https://docs.opencv.org/3.2.0/d5/dae/tutorial_aruco_detection.html) — это популярная технология для позиционирования
роботехнических систем с использованием компьютерного зрения.
Пример ArUco-маркеров:
![](/assets/markers.jpg)
![](assets/markers.jpg)
aruco_pose
---
> **Hint** При печати визуальных маркеров необходимо использовать максимально матовую бумагу. Глянцевая бумага будет бликовать на свету, сильно ухудшая качество распознавания.
Для быстрого генерирования маркеров для печати можно использовать онлайн-инструмент: http://chev.me/arucogen/.
## aruco\_pose
Модуль `aruco_pose` позволяет восстанавливать позицию коптера относительно карты ArUco-маркеров и сообщать ее полетному контролеру, используя механизм [Vision Position Estimation](https://dev.px4.io/en/ros/external_position_estimation.html).
При наличии источника положения коптера по маркерам появляется возможность производить точную автономную indoor-навигацию по позициям при помощи модуля [simple_offboard](/docs/simple_offboard.md).
При наличии источника положения коптера по маркерам появляется возможность производить точную автономную indoor-навигацию по позициям при помощи модуля [simple\_offboard](simple_offboard.md).
### Включение
Необходимо убедиться, что в launch-файле Клевера (`~/catkin_ws/src/clever/clever/launch/clever.launch`) включен запуск aruco_pose и [камеры для компьютерного зрения](/docs/camera.md):
Необходимо убедиться, что в launch-файле Клевера \(`~/catkin_ws/src/clever/clever/launch/clever.launch`\) включен запуск aruco\_pose и [камеры для компьютерного зрения](camera.md):
```xml
<arg name="main_camera" default="true"/>
@@ -44,25 +46,26 @@ sudo systemctl restart clever
<param name="frame_id" value="aruco_map_raw"/>
<!-- тип маркерного поля -->
<param name="type" value="gridboard"/>
<!-- количество маркеров по x -->
<param name="markers_x" value="1"/>
<!-- количество маркеров по y -->
<param name="markers_y" value="6"/>
<!-- ID маркера первого маркера (левого верхнего) -->
<param name="first_marker" value="240"/>
<!-- длина стороны маркера в метрах -->
<param name="markers_side" value="0.3362"/>
<!-- растояние между маркерами -->
<param name="markers_sep" value="0.46"/>
</node>
```
Можно задать отдельно расстояние между маркерами по горизонтали и вертикали:
```xml
<!-- расстояние между маркерами по горизонтали -->
<param name="markers_sep_x" value="0.97"/>
@@ -79,13 +82,13 @@ sudo systemctl restart clever
Нумерация маркеров ведется с левого верхнего угла поля.
Для контроля карты, по которой в данный момент коптер осуществляет навигацию, можно просмотреть содержимое топика `aruco_pose/map_image`. Через браузер его можно просмотреть при помощи [web_video_server](/docs/web_video_server.md) по ссылке http://192.168.11.1:8080/snapshot?topic=/aruco_pose/map_image:
Для контроля карты, по которой в данный момент коптер осуществляет навигацию, можно просмотреть содержимое топика `aruco_pose/map_image`. Через браузер его можно просмотреть при помощи [web\_video\_server](web_video_server.md) по ссылке [http://192.168.11.1:8080/snapshot?topic=/aruco\_pose/map\_image](http://192.168.11.1:8080/snapshot?topic=/aruco_pose/map_image):
![](/assets/Снимок экрана 2017-11-27 в 23.20.49.png)
![](assets/Снимок экрана 2017-11-27 в 23.20.49.png)
При полетах необходимо убедиться, что наклеенные на пол метки соответствуют карте.
В топике `aruco_pose/debug` (http://192.168.11.1:8080/snapshot?topic=/aruco_pose/debug) доступен текущий результат распознования меток:
В топике `aruco_pose/debug` \([http://192.168.11.1:8080/snapshot?topic=/aruco\_pose/debug](http://192.168.11.1:8080/snapshot?topic=/aruco_pose/debug)\) доступен текущий результат распознования меток:
TODO
@@ -93,21 +96,21 @@ TODO
По [соглашению](http://www.ros.org/reps/rep-0103.html), в маркерном поле используется стандартная система координат ENU:
* x — вправо (условный "восток");
* y — вперед (условный "север");
* x — вправо \(условный "восток"\);
* y — вперед \(условный "север"\);
* z — вверх.
_Примечание_: указанное выше определение приведено для ситуации, когда поле маркеров лежит на полу.
Таким образом, нулевой является левая нижня точка маркерного поля. Угол по рысканью считается равным 0, когда коптер смотрит направо (по оси x).
Таким образом, нулевой является левая нижня точка маркерного поля. Угол по рысканью считается равным 0, когда коптер смотрит направо \(по оси x\).
![](/assets/aruco-frame.png)
![](assets/aruco-frame.png)
### Настройка полетного контролера
Для правильной работы Vision Position Estimation необходимо (через [QGroundControl](/docs/gcs_bridge.md)) убедиться, что:
Для правильной работы Vision Position Estimation необходимо \(через [QGroundControl](gcs_bridge.md)\) убедиться, что:
* Для PixHawk: Установлена прошивка с LPE (local position estimator). Для PixRacer: параметр `SYS_MC_EST_GROUP` установлен в `local_position_estimator, attitude_estimator_q`.
* Для PixHawk: Установлена прошивка с LPE \(local position estimator\). Для PixRacer: параметр `SYS_MC_EST_GROUP` установлен в `local_position_estimator, attitude_estimator_q`.
* В параметре `LPE_FUSION` включены **только** флажки `vision position`, `vision yaw`, `land detector`. Итоговое значение _28_.
* Выключен компас: `ATT_W_MAG` = 0
* Вес угла по рысканью по зрению: `ATT_W_EXT_HDG` = 0.5
@@ -118,13 +121,16 @@ _Примечание_: указанное выше определение пр
* `LNDMC_ROT_MAX` = 45 deg
* `LNDMC_THR_RANGE` = 0.5
* `LNDMC_Z_VEL_MAX` = 1 m/s
Для простоты настройки можно воспользоваться готовым файлом настроек для [Clever 2](https://github.com/CopterExpress/clever/blob/masterassets/Clever2LPE_160118.params) или для [Clever 3](https://github.com/CopterExpress/clever/blob/masterassets/Clever3_LPE_020218.params) и вгрузить его в контроллер с помощью меню Tools - Load from file из раздела Parameters в QGroundControl.
![](assets/Screenshot from 2018-02-27 22-30-50.png)
### Полет
При правильной настройке коптер начнет удерживать позицию по VPE (в [режимах](/docs/modes.md) `POSCTL` или `OFFBOARD`) автоматически.
При правильной настройке коптер начнет удерживать позицию по VPE \(в [режимах](modes.md) `POSCTL` или `OFFBOARD`\) автоматически.
Для [автономных полетов](/docs/simple_offboard.md) можно будет использовать функции `navigate`, `set_position`, `set_velocity`. Для полета в определенные координаты маркерного поля необходимо использовать фрейм `aruco_map`:
Для [автономных полетов](simple_offboard.md) можно будет использовать функции `navigate`, `set_position`, `set_velocity`. Для полета в определенные координаты маркерного поля необходимо использовать фрейм `aruco_map`:
```python
# Вначале необходимо взлететь, чтобы коптер увидел карту меток
@@ -136,15 +142,16 @@ time.sleep(5)
# Полет в координату 2:2 маркерного поля, высота 2 метра
navigate(2, 2, 2, speed=1, frame_id='aruco_map', update_frame=True) # полет в координату 2:2, высота 3 метра
```
См. [другие функции](/docs/simple_offboard.md) simple offboard.
См. [другие функции](simple_offboard.md) simple offboard.
### Расположение маркеров на потолке
> **Info** Образ версии >0.2.
> **Info** Образ версии &gt;0.2.
![](/assets/IMG_4175.JPG)
![](assets/IMG_4175.JPG)
Для навигации по маркерам, расположенным на потолке, необходимо поставить основную камеру так, чтобы она смотрела вверх и [установить соответствующий фрейм камеры](/docs/camera_frame.md).
Для навигации по маркерам, расположенным на потолке, необходимо поставить основную камеру так, чтобы она смотрела вверх и [установить соответствующий фрейм камеры](camera_frame.md).
Чтобы задавать карту маркеров в "перевернутой" системе координат, необходимо изменить параметр `aruco_orientation` в файле `~/catkin_ws/src/clever/clever/aruco.launch`:
@@ -152,8 +159,11 @@ navigate(2, 2, 2, speed=1, frame_id='aruco_map', update_frame=True) # поле
<param name="aruco_orientation" value="local_origin_upside_down"/>
```
При задании вышеуказанного параметра фрейм aruco_map также окажется "перевернутым". Таким образом, для полета на высоту 2 метра ниже потолка, аргумент `z` нужно устанавливать в 2:
При задании вышеуказанного параметра фрейм aruco\_map также окажется "перевернутым". Таким образом, для полета на высоту 2 метра ниже потолка, аргумент `z` нужно устанавливать в 2:
```python
navigate(x=1, y=2, z=1.1, speed=0.5, frame_id='aruco_map')
```

View File

@@ -1,12 +1,12 @@
Инструкция по сборке конструктора Клевер 2
==========================================
![Clever](../assets/Clevermain.png)
![Clever](assets/Clevermain.png)
Состав конструктора
-------------------
![Explosion](../assets/explosion.png)
![Explosion](assets/explosion.png)
* Рама центральная x2.
* Рама дополнительная х4.
@@ -14,14 +14,14 @@
* Ножки x8.
* Защита для лучей x8.
* Защита пропеллеров x16.
* Защита боковая x16.
* Защита боковая x16.
* Пропеллер пластиковый Dalprop 5045 x4.
* Бесколлекторный электродвигатель Racerstar BR2205 2300kV x4.
* Регуляторы хода ESC, DYS XSD20А x4.
* Разъем силовой XT60 pin x1.
* Разъем силовой XT60 socket x1.
* Трехпроводной шлейф “мама-мама” x2.
* Провод медный многожильный с силиконовой изоляцией 14AWG (красный, черный), длина 50 см.
* Провод медный многожильный с силиконовой изоляцией 14AWG (красный, черный), длина 50 см.
* Плата распределения питания PDB BeeRotor Power Distribution Board V2.0 x1.
* Аккумуляторная батарея (АКБ) Li-ion 18650 x8.
* Зарядное устройство EFEST Luc V4 Li-lon x1.
@@ -33,7 +33,7 @@
* Зарядное устройство EFEST LUC V4 x1.
* Провод Micro USB - USB x1
* Батарейный отсек 18650 li-Ion x1
* Провод медный многожильный с силиконовой изоляцией 18AWG (красный, черный), длина 100 см.
* Провод медный многожильный с силиконовой изоляцией 18AWG (красный, черный), длина 100 см.
* Батарейка АА х4
* Джампер, Bind-разъем
@@ -76,12 +76,12 @@
16. Ручка A (VrA).
17. Ручка B (VrB).
![radio Transmitter](../assets/radioTransmitter.png)
![radio Transmitter](assets/radioTransmitter.png)
Дополнительное оборудование
---------------------------
#### Данное оборудование не входит в состав конструктора Клевер 2, но оно необходимо для реализации сборочного процесса
#### Данное оборудование не входит в состав конструктора Клевер 2, но оно необходимо для реализации сборочного процесса
1. Паяльник
2. Канифоль/ Флюс (нейтральный)
@@ -92,10 +92,10 @@
7. Канцелярский нож
8. Мультиметр
![Дополнительное оборудование](../assets/addEqipment.jpg)
![Дополнительное оборудование](assets/addEqipment.jpg)
![Техника безопасности при пайке](../docs/tb.md)
[Техника безопасности при пайке](tb.md)
Порядок сборки
--------------
@@ -104,7 +104,7 @@
* Распаковать моторы. Используя плоскогубцы, укоротить провода на моторах, обрезать половину длины (оставив 25 мм).
![Мотор brrc2205](../assets/brrc2205.png)
![Мотор brrc2205](assets/brrc2205.png)
Зачистить
* снять 2мм термоизоляции с конца провода не повредив медные жилы.
@@ -112,41 +112,41 @@
Скрутить провода.
Залудить
* Нанести флюс на оголенную часть провода.
* Нанести флюс на оголенную часть провода.
* Покрыть припоем, используя пинцет.
![Лужение](../assets/zap.jpg)
![Лужение](assets/zap.jpg)
#### Закрепить мотор на луче
* Установить мотор на сторону луча с гравировкой.
* Прикрепить моторы к лучам винтами М3х8, используя отвертку.
![Закрепить мотор на луче](../assets/brrc2205on.png)
![Закрепить мотор на луче](assets/brrc2205on.png)
* Лучи с моторами необходимо расположить согласно схеме. Стрелками указано направление вращения моторов.
![Вращение моторов](../assets/brrc2205ondeck.png)
//указать стрелками направление вращения на моторах
![Вращение моторов](assets/brrc2205ondeck.png)
#### Залудить три контактные площадки регулятора
* Нанести флюс
* Нанести флюс
* Нанести припой
Чтобы припой аккуратно заполнил всю площадку, необходимо прогреть площадку регулятора. Для этого нужно удерживать жало паяльника на контактной плащадке в течение 2 сек (или больше, если потребуется)
![Лужение контактных площадок регуляторов](../assets/escDYSzap.png)
![Лужение контактных площадок регуляторов](assets/escDYSzap.png)
* Повторить данную операцию для оставшихся трех регуляторов
#### Припаять провода моторов к регуляторам
Припаять ранее приготовленные провода моторов к контактным площадкам регуляторов.
![Припаять провода моторов к регуляторам](../assets/solderingBrrc2205ondeckTOescDYSzap.png)
![Припаять провода моторов к регуляторам](assets/solderingBrrc2205ondeckTOescDYSzap.png)
* Повторить данную операцию для оставшихся трех регуляторов
### Монтаж разъемов питания
![Статья про силовые и управляющие цепи](/power.md)
[Статья про силовые и управляющие цепи](powerConnection.md)
#### Подготовка проводов для силовых разъемов XT60
@@ -155,13 +155,13 @@
* Длина 7 см (Для силового разъема XT60 pin) - 1 красный, 1 черный
* Длина 9 см (Для силового разъема XT60 socket) - 1 красный, 1 черный
![Подготовка проводов для силового разъема](../assets/cutwire14AWG.jpg)
![Подготовка проводов для силового разъема](assets/cutwire14AWG.jpg)
#### Подготовка силовых разъемов питания XT60 pin и XT60 socket
![Статья про силовые разъемы и их обозначения](../notes/powerConnection.md)
[Статья про силовые разъемы и их обозначения](connectortypes.md)
![Силовой разъем XT60](../assets/xt60pinsocket.jpg)
![Силовой разъем XT60](assets/xt60pinsocket.jpg)
1. Под разъем XT60 pin залудить два силовых провода красный и чёрный 14AWG длиной 7 см.
2. Залудить контактные площадки разъема XT60 pin.
@@ -171,51 +171,48 @@
6. Надеть термоусадку ф5 на провода так, чтобы она закрывала контактные площадки проводов с XT60 .
7. Усадить термоусадку феном.
![Монтаж разъемов XT60](../assets/mountxt60pinsocket.png)
![Монтаж разъемов XT60](assets/mountxt60pinsocket.png)
8. Повторить процедуру для разъема XT60 socket.
#### Подготовка разъема питания управляющей цепи 5В
![Статья про трехпроводной шлейф мама-мама](../notes/servoWire.md) // *почему используется именно 3х контактный разъем, почему шина питания посередине
1. Обрезать/вытащить все пины из одного из разъемов. Отсоединить его.
2. Поддеть канцелярским ножом фиксатор на оставшемся разъеме, чтобы освободить 3-й провод.
3. Убрать 3-й (оранжевый) провод из разъема, за ненадобностью.
4. Длина оставшихся черного и красного проводов 10-12 см.
![Монтаж разъема 5В](../assets/mount5vconnector.png) *было бы круто, если делать такие картинки и в формате гифки
![Монтаж разъема 5В](assets/mount5vconnector.png) *было бы круто, если делать такие картинки и в формате гифки
### Монтаж платы распределения питания
![Статья про PDB](/pdb.md)
#### Предпаячная проверка
![Статья про прозвонку](/notes/testConnection.md)
[Статья про прозвонку](testConnection.md)
![Предпаячная проверка](../assets/startPDBtest.jpg)
![Предпаячная проверка](assets/startPDBtest.jpg)
Прозвонить следующие цепи на НЕЗАМКНУТОСТЬ (отсутствие звукового сигнала мультиметра):
* “BAT+” и “BAT-”
* “BAT+” и “BAT-”
* “12V” и “GND”
* “5V” и “GND”
Прозвонить следующие цепи на ЗАМКНУТОСТЬ (появление звукового сигнала мультиметра):
* “BAT-” c каждым контактом, обозначенным “-” и “GND”
* “BAT-” c каждым контактом, обозначенным “-” и “GND”
* “BAT+”, с каждым контактом, обозначенным “+”
#### Залудить контактные площадки платы питания
1. ![Залудить*](../notes/zap.md) контактные площадки платы питания.
1. [Залудить*](zap.md) контактные площадки платы питания.
2. С помощью мультиметра проверить отсутствие контактного замыкания на плате (прозвонить)
![Постпаячная проверка](../assets/zapPDBtest.jpg)
![Постпаячная проверка](assets/zapPDBtest.jpg)
Чтобы припой аккуратно заполнил всю площадку, необходимо её прогреть. Для этого нужно удерживать жало паяльника на контактной плащадке в течение 2 сек (или больше, если потребуется)
#### Пайка силового разъема питания XT60
Припаять разъем для АКБ, соблюдая полярность на контактных площадках.
![Пайка XT60 на PDB](../assets/solderingxt60socketTOpdb.png)
![Пайка XT60 на PDB](assets/solderingxt60socketTOpdb.png)
ВАЖНО о полярности
* красный провод - это “+”
@@ -225,12 +222,12 @@
Припаять разъем 5В, соблюдая полярность на контактных площадках.
(на изображении: красный провод - это питание “+”)
![Пайка 5В на PDB](../assets/soldering5VTOpdb.png)
![Пайка 5В на PDB](assets/soldering5VTOpdb.png)
### Монтаж отсека АКБ
#### Подготовка перемычек (3 шт.)
![Перемычка](../assets/jumper.png)
![Перемычка](assets/jumper.png)
* Отрезать силовой провод длиной 2 см.
* Зачистить с обеих сторон.
@@ -240,7 +237,7 @@
* Прозвонить мультиметром. В случае необходимости зачистить наждачной бумагой.
#### Подготовка отсека АКБ
![Подготовка отсека АКБ](../assets/casebattery.png)
![Подготовка отсека АКБ](assets/casebattery.png)
* Приклеить наклейки с разметкой внутрь отсека АКБ, в соответствии с полярностью.
* Приклеить ленту из скотча на дно отсека.
@@ -248,34 +245,34 @@
### Монтаж платы распределения питания
* Установить плату питания на раму винтами М3х8 и пластиковыми гайками.
![Установка платы PDB](../assets/mountPDB.png)
![Установка платы PDB](assets/mountPDB.png)
* ВАЖНО
Стрелочка на плате направлена в сторону носового выреза
![Установка платы PDB](../assets/topviewmountPDB.png)
![Установка платы PDB](assets/topviewmountPDB.png)
#### Монтаж элементов
1. Установить гайки в пластиковые держатели
![Монтаж пластиковых держателей](../assets/holderLegs.png)
![Монтаж пластиковых держателей](assets/holderLegs.png)
2. Установить лучи на раму винтами М3х16
*Лучи устанавливаются поверх рамы
*Лучи устанавливаются поверх рамы
*Пластиковые держатели устанавливаются снизу рамы
![Монтаж лучей](../assets/mountBeams.png)
![Монтаж лучей](assets/mountBeams.png)
3. Расположение моторов
Проверить расположение моторов (моторы с черной гайкой в левом верхнем углу и в правом нижнем).
![Расположение моторов](../assets/motorsTopview.png)
![Расположение моторов](assets/motorsTopview.png)
4. Продеть силовые провода регуляторов в отверстия.
![силовые провода моторов](../assets/escWires.png)
![силовые провода моторов](assets/escWires.png)
#### Пайка силовой цепи платы питания
Припаять силовые провода регуляторов к плате питания, соблюдая полярность.
![Пайка силовых проводов на PDB](../assets/solderingPowerwires.png)
![Пайка силовых проводов на PDB](assets/solderingPowerwires.png)
ВАЖНО о полярности
*красный провод - это “+”
@@ -284,73 +281,74 @@
### Сопряжение приемника и пульта
1. Подключить радиоприемник к разъему 5В. В любой разъем, GND внизу. На схеме питание обозначено как 5V
![Подключение питания приемника](../assets/receiver5V.png)
![Подключение питания приемника](assets/receiver5V.png)
3. Подключить АКБ.
Светодиод на радиоприемнике должен мигать.
![Подключение АКБ](../assets/connectBattery.png)
![Подключение АКБ](assets/connectBattery.png)
#### БЕЗОПАСНОСТЬ при работе с АКБ
![БЕЗОПАСНОСТЬ при работе с АКБ](../assets/safetyPower.png)
![БЕЗОПАСНОСТЬ при работе с АКБ](assets/safetyPower.png)
#### Включение радиопульта
1. На пульте зажать кнопку BIND KEY.
2. Включить пульт (перещелкнуть POWER, BIND KEY не отпускаем).
3. Ждем синхронизацию.
4. Отсоединить джампер.
5. Светодиод горит непрерывно.
1. Вставить джампер в B/VCC радиоприемника (замкнуть "землю" и "сигнал")
2. На пульте зажать кнопку BIND KEY.
3. Включить пульт (перещелкнуть POWER, BIND KEY не отпускаем).
4. Подключить аккумулятор к коптеру.
5. Ждем синхронизацию.
6. Отсоединить джампер.
7. Светодиод горит непрерывно.
![Подключение питания приемника](../assets/connectingRadio.png)
![Подключение питания приемника](assets/connectingRadio.png)
![Мануал по неисправностям](../docs/radioerrors1.md)
[Мануал по неисправностям радиоаппаратуры](radioerrors1.md)
### Проверка направления вращения моторов
1. Наклеить наклейки на АКБ 18650.
2. Установить 18650 в отсек АКБ, соблюдая полярность.
![Готовность отсека АКБ](../assets/readyBatteryholder.png)
![Готовность отсека АКБ](assets/readyBatteryholder.png)
3. Проверить, что разъем питания 5В подключен к приемнику по схеме.
4. Подключить регулятор мотора к 3 каналу приемника CH3 по схеме.
![Подключение регулятора к приемнику](../assets/connectionESCtoReceiver.png)
![Подключение регулятора к приемнику](assets/connectionESCtoReceiver.png)
5. Подключить внешнее питание (АКБ).
6. Включить пульт.
7. Подать левым стиком газ (throttle) на 10%.
8. Проверить направления вращения мотора по схеме.
![Проверка вращения моторов](../assets/testMotors.png)
![Проверка вращения моторов](assets/testMotors.png)
9. Если необходимо изменить направление вращения, то меняем любые два фазных провода мотора (нужно перепаять).
![Перепайка фазных проводов](../assets/resolderingESC.png)
![Перепайка фазных проводов](assets/resolderingESC.png)
### Монтаж радиоприемника
1. Установить пластиковые стойки 30 мм на раму винтами М3х8.
2. Разъем питания 5В продеть в прорезь.
![Установка стоек и прорезь](../assets/mountReceiverStud.png)
![Установка стоек и прорезь](assets/mountReceiverStud.png)
3. Приемник прикрепить к ![нижней дополнительной раме*](../notes/deck.md), используя двухсторонний скотч и ориентируясь на гравировку. Антенны направлены вперед.
3. Приемник прикрепить к нижней дополнительной раме, используя двухсторонний скотч и ориентируясь на гравировку. Антенны направлены вперед.
![Установка радиоприемника на деку](../assets/mountReceiverDeck.png)
![Установка радиоприемника на деку](assets/mountReceiverDeck.png)
4. Установить 3х проводной шлейф в канал PPM / CH1.
![Подключение радиоприемника](../assets/receiverPPM.png)
![Подключение радиоприемника](assets/receiverPPM.png)
5. Продеть в прорезь к разъему 5 В.
6. Прикрутить нижнюю дополнительную раму к стойкам на центральной раме винтами М3х8.
![Установка нижней деки](../assets/mountBottomDeck.png)
6. Прикрутить нижнюю дополнительную раму к стойкам на центральной раме винтами М3х8.
![Установка нижней деки](assets/mountBottomDeck.png)
##### ВАЖНО
Направление стрелок на плате питания и на раме дополнительной совпадают
Направление стрелок на плате питания и на дополнительной раме совпадают
### Монтаж полетного контроллера
#### Переворачиваем сборку
![Переворачиваем сборку](../assets/topPreview.png)
![Переворачиваем сборку](assets/topPreview.png)
#### Установка полетного контроллера Pixhawk
1. Клеим 2х сторонний скотч по углам полетного контроллера
![Полетный контроллер](../assets/pixhawk.png)
1. Клеим 2х сторонний скотч по углам полетного контроллера
![Полетный контроллер](assets/pixhawk.png)
##### ВАЖНО
При работе моторов возникают вибрации, отрицательно влияющие на показания датчиков полетного контроллера Pixhawk. Чтобы избежать этого эффекта, количество слоев двустороннего скотча
@@ -358,7 +356,7 @@
2. Установить полетный контроллер в центр рамы
![Полетный контроллер](../assets/topviewpixhawk.png)
![Полетный контроллер](assets/topviewpixhawk.png)
##### ВАЖНО
Стрелки на раме и pixhawk должны быть сонаправлены
@@ -368,29 +366,29 @@
2. Моторы к 1,2,3,4 портам MAIN OUT, согласно схеме
3. Питание от PDB (5В/VCC) в любой порт, кроме SB (SBUS)
![Подключение полетного контроллера](../assets/connectionPixhawk.png)
![Подключение полетного контроллера](assets/connectionPixhawk.png)
### Сборка регуляторов
1. Клеим 2х сторонний скотч на основание защитного бокса регуляторов
![Скотч на бокс регулей](../assets/escCase.png)
![Скотч на бокс регулей](assets/escCase.png)
2. Укладываем регуляторы в защитные боксы. Крепим полученную сборку к лучам рамы.
![Вид сверху с боксами для регулей](../assets/topESCcaseview.png)
![Вид сверху с боксами для регулей](assets/topESCcaseview.png)
### Установка защиты
1. Закрепить нижнюю защиту винтами М3х16 на лучах рамы
![Установка лучевой защиты](../assets/lowsafeDeck.png)
![Установка лучевой защиты](assets/lowsafeDeck.png)
2. Закрепить ножки к пластиковым держателям винтами М3х16
![Установка ножек](../assets/safeLegs.png)
![Установка ножек](assets/safeLegs.png)
3. Закрепить стойки 30 мм в отверстия нижней защиты винтами М3х12
![Установка нижней радиальной защиты](../assets/safelowRadial.png)
![Установка нижней радиальной защиты](assets/safelowRadial.png)
4. Закрепить верхнюю защиту винтами М3х12
![Установка верхней радиальной защиты](../assets/safehighRadial.png)
![Установка верхней радиальной защиты](assets/safehighRadial.png)
### Монтаж отсека АКБ
@@ -402,11 +400,11 @@
* Батарейный отсек (1 шт)
1. Прикрепить батарейный отсек на верхнюю дополнительную раму винтами М3х12 и гайками.
![Монтаж отсека АКБ](../assets/mountHolder.png)
![Монтаж отсека АКБ](assets/mountHolder.png)
2. Прикрепить верхнюю дополнительную раму на стойки винтами М3х8.
![Монтаж отсека АКБ](../assets/isoViewmountHolder.png)
![Монтаж отсека АКБ](assets/isoViewmountHolder.png)
3. Установить АКБ в отсек.
@@ -415,12 +413,12 @@
1. Крепим антенны на 2х сторонний скотч или изоленту, а усики продеваем в передние отверстия верхней дополнительной рамы.
![Монтаж отсека АКБ](../assets/mountAntenna.png)
![Монтаж отсека АКБ](assets/mountAntenna.png)
Коптер готов к настройке!
## БЕЗОПАСНОСТЬ ПРИ СБОРКЕ И НАСТРОЙКЕ
## Безопасность при сборке и настройке
1. Снять пропеллеры.“Все наземные операции производить со снятыми пропеллерами. Устанавливать пропеллеры на моторы только перед полётом.”
@@ -430,17 +428,12 @@
3. Позвать на помощь
“Если при выполнении работ возникли какие-либо проблемы, необходимо обратиться к преподавателю или учителю, а не пытаться решить проблему самостоятельно.”
![Безопасность при сборке](../assets/safetybyassem.png)
![Безопасность при сборке](assets/safetybyassem.png)
## Безопасность при работе с Li-ion аккумуляторами 18650
1. Обращаться с аккумуляторами бережно. Не допускать падений, ударов деформаций.
1. Обращаться с аккумуляторами бережно. Не допускать падений, ударов деформаций.
2. При подключении (отключении) аккумуляторов держаться только за разъёмы, тянуть или дергать за провода запрещается.
3. В случае обрыва разъемов, обнаружения нарушений целостности изоляции или корпуса аккумулятора, не трогая его, немедленно сообщить преподавателю.
## ![БЕЗОПАСНОСТЬ ПРИ ЛЁТНОЙ ЭКСПЛУАТАЦИИ КОПТЕРОВ](../docs/safetyDoc.md#ПОЛЁТЫ)
## [ТЕХНИКА БЕЗОПАСНОСТИ ПРИ ПАЙКЕ И ЛЁТНОЙ ЭКСПЛУАТАЦИИ КОПТЕРОВ](safety.md)

View File

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 143 KiB

View File

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

View File

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 141 KiB

View File

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View File

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

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