Compare commits

...

65 Commits

Author SHA1 Message Date
Oleg Kalachev
6f96c9e3ff Fix build, attempt #2 2018-09-19 07:04:34 +03:00
Oleg Kalachev
9aca12e0a5 Little fix in byobu installation 2018-09-19 04:40:20 +03:00
Oleg Kalachev
ead55fe0e3 image: add ltrace utility 2018-09-19 03:22:31 +03:00
Oleg Kalachev
f2820471bc mavros.launch: blacklisted wind_estimation plugin 2018-09-19 03:06:29 +03:00
Oleg Kalachev
fb7885ada2 optical flow: get fcu frame id from mavros params 2018-09-19 02:58:33 +03:00
Oleg Kalachev
f9f4dc5a92 simple_offboard: minor optimization 2018-09-19 02:56:59 +03:00
Oleg Kalachev
ffe4f562cc Code style 2018-09-19 02:53:16 +03:00
Oleg Kalachev
a906428734 image: add ROS packages for interactive markers 2018-09-19 01:42:08 +03:00
Oleg Kalachev
abc7e6fec1 Little fix 2018-09-19 01:30:51 +03:00
Oleg Kalachev
3b01cf3782 Experimental node for controlling the copter with rviz interactive markers 2018-09-19 00:13:11 +03:00
Oleg Kalachev
53d616fb16 image: add compressed_image_transport plugin 2018-09-18 04:39:27 +03:00
Oleg Kalachev
8168c1f201 docs: type 2018-09-17 19:57:44 +03:00
Oleg Kalachev
a0e1e032d6 docs: little fix 2018-09-17 19:57:15 +03:00
Andrei Korigodski
77eca7578f Use Copter Express Technologies as copyright holder 2018-09-17 19:51:20 +03:00
Andrei Korigodski
d13badca50 Improve copyright notices 2018-09-17 19:51:20 +03:00
Oleg Kalachev
acf4f84cae mavros.launch: fix copter_visualization params 2018-09-16 07:12:48 +03:00
Oleg Kalachev
c24d135815 docs: Pixhawk and Pixracer name themselves this way 2018-09-16 05:37:54 +03:00
Oleg Kalachev
0d64476b04 docs: spelling 2018-09-16 05:28:30 +03:00
Oleg Kalachev
091e110afd Move copter_visualization.launch to mavros.launch 2018-09-16 04:43:16 +03:00
Oleg Kalachev
de8ba52643 mavros.launch: fix aligning 2018-09-16 04:37:06 +03:00
Oleg Kalachev
8a2bb6eb32 mavros.launch: default connection is usb 2018-09-16 04:30:22 +03:00
Oleg Kalachev
ed649fd1b1 mavros: disable waypoint plugin 2018-09-16 04:30:07 +03:00
Oleg Kalachev
4cd4b99ae0 docs: add remark about plugin_blacklist usage in mavros 2018-09-16 04:13:37 +03:00
Oleg Kalachev
c903afa09d docs: small fix in snippets 2018-09-12 23:36:35 +03:00
Oleg Kalachev
8aeb11f771 snippet: correct formula for calculating angle to horizon 2018-09-12 23:35:53 +03:00
Oleg Kalachev
ed51b826a0 docs: add link to jsk-visualization plugins 2018-09-12 21:48:49 +03:00
Oleg Kalachev
bb84eeb35e docs: add some code smippets 2018-09-12 21:30:55 +03:00
Smirnov Artem
8a9fd2a97c Merge pull request #62 from urpylka/uart-article
Add UART article & new UART configure of image
2018-09-12 20:55:04 +03:00
Artem Smirnov
3b49f9a67f image_builder: new configure UART on RPi 2018-09-12 20:50:36 +03:00
Artem Smirnov
2a4faedf67 Add article about UART 2018-09-12 19:28:53 +03:00
Oleg Kalachev
82f7f82f54 Fix 2018-09-12 03:42:26 +03:00
Oleg Kalachev
276922104c Sane settings for rangefinders 2018-09-12 03:39:49 +03:00
Oleg Kalachev
3bd4a6673f Make camera markers node retrieve frame id from camera info 2018-09-12 02:50:36 +03:00
Oleg Kalachev
1909feceba Add experimental optical flow node 2018-09-11 19:30:11 +03:00
Oleg Kalachev
e585341933 Remove fpv_camera arg from sitl.launch 2018-09-11 06:54:08 +03:00
Oleg Kalachev
e87054f0d3 Respawn web server on failure 2018-09-11 04:35:37 +03:00
Oleg Kalachev
6b0bd77d49 selfcheck.py fixes 2018-09-11 04:02:36 +03:00
Oleg Kalachev
77f4cbcdd3 Remove unneeded 2018-09-08 23:40:30 +03:00
Oleg Kalachev
928c5938e9 Set up syntax highlighting in vim for .launch files 2018-09-08 23:38:51 +03:00
Oleg Kalachev
03500d70af selfcheck: add CPU usage checking 2018-09-08 23:37:31 +03:00
Oleg Kalachev
2c30a5361f selfcheck: add boot duration checking 2018-09-08 19:17:18 +03:00
Oleg Kalachev
c59d31fc21 Refactor selfcheck node 2018-09-08 18:45:58 +03:00
Oleg Kalachev
5115ba6d8a Update web_video_server version 2018-09-08 04:47:31 +03:00
Oleg Kalachev
4daab3d286 This is unneeded 2018-09-08 02:08:18 +03:00
Oleg Kalachev
34512e5e49 Deny byobu to check updates and take 100% CPU 2018-09-08 02:07:29 +03:00
Oleg Kalachev
0fddd90e1f clever.launch: remove viz argument from the header 2018-09-08 01:55:13 +03:00
Oleg Kalachev
29b6a58769 Set Monkey workers number to 1 2018-09-08 01:47:03 +03:00
Oleg Kalachev
549b2e3815 Add some plugins to mavros blacklist 2018-09-08 01:32:54 +03:00
Oleg Kalachev
88ef7d7eca Add butterfly web terminal 2018-09-08 01:32:05 +03:00
Oleg Kalachev
d70c3f92ad Remove FPV camera from clever.launch as it is not used 2018-09-08 00:18:21 +03:00
Oleg Kalachev
4a25fed9d5 Add camera visualisation markers node for aligning frame with rviz 2018-09-07 22:22:01 +03:00
Smirnov Artem
6fb4d43500 image_builder: change os version to 2018-06-27
Change base OS version to 2018-06-27-raspbian-stretch-lite
2018-09-06 15:56:15 +03:00
Oleg Kalachev
76dca88b62 image_builder: fix Monkey repository URL 2018-09-05 21:15:06 +03:00
Oleg Kalachev
bc7fb94d63 simple_offboard: fix yaw transformation 2018-09-05 20:30:37 +03:00
Smirnov Artem
2bedc6cd31 image_builder: Set max space for syslogs 2018-09-05 16:01:45 +03:00
Oleg Kalachev
c0f748756b docs: small fix 2018-09-04 22:44:35 +03:00
Oleg Kalachev
181a8aeb1b simple_offboard: default speed for navigate service 2018-09-04 02:23:28 +03:00
Oleg Kalachev
c45f7b8148 Don’t run web server in SITL 2018-09-04 01:52:23 +03:00
Oleg Kalachev
1d21665c16 Add Monkey web server 2018-09-04 01:30:30 +03:00
Oleg Kalachev
b87d3c612b Some fixes to selfcheck 2018-09-04 01:22:49 +03:00
Oleg Kalachev
d6757d67f8 Image builder: disable apt auto-updates 2018-09-03 20:15:11 +03:00
Oleg Kalachev
376e44ec6c simple_offboard: enable ‘navigate_after_armed’ by default 2018-09-01 02:48:53 +03:00
Oleg Kalachev
94402d96ad rc: new icon, version update 2018-08-24 00:36:13 +03:00
Oleg Kalachev
d3a1bf7eb6 Remove web server argument from sitl.launch 2018-08-22 20:50:43 +03:00
Oleg Kalachev
beb9370fc5 Remove web_server node 2018-08-22 18:08:48 +03:00
90 changed files with 1029 additions and 312 deletions

View File

@@ -5,7 +5,7 @@ end_of_line = lf
insert_final_newline = true insert_final_newline = true
charset = utf-8 charset = utf-8
[*.{py,cpp,h,swift,launch}] [*.{py,swift,launch}]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4

View File

@@ -13,8 +13,8 @@
"WireShark", "WireShark",
"Wi-Fi", "Wi-Fi",
"Raspberry Pi", "Raspberry Pi",
"PixHawk", "Pixhawk",
"PixRacer", "Pixracer",
"ArUco" "ArUco"
], ],
"code_blocks": false "code_blocks": false

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2018 Copter Express Copyright (c) 2018 Copter Express Technologies
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

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

View File

@@ -226,16 +226,10 @@
); );
inputPaths = ( inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-cleverrc/Pods-cleverrc-frameworks.sh", "${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", "${BUILT_PRODUCTS_DIR}/SwiftSocket/SwiftSocket.framework",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( 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", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftSocket.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -397,7 +391,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 7QY6KJ2672; DEVELOPMENT_TEAM = M8TDN3PAH2;
INFOPLIST_FILE = cleverrc/Info.plist; INFOPLIST_FILE = cleverrc/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = coex.cleverrc; PRODUCT_BUNDLE_IDENTIFIER = coex.cleverrc;
@@ -413,7 +407,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 7QY6KJ2672; DEVELOPMENT_TEAM = M8TDN3PAH2;
INFOPLIST_FILE = cleverrc/Info.plist; INFOPLIST_FILE = cleverrc/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = coex.cleverrc; PRODUCT_BUNDLE_IDENTIFIER = coex.cleverrc;

View File

@@ -3,7 +3,7 @@
// cleverrc // cleverrc
// //
// Created by Oleg Kalachev on 20.01.2018. // Created by Oleg Kalachev on 20.01.2018.
// Copyright © 2018 Copter Express. All rights reserved. // Copyright © 2018 Copter Express Technologies. All rights reserved.
// //
import UIKit import UIKit

View File

@@ -3,114 +3,176 @@
{ {
"size" : "20x20", "size" : "20x20",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "cleverrc40.png", "filename" : "Icon-App-20x20@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "20x20", "size" : "20x20",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "clever60.png", "filename" : "Icon-App-20x20@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "clever58.png", "filename" : "Icon-App-29x29@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "clever87.png", "filename" : "Icon-App-29x29@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "clever80.png", "filename" : "Icon-App-40x40@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "clever120.png", "filename" : "Icon-App-40x40@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "60x60", "size" : "60x60",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "clever120-1.png", "filename" : "Icon-App-60x60@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "60x60", "size" : "60x60",
"idiom" : "iphone", "idiom" : "iphone",
"filename" : "clever180-1.png", "filename" : "Icon-App-60x60@3x.png",
"scale" : "3x" "scale" : "3x"
}, },
{ {
"size" : "20x20", "size" : "20x20",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever20.png", "filename" : "Icon-App-20x20@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "20x20", "size" : "20x20",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever40.png", "filename" : "Icon-App-20x20@2x-1.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever29.png", "filename" : "Icon-App-29x29@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "29x29", "size" : "29x29",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever58-1.png", "filename" : "Icon-App-29x29@2x-1.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever40-1.png", "filename" : "Icon-App-40x40@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "40x40", "size" : "40x40",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever80-1.png", "filename" : "Icon-App-40x40@2x-1.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "76x76", "size" : "76x76",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever76.png", "filename" : "Icon-App-76x76@1x.png",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"size" : "76x76", "size" : "76x76",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever152.png", "filename" : "Icon-App-76x76@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "83.5x83.5", "size" : "83.5x83.5",
"idiom" : "ipad", "idiom" : "ipad",
"filename" : "clever167.png", "filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"size" : "1024x1024", "size" : "1024x1024",
"idiom" : "ios-marketing", "idiom" : "ios-marketing",
"filename" : "clever1024.png", "filename" : "ItunesArtwork@2x.png",
"scale" : "1x"
},
{
"size" : "24x24",
"idiom" : "watch",
"scale" : "2x",
"role" : "notificationCenter",
"subtype" : "38mm"
},
{
"size" : "27.5x27.5",
"idiom" : "watch",
"scale" : "2x",
"role" : "notificationCenter",
"subtype" : "42mm"
},
{
"size" : "29x29",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "watch",
"scale" : "2x",
"role" : "appLauncher",
"subtype" : "38mm"
},
{
"size" : "44x44",
"idiom" : "watch",
"scale" : "2x",
"role" : "longLook",
"subtype" : "42mm"
},
{
"size" : "86x86",
"idiom" : "watch",
"scale" : "2x",
"role" : "quickLook",
"subtype" : "38mm"
},
{
"size" : "98x98",
"idiom" : "watch",
"scale" : "2x",
"role" : "quickLook",
"subtype" : "42mm"
},
{
"idiom" : "watch-marketing",
"size" : "1024x1024",
"scale" : "1x" "scale" : "1x"
} }
], ],
"info" : { "info" : {
"version" : 1, "version" : 1,
"author" : "xcode" "author" : "xcode"
},
"properties" : {
"pre-rendered" : true
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 B

View File

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

View File

@@ -17,9 +17,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>1.1</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>5</string> <string>6</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>

View File

@@ -3,13 +3,12 @@
// cleverrc // cleverrc
// //
// Created by Oleg Kalachev on 20.01.2018. // Created by Oleg Kalachev on 20.01.2018.
// Copyright © 2018 Copter Express. All rights reserved. // Copyright © 2018 Copter Express Technologies. All rights reserved.
// //
import UIKit import UIKit
import WebKit import WebKit
import SwiftSocket import SwiftSocket
import NotificationBannerSwift
import AudioToolbox.AudioServices import AudioToolbox.AudioServices
class ViewController: UIViewController, WKScriptMessageHandler { class ViewController: UIViewController, WKScriptMessageHandler {

View File

@@ -21,6 +21,9 @@ find_package(catkin REQUIRED COMPONENTS
tf tf
tf2 tf2
tf2_geometry_msgs tf2_geometry_msgs
tf2_ros
image_transport
cv_bridge
) )
@@ -121,7 +124,7 @@ generate_messages(
## DEPENDS: system dependencies of this project that dependent projects also need ## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package( catkin_package(
# INCLUDE_DIRS include # INCLUDE_DIRS include
# LIBRARIES clever LIBRARIES clever
# CATKIN_DEPENDS other_catkin_pkg # CATKIN_DEPENDS other_catkin_pkg
# DEPENDS system_lib # DEPENDS system_lib
) )
@@ -137,7 +140,11 @@ include_directories(
${catkin_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS}
) )
## Declare a C++ library # Declare a C++ library
add_library(clever
src/optical_flow.cpp
)
add_library(fcu_horiz add_library(fcu_horiz
src/fcu_horiz.cpp src/fcu_horiz.cpp
) )
@@ -156,8 +163,12 @@ add_library(aruco_vpe
## The recommended prefix ensures that target names across packages don't collide ## The recommended prefix ensures that target names across packages don't collide
add_executable(rc src/rc.cpp) add_executable(rc src/rc.cpp)
add_executable(camera_markers src/camera_markers.cpp)
target_link_libraries(rc ${catkin_LIBRARIES}) target_link_libraries(rc ${catkin_LIBRARIES})
target_link_libraries(camera_markers ${catkin_LIBRARIES})
## Rename C++ executable without prefix ## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the ## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use ## target back to the shorter version for ease of user use
@@ -169,6 +180,10 @@ target_link_libraries(rc ${catkin_LIBRARIES})
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against ## Specify libraries to link a library or executable target against
target_link_libraries(clever
${catkin_LIBRARIES}
)
target_link_libraries(fcu_horiz target_link_libraries(fcu_horiz
${catkin_LIBRARIES} ${catkin_LIBRARIES}
"/opt/ros/kinetic/lib/libtf2_ros.so" "/opt/ros/kinetic/lib/libtf2_ros.so"

View File

@@ -2,15 +2,13 @@
<arg name="fcu_conn" default="usb"/> <arg name="fcu_conn" default="usb"/>
<arg name="fcu_ip" default="127.0.0.1"/> <arg name="fcu_ip" default="127.0.0.1"/>
<arg name="gcs_bridge" default="tcp"/> <arg name="gcs_bridge" default="tcp"/>
<arg name="viz" default="true"/> <arg name="web_server" default="true"/>
<arg name="web_server" default="false"/>
<arg name="web_video_server" default="true"/> <arg name="web_video_server" default="true"/>
<arg name="rosbridge" default="true"/> <arg name="rosbridge" default="true"/>
<arg name="main_camera" default="true"/> <arg name="main_camera" default="true"/>
<arg name="optical_flow" default="false"/>
<arg name="aruco" default="false"/> <arg name="aruco" default="false"/>
<arg name="rc" value="true"/> <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"/> <arg name="arduino" default="false"/>
<!-- mavros --> <!-- mavros -->
@@ -18,11 +16,12 @@
<arg name="fcu_conn" value="$(arg fcu_conn)"/> <arg name="fcu_conn" value="$(arg fcu_conn)"/>
<arg name="fcu_ip" value="$(arg fcu_ip)"/> <arg name="fcu_ip" value="$(arg fcu_ip)"/>
<arg name="gcs_bridge" value="$(arg gcs_bridge)"/> <arg name="gcs_bridge" value="$(arg gcs_bridge)"/>
<arg name="viz" value="$(arg viz)"/> <arg name="viz" value="true"/>
</include> </include>
<!-- web server -->
<include file="$(find clever)/launch/web_server.launch" if="$(arg web_server)"/> <!-- web server, serving /home/pi/catkin_ws/src/clever/clever/static -->
<node name="web_server" pkg="clever" type="monkey" output="screen" if="$(arg web_server)" respawn="true" respawn_delay="5"/>
<!-- web video server --> <!-- web video server -->
<node name="web_video_server" pkg="web_video_server" type="web_video_server" if="$(arg web_video_server)" required="false" respawn="true" respawn_delay="5"/> <node name="web_video_server" pkg="web_video_server" type="web_video_server" if="$(arg web_video_server)" required="false" respawn="true" respawn_delay="5"/>
@@ -30,6 +29,12 @@
<!-- aruco vpe --> <!-- aruco vpe -->
<include file="$(find clever)/launch/aruco.launch" if="$(arg aruco)"/> <include file="$(find clever)/launch/aruco.launch" if="$(arg aruco)"/>
<!-- optical flow -->
<node pkg="nodelet" type="nodelet" name="optical_flow" args="load clever/optical_flow nodelet_manager" if="$(arg optical_flow)" clear_params="true">
<remap from="image" to="main_camera/image_raw"/>
<remap from="camera_info" to="main_camera/camera_info"/>
</node>
<!-- main nodelet manager --> <!-- main nodelet manager -->
<node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager" output="screen" clear_params="true"> <node pkg="nodelet" type="nodelet" name="nodelet_manager" args="manager" output="screen" clear_params="true">
<param name="num_worker_threads" value="2"/> <param name="num_worker_threads" value="2"/>
@@ -52,11 +57,6 @@
<!-- rc backend --> <!-- rc backend -->
<node name="rc" pkg="clever" type="rc" output="screen" if="$(arg rc)"/> <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)">
<arg name="device" value="$(arg fpv_camera_device)"/>
</include>
<!-- Arduino bridge --> <!-- Arduino bridge -->
<include file="$(find clever)/launch/arduino.launch" if="$(arg arduino)"/> <include file="$(find clever)/launch/arduino.launch" if="$(arg arduino)"/>
</launch> </launch>

View File

@@ -1,12 +0,0 @@
<launch>
<remap to="mavros/local_position/pose" from="local_position"/>
<remap to="mavros/setpoint_position/local" from="local_setpoint"/>
<node name="copter_visualization" pkg="mavros_extras" type="copter_visualization"/>
<param name="copter_visualization/fixed_frame_id" value="local_origin"/>
<param name="copter_visualization/child_frame_id" value="fcu"/>
<param name="copter_visualization/marker_scale" value="1"/>
<param name="copter_visualization/max_track_size" value="500"/>
<param name="copter_visualization/num_rotors" value="4"/>
</launch>

View File

@@ -1,4 +1,7 @@
<launch> <launch>
<!-- Camera position and orientation are represented by fcu -> main_camera_optical transform -->
<!-- static_transform_publisher arguments: x y z yaw pitch roll frame_id child_frame_id -->
<!-- clever 2 --> <!-- clever 2 -->
<!--<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0 0 -0.07 -1.5707963 0 3.1415926 fcu main_camera_optical"/>--> <!--<node pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0 0 -0.07 -1.5707963 0 3.1415926 fcu main_camera_optical"/>-->
@@ -20,4 +23,9 @@
<param name="image_width" value="320"/> <param name="image_width" value="320"/>
<param name="image_height" value="240"/> <param name="image_height" value="240"/>
</node> </node>
<!-- camera visualization markers -->
<node pkg="clever" type="camera_markers" ns="main_camera" name="main_camera_markers">
<param name="scale" value="3.0"/>
</node>
</launch> </launch>

View File

@@ -1,58 +1,95 @@
<launch> <launch>
<arg name="fcu_conn" default="uart"/> <arg name="fcu_conn" default="usb"/>
<arg name="fcu_ip" default="127.0.0.1"/> <arg name="fcu_ip" default="127.0.0.1"/>
<arg name="gcs_bridge" default="tcp"/> <arg name="gcs_bridge" default="tcp"/>
<arg name="viz" default="true"/> <arg name="viz" default="true"/>
<arg name="respawn" default="true"/> <arg name="respawn" default="true"/>
<node pkg="mavros" type="mavros_node" name="mavros" required="false" clear_params="true" respawn="$(arg respawn)" respawn_delay="5" output="screen"> <node pkg="mavros" type="mavros_node" name="mavros" required="false" clear_params="true" respawn="$(arg respawn)" respawn_delay="5" output="screen">
<!-- UART connection --> <!-- UART connection -->
<param name="fcu_url" value="/dev/ttyAMA0:921600" if="$(eval fcu_conn is None or fcu_conn == 'uart')"/> <param name="fcu_url" value="/dev/ttyAMA0:921600" if="$(eval fcu_conn is None or fcu_conn == 'uart')"/>
<!-- USB connection --> <!-- USB connection -->
<param name="fcu_url" value="/dev/ttyACM0" if="$(eval fcu_conn == 'usb')"/> <param name="fcu_url" value="/dev/ttyACM0" if="$(eval fcu_conn == 'usb')"/>
<!-- sitl --> <!-- sitl -->
<param name="fcu_url" value="udp://@$(arg fcu_ip):14557" if="$(eval fcu_conn == 'udp')"/> <param name="fcu_url" value="udp://@$(arg fcu_ip):14557" if="$(eval fcu_conn == 'udp')"/>
<!-- gcs bridge --> <!-- gcs bridge -->
<param name="gcs_url" value="tcp-l://0.0.0.0:5760" if="$(eval gcs_bridge == 'tcp')"/> <param name="gcs_url" value="tcp-l://0.0.0.0:5760" if="$(eval gcs_bridge == 'tcp')"/>
<param name="gcs_url" value="udp://0.0.0.0:14550@14550" if="$(eval gcs_bridge == 'udp')"/> <param name="gcs_url" value="udp://0.0.0.0:14550@14550" if="$(eval gcs_bridge == 'udp')"/>
<param name="gcs_url" value="udp-b://$(env ROS_IP):14550@14550" if="$(eval gcs_bridge == 'udp-b')"/> <param name="gcs_url" value="udp-b://$(env ROS_IP):14550@14550" if="$(eval gcs_bridge == 'udp-b')"/>
<param name="gcs_url" value="udp-pb://$(env ROS_IP):14550@14550" if="$(eval gcs_bridge == 'udp-pb')"/> <param name="gcs_url" value="udp-pb://$(env ROS_IP):14550@14550" if="$(eval gcs_bridge == 'udp-pb')"/>
<param name="gcs_url" value="" if="$(eval not gcs_bridge)"/> <param name="gcs_url" value="" if="$(eval not gcs_bridge)"/>
<param name="gcs_quiet_mode" value="true"/> <param name="gcs_quiet_mode" value="true"/>
<param name="conn/timeout" value="8"/> <param name="conn/timeout" value="8"/>
<!-- default px4 params --> <!-- default px4 params -->
<rosparam command="load" file="$(find mavros)/launch/px4_config.yaml"/> <rosparam command="load" file="$(find mavros)/launch/px4_config.yaml"/>
<!-- additional params --> <!-- rangefinders -->
<param name="local_position/frame_id" value="local_origin"/> <rosparam>
<param name="local_position/tf/send" value="true"/> distance_sensor:
<param name="local_position/tf/frame_id" value="local_origin"/> rangefinder_0:
<param name="local_position/tf/child_frame_id" value="fcu"/> id: 0
<param name="global_position/tf/send" value="false"/> frame_id: "rangefinder"
<param name="imu/frame_id" value="fcu"/> orientation: PITCH_270
<rosparam param="plugin_blacklist"> field_of_view: 0.5
- safety_area rangefinder_1:
- image_pub id: 1
- vibration frame_id: "rangefinder"
- distance_sensor orientation: PITCH_270
- rangefinder field_of_view: 0.5
- 3dr_radio rangefinder_2_sub:
- actuator_control subscriber: true
- hil_controls id: 2
- vfr_hud orientation: PITCH_270
- px4flow rangefinder_3_sub:
- vision_speed_estimate subscriber: true
- fake_gps id: 3
- cam_imu_sync orientation: PITCH_270
- hil </rosparam>
- adsb
</rosparam> <!-- additional params -->
<param name="local_position/frame_id" value="local_origin"/>
<param name="local_position/tf/send" value="true"/>
<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
- vibration
- rangefinder
- 3dr_radio
- actuator_control
- hil_controls
- vfr_hud
- vision_speed_estimate
- fake_gps
- cam_imu_sync
- hil
- adsb
- waypoint
- obstacle_distance
- setpoint_accel
- trajectory
- wind_estimation
</rosparam>
</node> </node>
<!-- Rangefinders frame -->
<node pkg="tf2_ros" type="static_transform_publisher" name="rangefinder_frame" args="0 0 -0.05 0 1.5707963268 0 fcu rangefinder"/>
<!-- Copter visualization --> <!-- Copter visualization -->
<include file="$(find clever)/launch/copter_visualization.launch" if="$(arg viz)"/> <node name="copter_visualization" pkg="mavros_extras" type="copter_visualization" if="$(arg viz)">
<remap to="mavros/local_position/pose" from="local_position"/>
<remap to="mavros/setpoint_position/local" from="local_setpoint"/>
<param name="fixed_frame_id" value="local_origin"/>
<param name="child_frame_id" value="fcu"/>
<param name="marker_scale" value="1"/>
<param name="max_track_size" value="20"/>
<param name="num_rotors" value="4"/>
</node>
</launch> </launch>

View File

@@ -7,11 +7,11 @@
<arg name="fcu_conn" value="udp"/> <arg name="fcu_conn" value="udp"/>
<arg name="fcu_ip" value="$(arg ip)"/> <arg name="fcu_ip" value="$(arg ip)"/>
<arg name="gcs_bridge" value="false"/> <arg name="gcs_bridge" value="false"/>
<arg name="optical_flow" value="false"/>
<arg name="web_server" default="false"/>
<arg name="web_video_server" default="false"/> <arg name="web_video_server" default="false"/>
<arg name="main_camera" default="false"/> <arg name="main_camera" default="false"/>
<arg name="fpv_camera" default="false"/>
<arg name="rosbridge" value="$(arg rosbridge)"/> <arg name="rosbridge" value="$(arg rosbridge)"/>
<arg name="web_server" default="false"/>
<arg name="aruco" default="false"/> <arg name="aruco" default="false"/>
</include> </include>
</launch> </launch>

View File

@@ -1,5 +0,0 @@
<launch>
<node name="web_server" pkg="clever" type="web_server.py" output="screen">
<param name="path" value="$(find clever)/static"/>
</node>
</launch>

View File

@@ -1,3 +1,8 @@
<library path="lib/libclever">
<class name="clever/optical_flow" type="OpticalFlow" base_class_type="nodelet::Nodelet">
<description/>
</class>
</library>
<library path="lib/libfcu_horiz"> <library path="lib/libfcu_horiz">
<class name="clever/fcu_horiz" type="FcuHoriz" base_class_type="nodelet::Nodelet"> <class name="clever/fcu_horiz" type="FcuHoriz" base_class_type="nodelet::Nodelet">
<description/> <description/>

View File

@@ -0,0 +1,101 @@
/*
* Visualization marker for camera alignment
* Copyright (C) 2018 Copter Express Technologies
*
* Author: Oleg Kalachev <okalachev@gmail.com>
*
* Distributed under MIT License (available at https://opensource.org/licenses/MIT).
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/
#include <string>
#include <ros/ros.h>
#include <sensor_msgs/CameraInfo.h>
#include <visualization_msgs/Marker.h>
#include <visualization_msgs/MarkerArray.h>
using namespace visualization_msgs;
double markers_scale;
std::string camera_frame;
MarkerArray createMarkers() {
MarkerArray markers;
Marker lens;
lens.header.frame_id = camera_frame;
lens.ns = "camera_markers";
lens.id = 0;
lens.action = Marker::ADD;
lens.type = visualization_msgs::Marker::CYLINDER;
lens.frame_locked = true;
lens.scale.x = 0.013 * markers_scale;
lens.scale.y = 0.013 * markers_scale;
lens.scale.z = 0.015 * markers_scale;
lens.color.r = 0.3;
lens.color.g = 0.3;
lens.color.b = 0.3;
lens.color.a = 0.9;
lens.pose.position.z = 0.0075 * markers_scale;
lens.pose.orientation.w = 1;
Marker board;
board.header.frame_id = camera_frame;
board.ns = "camera_markers";
board.id = 1;
board.action = Marker::ADD;
board.type = Marker::CUBE;
board.frame_locked = true;
board.scale.x = 0.024 * markers_scale;
board.scale.y = 0.024 * markers_scale;
board.scale.z = 0.001 * markers_scale;
board.color.r = 0.0;
board.color.g = 0.8;
board.color.b = 0.0;
board.color.a = 0.9;
board.pose.orientation.w = 1;
Marker wire;
wire.header.frame_id = camera_frame;
wire.ns = "camera_markers";
wire.id = 2;
wire.action = Marker::ADD;
wire.type = Marker::CUBE;
wire.frame_locked = true;
wire.scale.x = 0.014 * markers_scale;
wire.scale.y = 0.04 * markers_scale;
wire.scale.z = 0.001 * markers_scale;
wire.color.r = 0.9;
wire.color.g = 0.9;
wire.color.b = 1.0;
wire.color.a = 0.8;
wire.pose.position.x = 0;
wire.pose.position.y = (0.01 + 0.02) * markers_scale;
wire.pose.position.z = 0.002 * markers_scale;
wire.pose.orientation.w = 1;
markers.markers.push_back(lens);
markers.markers.push_back(board);
markers.markers.push_back(wire);
return markers;
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "camera_markers", ros::init_options::AnonymousName);
ros::NodeHandle nh, nh_priv("~");
nh_priv.param("scale", markers_scale, 1.0);
// wait for camera info
auto camera_info = ros::topic::waitForMessage<sensor_msgs::CameraInfo>("camera_info", nh);
camera_frame = camera_info->header.frame_id;
ros::Publisher markers_pub = nh.advertise<visualization_msgs::MarkerArray>("camera_markers", 1, true);
markers_pub.publish(createMarkers());
ROS_INFO("Camera markers initialized");
ros::spin();
}

85
clever/src/interactive.py Executable file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python
import copy
import rospy
import tf.transformations as t
from interactive_markers.interactive_marker_server import InteractiveMarkerServer
from visualization_msgs.msg import Marker, InteractiveMarker, InteractiveMarkerControl, InteractiveMarkerFeedback
from clever import srv
def make_box(msg):
marker = Marker()
marker.type = Marker.CUBE
marker.scale.x = msg.scale * 0.3
marker.scale.y = msg.scale * 0.3
marker.scale.z = msg.scale * 0.3
marker.color.r = 0.5
marker.color.g = 0.5
marker.color.b = 0.5
marker.color.a = 1.0
marker.pose.orientation.w = 1
return marker
def make_box_control(msg):
control = InteractiveMarkerControl()
control.always_visible = True
control.orientation.w = 1
control.markers.append(make_box(msg))
msg.controls.append(control)
return control
def make_quadcopter_marker():
marker = InteractiveMarker()
marker.header.frame_id = 'fcu'
marker.header.stamp = rospy.get_rostime()
marker.scale = 1
marker.pose.orientation.w = 1
marker.name = 'quadcopter'
marker.description = 'Quadcopter'
make_box_control(marker)
control = InteractiveMarkerControl()
control.orientation.w = 1
control.orientation.x = 0
control.orientation.y = 1
control.orientation.z = 0
control.interaction_mode = InteractiveMarkerControl.MOVE_ROTATE
marker.controls.append(copy.deepcopy(control))
control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
marker.controls.append(control)
return marker
navigate = rospy.ServiceProxy('navigate', srv.Navigate)
def process_feedback(feedback):
if feedback.event_type != InteractiveMarkerFeedback.MOUSE_UP:
return
p = feedback.pose.position
o = feedback.pose.orientation
yaw = t.euler_from_quaternion((o.x, o.y, o.z, o.w), axes='rzyx')[0]
rospy.loginfo('Navigate to %s', p)
rospy.loginfo(navigate(x=p.x, y=p.y, z=p.z, yaw=yaw, speed=2,
frame_id=feedback.header.frame_id, auto_arm=True))
rospy.init_node('quadcopter_im')
server = InteractiveMarkerServer('quadcopter_im')
int_marker = make_quadcopter_marker()
server.insert(int_marker, process_feedback)
server.applyChanges()
rospy.loginfo('Interactive quadcopter marker initialized')
rospy.spin()

3
clever/src/monkey Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
exec /home/pi/monkey/build/monkey --port 80 --workers 1

200
clever/src/optical_flow.cpp Normal file
View File

@@ -0,0 +1,200 @@
/*
* Optical Flow node for PX4
* Copyright (C) 2018 Copter Express Technologies
*
* Author: Oleg Kalachev <okalachev@gmail.com>
*
* Distributed under MIT License (available at https://opensource.org/licenses/MIT).
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/
#include <vector>
#include <cmath>
#include <nodelet/nodelet.h>
#include <pluginlib/class_list_macros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <opencv2/opencv.hpp>
#include <tf/transform_datatypes.h>
#include <tf2/exceptions.h>
#include <tf2/convert.h>
#include <tf2_ros/transform_listener.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
#include <mavros_msgs/OpticalFlowRad.h>
#include <sensor_msgs/Imu.h>
#include <geometry_msgs/Vector3Stamped.h>
#include <geometry_msgs/PointStamped.h>
#include <geometry_msgs/TwistStamped.h>
using cv::Mat;
class OpticalFlow : public nodelet::Nodelet
{
public:
OpticalFlow():
camera_matrix_(3, 3, CV_64F),
dist_coeffs_(8, 1, CV_64F),
tf_listener_(tf_buffer_)
{}
private:
ros::Publisher flow_pub_, velo_pub_, shift_pub_;
ros::Time prev_stamp_;
std::string fcu_frame_id_;
image_transport::CameraSubscriber img_sub_;
image_transport::Publisher img_pub_;
mavros_msgs::OpticalFlowRad flow_;
int roi_, roi_2_;
Mat hann_;
Mat prev_, curr_;
Mat camera_matrix_, dist_coeffs_;
tf2_ros::Buffer tf_buffer_;
tf2_ros::TransformListener tf_listener_;
void onInit()
{
ros::NodeHandle& nh = getNodeHandle();
ros::NodeHandle& nh_priv = getPrivateNodeHandle();
image_transport::ImageTransport it(nh);
image_transport::ImageTransport it_priv(nh_priv);
nh_priv.param<std::string>("mavros/local_position/tf/child_frame_id", fcu_frame_id_, "fcu");
nh_priv.param("roi", roi_, 128);
roi_2_ = roi_ / 2;
img_sub_ = it.subscribeCamera("image", 1, &OpticalFlow::flow, this);
img_pub_ = it_priv.advertise("debug", 1);
flow_pub_ = nh.advertise<mavros_msgs::OpticalFlowRad>("mavros/px4flow/raw/send", 1);
velo_pub_ = nh_priv.advertise<geometry_msgs::TwistStamped>("angular_velocity", 1);
shift_pub_ = nh_priv.advertise<geometry_msgs::Vector3Stamped>("shift", 1);
flow_.integrated_xgyro = NAN; // no IMU available
flow_.integrated_ygyro = NAN;
flow_.integrated_zgyro = NAN;
flow_.time_delta_distance_us = 0;
flow_.distance = -1; // no distance sensor available
flow_.temperature = 0;
ROS_INFO("Optical Flow initialized");
}
void parseCameraInfo(const sensor_msgs::CameraInfoConstPtr &cinfo) {
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
camera_matrix_.at<double>(i, j) = cinfo->K[3 * i + j];
}
}
for (int k = 0; k < cinfo->D.size(); k++) {
dist_coeffs_.at<double>(k) = cinfo->D[k];
}
}
void drawFlow(Mat& frame, double x, double y, double quality) const
{
double brightness = (1 - quality) * 25;;
cv::Scalar color(brightness, brightness, brightness);
double radius = std::sqrt(x * x + y * y);
// draw a circle and line indicating the shift direction...
cv::Point center(frame.cols >> 1, frame.rows >> 1);
cv::circle(frame, center, (int)(radius*5), color, 3, cv::LINE_AA);
cv::line(frame, center, cv::Point(center.x + (int)(x*5), center.y + (int)(y*5)), color, 3, cv::LINE_AA);
}
void flow(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& cinfo)
{
parseCameraInfo(cinfo);
auto img = cv_bridge::toCvShare(msg, "mono8")->image;
// Apply ROI
if (roi_ != 0) {
img = img(cv::Rect((msg->width / 2 - roi_2_), (msg->height / 2 - roi_2_), roi_, roi_));
}
img.convertTo(curr_, CV_64F);
if (prev_.empty()) {
prev_ = curr_.clone();
prev_stamp_ = msg->header.stamp;
cv::createHanningWindow(hann_, curr_.size(), CV_64F);
} else {
double response;
cv::Point2d shift = cv::phaseCorrelate(prev_, curr_, hann_, &response);
// Publish raw shift in pixels
static geometry_msgs::Vector3Stamped shift_vec;
shift_vec.header.stamp = msg->header.stamp;
shift_vec.header.frame_id = msg->header.frame_id;
shift_vec.vector.x = shift.x;
shift_vec.vector.y = shift.y;
shift_pub_.publish(shift_vec);
// Undistort flow in pixels
uint32_t flow_center_x = msg->width / 2;
uint32_t flow_center_y = msg->height / 2;
shift.x += flow_center_x;
shift.y += flow_center_y;
std::vector<cv::Point2d> points_dist = { shift };
std::vector<cv::Point2d> points_undist(1);
cv::undistortPoints(points_dist, points_undist, camera_matrix_, dist_coeffs_, cv::noArray(), camera_matrix_);
points_undist[0].x -= flow_center_x;
points_undist[0].y -= flow_center_y;
// Calculate flow in radians
double focal_length_x = camera_matrix_.at<double>(0, 0);
double focal_length_y = camera_matrix_.at<double>(1, 1);
double flow_x = atan2(points_undist[0].x, focal_length_x);
double flow_y = atan2(points_undist[0].y, focal_length_y);
// // Convert to FCU frame
static geometry_msgs::Vector3Stamped flow_camera, flow_fcu;
flow_camera.header.frame_id = msg->header.frame_id;
flow_camera.header.stamp = msg->header.stamp;
flow_camera.vector.x = flow_y; // +y means counter-clockwise rotation around Y axis
flow_camera.vector.y = -flow_x; // +x means clockwise rotation around X axis
tf_buffer_.transform(flow_camera, flow_fcu, fcu_frame_id_);
// Calculate integration time
ros::Duration integration_time = msg->header.stamp - prev_stamp_;
uint32_t integration_time_us = integration_time.toSec() * 1.0e6;
// Publish flow in fcu frame
flow_.header.stamp = /*prev_stamp_*/ msg->header.stamp;
flow_.integration_time_us = integration_time_us;
flow_.integrated_x = flow_fcu.vector.x;
flow_.integrated_y = flow_fcu.vector.y;
flow_.quality = (uint8_t)(response * 255);
flow_pub_.publish(flow_);
// Publish debug image
if (img_pub_.getNumSubscribers() > 0) {
// publish debug image
drawFlow(img, shift_vec.vector.x, shift_vec.vector.y, response);
cv_bridge::CvImage out_msg;
out_msg.header.frame_id = msg->header.frame_id;
out_msg.header.stamp = msg->header.stamp;
out_msg.encoding = sensor_msgs::image_encodings::MONO8;
out_msg.image = img;
img_pub_.publish(out_msg.toImageMsg());
}
// Publish estimated angular velocity
static geometry_msgs::TwistStamped velo;
velo.header.stamp = msg->header.stamp;
velo.header.frame_id = fcu_frame_id_;
velo.twist.angular.x = flow_.integrated_x / integration_time.toSec();
velo.twist.angular.y = flow_.integrated_y / integration_time.toSec();
velo_pub_.publish(velo);
prev_ = curr_.clone();
prev_stamp_ = msg->header.stamp;
}
}
};
PLUGINLIB_EXPORT_CLASS(OpticalFlow, nodelet::Nodelet)

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
import math
from subprocess import Popen, PIPE
import re
import traceback
import rospy import rospy
from std_srvs.srv import Trigger from std_srvs.srv import Trigger
from sensor_msgs.msg import Image, CameraInfo, NavSatFix, Imu from sensor_msgs.msg import Image, CameraInfo, NavSatFix, Imu
@@ -8,100 +12,160 @@ from geometry_msgs.msg import PoseStamped, TwistStamped
# TODO: roscore is running # TODO: roscore is running
# TODO: disk free space
# TODO: local_origin, fcu, fcu_horiz # TODO: local_origin, fcu, fcu_horiz
# TODO: rc service # TODO: rc service
# TODO: perform commander check in PX4 # TODO: perform commander check in PX4
# TODO: check if FCU params setter succeed
# TODO: selfcheck ROS service (with blacklists for checks)
rospy.init_node('selfcheck') rospy.init_node('selfcheck')
failures = []
def failure(text, *args):
failures.append(text % args)
def check(name):
def inner(fn):
def wrapper(*args, **kwargs):
failures[:] = []
try:
fn(*args, **kwargs)
for f in failures:
rospy.logwarn('%s: %s', name, f)
except Exception as e:
traceback.print_exc()
rospy.logwarn('%s: exception occured', name)
return
if not failures:
rospy.loginfo('%s: OK', name)
return wrapper
return inner
@check('FCU')
def check_fcu(): def check_fcu():
try: try:
state = rospy.wait_for_message('mavros/state', State, timeout=3) state = rospy.wait_for_message('mavros/state', State, timeout=3)
if not state.connected: if not state.connected:
raise Exception('No connection to the FCU') failure('No connection to the FCU')
except rospy.ROSException: except rospy.ROSException:
raise Exception('No MAVROS state') failure('No MAVROS state')
@check('Camera')
def check_camera(name): def check_camera(name):
try: try:
rospy.wait_for_message(name + '/image_raw', Image, timeout=3) rospy.wait_for_message(name + '/image_raw', Image, timeout=1)
except rospy.ROSException: except rospy.ROSException:
raise Exception('No %s camera images' % name) failure('No %s camera images' % name)
try: try:
rospy.wait_for_message(name + '/camera_info', CameraInfo, timeout=3) rospy.wait_for_message(name + '/camera_info', CameraInfo, timeout=3)
except rospy.ROSException: except rospy.ROSException:
raise Exception('No %s camera camera info' % name) failure('No %s camera camera info' % name)
@check('Aruco detector')
def check_aruco(): def check_aruco():
try: try:
rospy.wait_for_message('aruco_pose/debug', Image, timeout=3) rospy.wait_for_message('aruco_pose/debug', Image, timeout=1)
except rospy.ROSException: except rospy.ROSException:
raise Exception('No aruco_pose/debug topic') failure('No aruco_pose/debug messages')
@check('Simple offboard node')
def check_simpleoffboard(): def check_simpleoffboard():
try: try:
rospy.wait_for_service('navigate', timeout=3) rospy.wait_for_service('navigate', timeout=3)
rospy.wait_for_service('get_telemetry', timeout=3) rospy.wait_for_service('get_telemetry', timeout=3)
rospy.wait_for_service('land', timeout=3) rospy.wait_for_service('land', timeout=3)
except rospy.ROSException: except rospy.ROSException:
raise Exception('No simple_offboard services') failure('No simple_offboard services')
@check('IMU')
def check_imu(): def check_imu():
try: try:
rospy.wait_for_message('mavros/imu/data', Imu, timeout=3) rospy.wait_for_message('mavros/imu/data', Imu, timeout=1)
except rospy.ROSException: except rospy.ROSException:
raise Exception('No IMU data') failure('No IMU data')
@check('Local position')
def check_local_position(): def check_local_position():
try: try:
rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=3) rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=1)
except rospy.ROSException: except rospy.ROSException:
raise Exception('No local position') failure('No local position')
@check('Velocity estimation')
def check_velocity(): def check_velocity():
try: try:
velocity = rospy.wait_for_message('mavros/local_position/velocity', TwistStamped, timeout=3) velocity = rospy.wait_for_message('mavros/local_position/velocity', TwistStamped, timeout=1)
horiz = math.hypot(velocity.twist.linear.x, velocity.twist.linear.y) horiz = math.hypot(velocity.twist.linear.x, velocity.twist.linear.y)
vert = velocity.twist.linear.z vert = velocity.twist.linear.z
if abs(horiz) > 0.1: if abs(horiz) > 0.1:
raise Exception('Horizontal velocity estimation is %s m/s; is the copter staying still?' % horiz) failure('Horizontal velocity estimation is %s m/s; is the copter staying still?' % horiz)
if abs(vert) > 0.1: if abs(vert) > 0.1:
raise Exception('Vertical velocity estimation is %s m/s; is the copter staying still?' % vert) failure('Vertical velocity estimation is %s m/s; is the copter staying still?' % vert)
except rospy.ROSException: except rospy.ROSException:
raise Exception('No velocity estimation') failure('No velocity estimation')
@check('Global position (GPS)')
def check_global_position(): def check_global_position():
try: try:
rospy.wait_for_message('mavros/global_position/global', PoseStamped, timeout=3) rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=2)
except rospy.ROSException: except rospy.ROSException:
raise Exception('No global position') failure('No global position')
def check(name, fn): @check('Boot duration')
try: def check_boot_duration():
fn() proc = Popen('systemd-analyze', stdout=PIPE)
rospy.loginfo('%s: OK', name) proc.wait()
except BaseException as e: output = proc.communicate()[0]
rospy.logwarn('%s: %s', name, str(e)) r = re.compile(r'([\d\.]+)s$')
duration = float(r.search(output).groups()[0])
if duration > 15:
failure('long Raspbian boot duration: %ss', duration)
@check('CPU usage')
def check_cpu_usage():
WHITELIST = 'nodelet',
CMD = "top -n 1 -b -i | tail -n +8 | awk '{ printf(\"%-8s\\t%-8s\\t%-8s\\n\", $1, $9, $12); }'"
proc = Popen(CMD, stdout=PIPE, shell=True)
proc.wait()
output = proc.communicate()[0]
processes = output.split('\n')
for process in processes:
if not process:
continue
pid, cpu, cmd = process.split('\t')
if cmd.strip() not in WHITELIST and float(cpu) > 30:
failure('High CPU usage (%s%%) detected: %s (PID %s)',
cpu.strip(), cmd.strip(), pid.strip())
def selfcheck(): def selfcheck():
check('FCU', check_fcu) check_fcu()
check('Simple offboard node', check_simpleoffboard) check_imu()
check('Main camera node', lambda: check_camera('main_camera')) check_local_position()
check('aruco_pose/debug topic', check_aruco) check_velocity()
check('IMU data', check_imu) check_global_position()
check('Local position', check_local_position) check_camera('main_camera')
check('Velocity estimation', check_velocity) check_aruco()
check('Global position (GPS)', check_global_position) check_simpleoffboard()
check_cpu_usage()
check_boot_duration()
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -83,12 +83,13 @@ AUTO_ARM = AUTO_OFFBOARD and rospy.get_param('~auto_arm', True)
OFFBOARD_TIMEOUT = rospy.Duration(rospy.get_param('~offboard_timeout', 3)) OFFBOARD_TIMEOUT = rospy.Duration(rospy.get_param('~offboard_timeout', 3))
ARM_TIMEOUT = rospy.Duration(rospy.get_param('~arm_timeout', 5)) ARM_TIMEOUT = rospy.Duration(rospy.get_param('~arm_timeout', 5))
LOCAL_POSITION_TIMEOUT = rospy.Duration(rospy.get_param('~local_position_timeout', 0.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)) NAVIGATE_AFTER_ARMED = rospy.Duration(rospy.get_param('~navigate_after_armed', True))
TRANSFORM_TIMEOUT = rospy.Duration(rospy.get_param('~transform_timeout', 3)) TRANSFORM_TIMEOUT = rospy.Duration(rospy.get_param('~transform_timeout', 3))
SETPOINT_RATE = rospy.get_param('~setpoint_rate', 30) SETPOINT_RATE = rospy.get_param('~setpoint_rate', 30)
LOCAL_FRAME = rospy.get_param('~local_frame', 'local_origin') LOCAL_FRAME = rospy.get_param('~local_frame', 'local_origin')
LAND_MODE = rospy.get_param('~land_mode', 'AUTO.LAND') LAND_MODE = rospy.get_param('~land_mode', 'AUTO.LAND')
LAND_TIMEOUT = rospy.Duration(rospy.get_param('~land_timeout', 2)) LAND_TIMEOUT = rospy.Duration(rospy.get_param('~land_timeout', 2))
DEFAULT_SPEED = rospy.get_param('~default_speed', 0.5)
def offboard_and_arm(): def offboard_and_arm():
@@ -120,6 +121,8 @@ def offboard_and_arm():
ps = PoseStamped() ps = PoseStamped()
vs = Vector3Stamped() vs = Vector3Stamped()
pt = PositionTarget()
at = AttitudeTarget()
BRAKE_TIME = rospy.Duration(0) BRAKE_TIME = rospy.Duration(0)
@@ -164,7 +167,7 @@ def get_publisher_and_message(req, stamp, continued=True, update_frame=True):
if update_frame: if update_frame:
ps.header.frame_id = req.frame_id or LOCAL_FRAME 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.position = Point(getattr(req, 'x', 0), getattr(req, 'y', 0), req.z)
ps.pose.orientation = orientation_from_euler(0, 0, req.yaw) ps.pose.orientation = orientation_from_euler(0, 0, req.yaw, axes='sxyz')
current_nav_finish = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT) current_nav_finish = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT)
if isinstance(req, srv.NavigateGlobalRequest): if isinstance(req, srv.NavigateGlobalRequest):
@@ -183,13 +186,14 @@ def get_publisher_and_message(req, stamp, continued=True, update_frame=True):
current_nav_start_stamp, req.speed) current_nav_start_stamp, req.speed)
yaw_rate_flag = math.isnan(req.yaw) yaw_rate_flag = math.isnan(req.yaw)
msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED, msg = pt
type_mask=PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + msg.coordinate_frame = PT.FRAME_LOCAL_NED
PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + msg.type_mask = PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + \
(PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE), PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + \
position=setpoint, (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE)
yaw=euler_from_orientation(current_nav_finish.pose.orientation, 'szyx')[2] - math.pi / 2, msg.position = setpoint
yaw_rate=req.yaw_rate) msg.yaw = euler_from_orientation(current_nav_finish.pose.orientation, 'sxyz')[2]
msg.yaw_rate = req.yaw_rate
return position_pub, msg return position_pub, msg
elif isinstance(req, (srv.SetPositionRequest, srv.SetPositionGlobalRequest)): elif isinstance(req, (srv.SetPositionRequest, srv.SetPositionGlobalRequest)):
@@ -202,13 +206,14 @@ def get_publisher_and_message(req, stamp, continued=True, update_frame=True):
pose_local.pose.position.x, pose_local.pose.position.y = global_to_local(req.lat, req.lon) pose_local.pose.position.x, pose_local.pose.position.y = global_to_local(req.lat, req.lon)
yaw_rate_flag = math.isnan(req.yaw) yaw_rate_flag = math.isnan(req.yaw)
msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED, msg = pt
type_mask=PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + msg.coordinate_frame = PT.FRAME_LOCAL_NED
PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + msg.type_mask = PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + \
(PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE), PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + \
position=pose_local.pose.position, (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE)
yaw=euler_from_orientation(pose_local.pose.orientation, 'szyx')[2] - math.pi / 2, msg.position = pose_local.pose.position
yaw_rate=req.yaw_rate) msg.yaw = euler_from_orientation(pose_local.pose.orientation, 'sxyz')[2]
msg.yaw_rate = req.yaw_rate
return position_pub, msg return position_pub, msg
elif isinstance(req, srv.SetVelocityRequest): elif isinstance(req, srv.SetVelocityRequest):
@@ -220,28 +225,33 @@ def get_publisher_and_message(req, stamp, continued=True, update_frame=True):
vector_local = tf_buffer.transform(vs, LOCAL_FRAME, TRANSFORM_TIMEOUT) vector_local = tf_buffer.transform(vs, LOCAL_FRAME, TRANSFORM_TIMEOUT)
yaw_rate_flag = math.isnan(req.yaw) yaw_rate_flag = math.isnan(req.yaw)
msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED, msg = pt
type_mask=PT.IGNORE_PX + PT.IGNORE_PY + PT.IGNORE_PZ + msg.coordinate_frame = PT.FRAME_LOCAL_NED
PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + msg.type_mask = PT.IGNORE_PX + PT.IGNORE_PY + PT.IGNORE_PZ + \
(PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE), PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + \
velocity=vector_local.vector, (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE)
yaw=euler_from_orientation(pose_local.pose.orientation, 'szyx')[2] - math.pi / 2, msg.velocity = vector_local.vector
yaw_rate=req.yaw_rate) msg.yaw = euler_from_orientation(pose_local.pose.orientation, 'sxyz')[2]
msg.yaw_rate = req.yaw_rate
return position_pub, msg return position_pub, msg
elif isinstance(req, srv.SetAttitudeRequest): elif isinstance(req, srv.SetAttitudeRequest):
ps.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(req.roll, req.pitch, req.yaw) ps.pose.orientation = orientation_from_euler(req.roll, req.pitch, req.yaw)
pose_local = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT) pose_local = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT)
msg = AttitudeTarget(orientation=pose_local.pose.orientation, msg = at
thrust=req.thrust, msg.orientation = pose_local.pose.orientation
type_mask=AT.IGNORE_YAW_RATE + AT.IGNORE_PITCH_RATE + AT.IGNORE_ROLL_RATE) msg.thrust = req.thrust
msg.type_mask = AT.IGNORE_YAW_RATE + AT.IGNORE_PITCH_RATE + AT.IGNORE_ROLL_RATE
return attitude_pub, msg return attitude_pub, msg
elif isinstance(req, srv.SetRatesRequest): elif isinstance(req, srv.SetRatesRequest):
msg = AttitudeTarget(thrust=req.thrust, msg = at
type_mask=AttitudeTarget.IGNORE_ATTITUDE, msg.thrust = req.thrust
body_rate=Vector3(req.roll_rate, req.pitch_rate, req.yaw_rate)) msg.type_mask = AT.IGNORE_ATTITUDE
msg.body_rate.x = req.roll_rate
msg.body_rate.y = req.pitch_rate
msg.body_rate.z = req.yaw_rate
return attitude_pub, msg return attitude_pub, msg
@@ -261,9 +271,12 @@ def handle(req):
rospy.logwarn('No connection to the FCU') rospy.logwarn('No connection to the FCU')
return {'message': 'No connection to the FCU'} return {'message': 'No connection to the FCU'}
if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)) and req.speed <= 0: if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)):
rospy.logwarn('Navigate speed must be greater than zero, %s passed') if req.speed < 0:
return {'message': 'Navigate speed must be greater than zero, %s passed' % req.speed} rospy.logwarn('Navigate speed must be positive, %s passed')
return {'message': 'Navigate speed must be positive, %s passed' % req.speed}
elif req.speed == 0:
req.speed = DEFAULT_SPEED
if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)) and \ if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)) and \
(pose is None or rospy.get_rostime() - pose.header.stamp > LOCAL_POSITION_TIMEOUT): (pose is None or rospy.get_rostime() - pose.header.stamp > LOCAL_POSITION_TIMEOUT):
@@ -280,13 +293,13 @@ def handle(req):
try: try:
with handle_lock: with handle_lock:
stamp = rospy.get_rostime() stamp = rospy.get_rostime()
current_req = req current_req = req
current_pub, current_msg = get_publisher_and_message(req, stamp, False) current_pub, current_msg = get_publisher_and_message(req, stamp, False)
rospy.loginfo('Topic: %s, message: %s', current_pub.name, current_msg) rospy.loginfo('Topic: %s, message: %s', current_pub.name, current_msg)
current_msg.header.stamp = stamp current_msg.header.stamp = stamp
current_pub.publish(current_msg) current_pub.publish(current_msg)
if req.auto_arm: if req.auto_arm:
offboard_and_arm() offboard_and_arm()

View File

@@ -1,60 +0,0 @@
#!/usr/bin/env python
import rospy
import subprocess
import re
from flask import Flask, send_from_directory, send_file, request, jsonify
rospy.init_node('web_server', disable_signals=True)
port = rospy.get_param('~port', 7070)
host = rospy.get_param('~host', '0.0.0.0')
serve_path = rospy.get_param('~path')
app = Flask(__name__)
@app.route('/')
def serve_index():
return send_from_directory(serve_path, 'index.html')
@app.route('/<path:path>')
def serve_static(path):
print serve_path, path
return send_from_directory(serve_path, path)
@app.route('/wifi_data/')
def get_wifi_data():
cur_ip = request.remote_addr
ip_signal = get_ip_signal()
return jsonify({'ip': cur_ip, 'signal': ip_signal[cur_ip]}), 200
def get_ip_signal():
wlan_interface = 'wlan0'
# Getting info about wifi client connected to access point. From here we know MAC and signal level
iwl = subprocess.check_output(['sudo', 'iw', 'dev', 'wlan0', 'station', 'dump']).splitlines()
mac_signal = {}
cur_client = ''
for line in iwl:
if line.find('Station') != -1:
cur_client = re.search(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', line, re.I).group()
if line.find('signal') != -1:
sg = re.search(r'(\[-?\d*\])', line, re.I).group()
mac_signal[cur_client] = re.sub(r'[\[\]]', '', sg)
ip_signal = {}
# Getting ip-mac mapping
ip_mac = subprocess.check_output(['arp', '-i', wlan_interface]).splitlines()
for line in ip_mac:
mac = re.search(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', line, re.I)
if mac is not None:
mac = mac.group()
if mac in mac_signal:
ips = re.search(r'((2[0-5]|1[0-9]|[0-9])?[0-9]\.){3}((2[0-5]|1[0-9]|[0-9])?[0-9])', line, re.I).group()
ip_signal[ips] = mac_signal[mac]
return ip_signal
rospy.loginfo('Serving on %s:%s', host, port)
app.run(host=host, port=port, threaded=True)

13
clever/static/index.html Normal file
View File

@@ -0,0 +1,13 @@
<h1>CLEVER Drone Kit Tools</h1>
<ul>
<!-- <li><a href="">View user reference</a> (<a href="http://clever.copterexpress.com">http://clever.copterexpress.com</a> snapshot)</li> -->
<li><a href="" id="wvs">View image topics</a> (<code>web_video_server</code>)</li>
<li><a href="" id="butterfly">Open web terminal</a> (<code>Butterfly</code>)</li>
<!-- <li><a href="viz.html">View 3D visualization</a> (<code>ros3djs</code>)</li> -->
</ul>
<script type="text/javascript">
document.querySelector("#wvs").href = location.origin + ':8080';
document.querySelector("#butterfly").href = location.origin + ':57575';
</script>

6
deploy/butterfly.service Normal file
View File

@@ -0,0 +1,6 @@
[Unit]
Description=Butterfly Terminal Server
[Service]
ExecStart=/usr/local/bin/butterfly.server.py --host="0.0.0.0" --unsecure
User=pi

5
deploy/butterfly.socket Normal file
View File

@@ -0,0 +1,5 @@
[Socket]
ListenStream=57575
[Install]
WantedBy=sockets.target

57
deploy/monkey Normal file
View File

@@ -0,0 +1,57 @@
# Default Host - Configuration
# ============================
# Here the variable principals of the program are defined in respect
# to the configuration of the different types of directives.
[HOST]
# ServerName:
# -----------
# Allow you to set a host and domain name (e.g monkey.linuxchile.cl). If
# you are working in a local network just set your IP address or if you
# are working like localhost set your loopback address (127.0.0.1).
ServerName 0.0.0.0
# DocumentRoot:
# -------------
# This variable corresponds to the location of the main server directory
# of the web pages, where the files of your site are located.
#
# Example:
# DocumentRoot /home/krypton/htdocs
DocumentRoot /home/pi/catkin_ws/src/clever/clever/static
# Redirect:
# ---------
# Under specific conditions, you may want the server performs a HTTP
# redirect when this Virtual Host is reach. If that is the case, append
# to the Redirect key the value of the address where to redirect the
# HTTP client.
#
# Redirect http://monkey-project.com
[LOGGER]
# AccessLog:
# ----------
# Registration file of correct request.
AccessLog /home/pi/monkey/build/log/access.log
# ErrorLog:
# ---------
# Registration file of incorrect request.
ErrorLog /home/pi/monkey/build/log/error.log
[ERROR_PAGES]
404 404.html
[HANDLERS]
# FastCGI
# =======
# Match /.*\.php fastcgi
# CGI
# ===
# Match /cgi-bin/.*\.cgi cgi

View File

@@ -5,7 +5,7 @@
«Клевер» — это учебный конструктор программируемого квадрокоптера, состоящего из популярных открытых компонентов, а также набор необходимой документации и библиотек для работы с ним. «Клевер» — это учебный конструктор программируемого квадрокоптера, состоящего из популярных открытых компонентов, а также набор необходимой документации и библиотек для работы с ним.
Набор включает в себя полетный контроллер PixHawk/PixRacer с полетным стеком PX4, Raspberry Pi 3 в качестве управлящего бортового компьютера, модуль камеры для реализации полетов с использованием компьютерного зрения, а также набор различных датчиков и другой периферии. Набор включает в себя полетный контроллер 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)» и многие другие. На базе точно такой же платформы были созданы многие «большие» проекты компании Copter Express, например, дроны для [пиар-акций по автономной доставке пиццы](https://www.youtube.com/watch?v=hmkAoZOtF58) (Самара, Казань); дрон-доставщик кофе в Сколково, мониторинговый дрон с зарядной станцией, дроны-победители на полевых испытаниях «[Робокросс-2016](https://www.youtube.com/watch?v=dGbDaz_VmYU)», «[Робокросс-2017](https://youtu.be/AQnd2CRczbQ)» и многие другие.

View File

@@ -7,12 +7,13 @@
* [Полетные режимы](modes.md) * [Полетные режимы](modes.md)
* [Raspberry Pi](raspberry.md) * [Raspberry Pi](raspberry.md)
* [Образ операционной системы на RPi](microsd_images.md) * [Образ операционной системы на RPi](microsd_images.md)
* [Подключение Raspberry Pi к PixHawk](connection.md) * [Подключение Raspberry Pi к Pixhawk](connection.md)
* [Подключение по Wi-Fi](wifi.md) * [Подключение по Wi-Fi](wifi.md)
* [Работа с QGroundControl через Wi-Fi](gcs_bridge.md) * [Работа с QGroundControl через Wi-Fi](gcs_bridge.md)
* [Прошивка PixHawk/PixRacer](firmware.md) * [Прошивка Pixhawk/Pixracer](firmware.md)
* [Пилотирование со смартфона](rc.md) * [Пилотирование со смартфона](rc.md)
* [SSH-доступ](ssh.md) * [SSH-доступ](ssh.md)
* [Устройство UART](uart.md)
* [Неисправности радиоаппаратуры](radioerrors.md) * [Неисправности радиоаппаратуры](radioerrors.md)
* [Безопасность](safety.md) * [Безопасность](safety.md)
* [Техника безопасности по пайке](tb.md) * [Техника безопасности по пайке](tb.md)

View File

@@ -110,7 +110,7 @@ _Примечание_: указанное выше определение пр
Для правильной работы Vision Position Estimation необходимо \(через [QGroundControl](gcs_bridge.md)\) убедиться, что: Для правильной работы Vision Position Estimation необходимо \(через [QGroundControl](gcs_bridge.md)\) убедиться, что:
* Для PixHawk: Установлена прошивка с LPE \(local position estimator\). Для PixHawk необходимо [скачать прошивку `px4fmu-v2_lpe.px4`](https://github.com/PX4/Firmware/releases). Для PixRacer параметр `SYS_MC_EST_GROUP` должен быть установлен в `local_position_estimator, attitude_estimator_q`. * Для Pixhawk: Установлена прошивка с LPE \(local position estimator\). Для Pixhawk необходимо [скачать прошивку `px4fmu-v2_lpe.px4`](https://github.com/PX4/Firmware/releases). Для Pixracer параметр `SYS_MC_EST_GROUP` должен быть установлен в `local_position_estimator, attitude_estimator_q`.
* В параметре `LPE_FUSION` включены **только** флажки `vision position`, `vision yaw`, `land detector`. Итоговое значение _28_. * В параметре `LPE_FUSION` включены **только** флажки `vision position`, `vision yaw`, `land detector`. Итоговое значение _28_.
* Выключен компас: `ATT_W_MAG` = 0 * Выключен компас: `ATT_W_MAG` = 0
* Вес угла по рысканью по зрению: `ATT_W_EXT_HDG` = 0.5 * Вес угла по рысканью по зрению: `ATT_W_EXT_HDG` = 0.5

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

@@ -26,6 +26,6 @@
* ОС [Raspbian Jessie](https://www.raspberrypi.org/downloads/raspbian/) * ОС [Raspbian Jessie](https://www.raspberrypi.org/downloads/raspbian/)
* Фреймворк [ROS](ros.md) * Фреймворк [ROS](ros.md)
* Пакет [MAVROS](mavros.md) для связи с PixHawk по [MAVLink](mavlink.md) * Пакет [MAVROS](mavros.md) для связи с Pixhawk по [MAVLink](mavlink.md)
* Дополнительные пакеты ROS: web_video_server, usb_cam, rosbridge_suite и другие * Дополнительные пакеты ROS: web_video_server, usb_cam, rosbridge_suite и другие
* Пакет программ clever_bundle * Пакет программ clever_bundle

View File

@@ -1,7 +1,7 @@
Подключение PixHawk/PixRacer к Raspberry Pi Подключение Pixhawk/Pixracer к Raspberry Pi
=== ===
Для программирования [автономных полетов](simple_offboard.md), [работы с PixHawk по Wi-Fi](gcs_bridge.md), использования [веб-пульта](web_rc.md) и других функций необходимо подсоединить Raspberry Pi к PixHawk. Для программирования [автономных полетов](simple_offboard.md), [работы с Pixhawk по Wi-Fi](gcs_bridge.md), использования [веб-пульта](web_rc.md) и других функций необходимо подсоединить Raspberry Pi к Pixhawk.
Убедиться в работоспособности подключения, выполнив на Raspberry Pi: Убедиться в работоспособности подключения, выполнив на Raspberry Pi:
@@ -14,7 +14,7 @@ rostopic echo /mavros/state
Подключение по USB Подключение по USB
--- ---
Соедините PixHawk/PixRacer и Raspberry Pi micro-USB to USB кабелем. Соедините Pixhawk/Pixracer и Raspberry Pi micro-USB to USB кабелем.
Необходимо убедиться, что в launch-файле Клевера (`~/catkin_ws/src/clever/clever/launch/clever.launch`) тип подключения установлен на USB: Необходимо убедиться, что в launch-файле Клевера (`~/catkin_ws/src/clever/clever/launch/clever.launch`) тип подключения установлен на USB:
@@ -28,7 +28,7 @@ rostopic echo /mavros/state
sudo systemctl restart clever sudo systemctl restart clever
``` ```
> **Hint** Для корректной работы подключения Raspberry Pi и PixHawk по USB необходимо установить значение параметра `CBRK_USB_CHK` на 197848. > **Hint** Для корректной работы подключения Raspberry Pi и Pixhawk по USB необходимо установить значение параметра `CBRK_USB_CHK` на 197848.
Подключение по UART Подключение по UART
--- ---
@@ -47,7 +47,7 @@ TODO схема подключения
sudo systemctl restart clever sudo systemctl restart clever
``` ```
> **Hint** Для корректной работы подключения Raspberry Pi и PixHawk по UART необходимо установить значение параметра `SYS_COMPANION` на 921600. > **Hint** Для корректной работы подключения Raspberry Pi и Pixhawk по UART необходимо установить значение параметра `SYS_COMPANION` на 921600.
Подключение к SITL Подключение к SITL
--- ---

View File

@@ -1,16 +1,16 @@
Прошивка PixHawk / PixRacer Прошивка Pixhawk / Pixracer
=== ===
PixHawk или PixRacer можно прошить, используя QGroundControl или утилиты командной строки. Pixhawk или Pixracer можно прошить, используя QGroundControl или утилиты командной строки.
Различные варианты сборок стабильных прошивок PX4 можно скачать в разделе [Releases на GitHub](https://github.com/PX4/Firmware/releases). Различные варианты сборок стабильных прошивок PX4 можно скачать в разделе [Releases на GitHub](https://github.com/PX4/Firmware/releases).
В названии файла прошивки кодируется информации о целевой плате и варианте сборки. Примеры: В названии файла прошивки кодируется информации о целевой плате и варианте сборки. Примеры:
* `px4fmu-v2_default.px4` — прошивка для PixHawk с EKF2. * `px4fmu-v2_default.px4` — прошивка для Pixhawk с EKF2.
* `px4fmu-v2_lpe.px4` — прошивка для PixHawk с LPE. * `px4fmu-v2_lpe.px4` — прошивка для Pixhawk с LPE.
* `px4fmu-v4_default.px4` — прошивка для PixRacer с EKF2 и LPE (*Клевер 3*). * `px4fmu-v4_default.px4` — прошивка для Pixracer с EKF2 и LPE (*Клевер 3*).
* `px4fmu-v3_default.px4` — прошивка для более новых версий PixHawk (чип ревизии 3, см. илл. + Bootloader v5) с EKF2 и LPE. * `px4fmu-v3_default.px4` — прошивка для более новых версий Pixhawk (чип ревизии 3, см. илл. + Bootloader v5) с EKF2 и LPE.
![](assets/stmrev.jpg) ![](assets/stmrev.jpg)
@@ -19,9 +19,9 @@ PixHawk или PixRacer можно прошить, используя QGroundCon
QGroundControl QGroundControl
--- ---
В QGroundControl откройте раздел Firmware. **После** этого подключите PixHawk / PixRacer по USB. В QGroundControl откройте раздел Firmware. **После** этого подключите Pixhawk / Pixracer по USB.
Выберите PX4 Flight Stack. Для скачивания и загрузки стандартной прошивки (вариант с EKF2 для PixHawk) выберите пункт меню "Standard Version", для загрузки собственного файла прошивки выберите пункт "Custom firmware file...", затем нажмите OK. Выберите PX4 Flight Stack. Для скачивания и загрузки стандартной прошивки (вариант с EKF2 для Pixhawk) выберите пункт меню "Standard Version", для загрузки собственного файла прошивки выберите пункт "Custom firmware file...", затем нажмите OK.
> **Warning** Не отключайте USB-кабель до окончания процесса прошивки. > **Warning** Не отключайте USB-кабель до окончания процесса прошивки.
@@ -46,7 +46,7 @@ make px4fmu-v4_default upload
Где `px4fmu-v4_default` – требуемый вариант прошивки. Где `px4fmu-v4_default` – требуемый вариант прошивки.
Для загрузки прошивки `v3` в PixHawk может понадобиться команда `force_upload`: Для загрузки прошивки `v3` в Pixhawk может понадобиться команда `force_upload`:
``` ```
make px4fmu-v3_default force-upload make px4fmu-v3_default force-upload

View File

@@ -38,7 +38,7 @@
Мониторинг топиков в режиме реального времени Мониторинг топиков в режиме реального времени
--- ---
Для более новых версий платы PixHawk (`px4fmu-v3`), а также для плат PixRacer, в прошивку включен модуль `topic_listener`, который позволяет просматривать значения топиков в режиме реального времени (в том числе в полете). Для более новых версий платы Pixhawk (`px4fmu-v3`), а также для плат Pixracer, в прошивку включен модуль `topic_listener`, который позволяет просматривать значения топиков в режиме реального времени (в том числе в полете).
Для ее использования нужно выбрать вкладку Mavlink Console в QGroundControl: Для ее использования нужно выбрать вкладку Mavlink Console в QGroundControl:

View File

@@ -11,7 +11,7 @@
## Полетный контроллер / автопилот ## Полетный контроллер / автопилот
**1\.** Специализированная плата, спроектированная для управления мультикоптером, самолетом или другим аппаратом. Примеры: **1\.** Специализированная плата, спроектированная для управления мультикоптером, самолетом или другим аппаратом. Примеры:
PixHawk, Ardupilot, Naze32, CC3D. Pixhawk, Ardupilot, Naze32, CC3D.
**2\.** Программное обеспечение для платы управления мультикоптером. Примеры: PX4, APM, CleanFlight. **2\.** Программное обеспечение для платы управления мультикоптером. Примеры: PX4, APM, CleanFlight.
@@ -47,11 +47,11 @@ Armed состояние коптера готовности к полету
## PX4 ## PX4
Популярный полетный контроллер с открытым исходным кодом, работащий на платах PixHawk, PixRacer и других. PX4 рекомендуется для использования на Клевере. Популярный полетный контроллер с открытым исходным кодом, работащий на платах Pixhawk, Pixracer и других. PX4 рекомендуется для использования на Клевере.
## APM / ArduPilot ## APM / ArduPilot
Полетный контроллер с открытым исходным кодом, изначально созданный для платы Arduino. Впоследствии был портирован на PixHawk, PixRacer и другие платы. Полетный контроллер с открытым исходным кодом, изначально созданный для платы Arduino. Впоследствии был портирован на Pixhawk, Pixracer и другие платы.
## MAVLink ## MAVLink
@@ -64,3 +64,7 @@ Armed состояние коптера готовности к полету
## MAVROS ## MAVROS
Библиотека-связующее звено между аппаратом, работающем по протоколу MAVLink, и ROS. Библиотека-связующее звено между аппаратом, работающем по протоколу MAVLink, и ROS.
## UART
Последовательный асинхронный интерфейс передачи данных, применяемый во многих устройствах. Например GPS антенны, Wi-Fi роутеры или Pixhawk.

View File

@@ -2,7 +2,7 @@
Основная документация: https://mavlink.io/en/. Основная документация: https://mavlink.io/en/.
MAVLink – это протокол для организации связи между автономными летательными и транспортными системами (дронами, самолетами, автомобилями). Проктол MAVLink лежит в основе взаимодействия между PixHawk и Raspberry Pi. MAVLink – это протокол для организации связи между автономными летательными и транспортными системами (дронами, самолетами, автомобилями). Проктол MAVLink лежит в основе взаимодействия между Pixhawk и Raspberry Pi.
В Клевер включено 2 обертки над этим протоколом: [MAVROS](mavros.md) и [simple_offboard](simple_offboard.md). В Клевер включено 2 обертки над этим протоколом: [MAVROS](mavros.md) и [simple_offboard](simple_offboard.md).

View File

@@ -8,7 +8,9 @@ MAVROS подписывается определенные ROS-топики в
Нода MAVROS автоматически запускается в launch-файле Клевера. Для [настройки типа подключения](connection.md) см. аргумент `fcu_conn`. Нода MAVROS автоматически запускается в launch-файле Клевера. Для [настройки типа подключения](connection.md) см. аргумент `fcu_conn`.
> **Note** Упрощенное взаимодействие с коптером возможно с использованием пакета [`simple_offboard`](simple_offboard.md). > **Hint** Упрощенное взаимодействие с коптером возможно с использованием пакета [`simple_offboard`](simple_offboard.md).
> **Note** В пакете `clever` некоторые плагины MAVROS отключены (в целях сохранения ресурсов). Подробнее см. параметр `plugin_blacklist` в файле `/home/pi/catkin_ws/src/clever/clever/launch/mavros.launch`.
## Основные сервисы ## Основные сервисы

View File

@@ -50,7 +50,7 @@
**Подведение итогов** **Подведение итогов**
Ниже предложен один из вариантов подведения итогов курса. Ниже предложен один из вариантов подведения итогов курса.
Финальное мероприятие включает 3 раздела: Финальное мероприятие включает 3 раздела:
@@ -155,7 +155,7 @@
| 5 | Заключение | Подвести итоги занятия, спросить, есть ли у класса вопросы. Спросить, что из изученного на занятии было для них интереснее всего. Попросить учеников ответить на контрольные вопросы. Предложить ученикам по желанию провести в интернете дополнительное исследование на пройденную тему. Сообщить ученикам, какую тему они будут проходить на следующем занятии. | | 5 | Заключение | Подвести итоги занятия, спросить, есть ли у класса вопросы. Спросить, что из изученного на занятии было для них интереснее всего. Попросить учеников ответить на контрольные вопросы. Предложить ученикам по желанию провести в интернете дополнительное исследование на пройденную тему. Сообщить ученикам, какую тему они будут проходить на следующем занятии. |
| 6 | Резервное время | Показать видео и рассказать классу интересные факты по пройденной теме, не вошедшие в программу. | | 6 | Резервное время | Показать видео и рассказать классу интересные факты по пройденной теме, не вошедшие в программу. |
## Урок №6. Тема: «Бесколлекторные двигатели и регуляторы их хода» ## Урок №6. Тема: «Бесколлекторные двигатели и регуляторы их хода»
**Цель урока:** закрепить теоретические знания о строении и работе бесколлекторных **Цель урока:** закрепить теоретические знания о строении и работе бесколлекторных
электродвигателей. Сформировать знания о работе и настройке регуляторов хода, электродвигателей. Сформировать знания о работе и настройке регуляторов хода,
@@ -381,7 +381,7 @@
| 5 | Меняем SSID | Рассказать, что такое SSID. Научить изменять имя wi-fi сети. Объяснить что такое демоны и в какой момент они запускаются. Проработать с конфигурацией одного из них. | | 5 | Меняем SSID | Рассказать, что такое SSID. Научить изменять имя wi-fi сети. Объяснить что такое демоны и в какой момент они запускаются. Проработать с конфигурацией одного из них. |
| 6 | Используем права суперпользователя | Рассказать о типах и правах пользователей системы. Показать примеры использования sudo. | | 6 | Используем права суперпользователя | Рассказать о типах и правах пользователей системы. Показать примеры использования sudo. |
| 7 | Подготовка коптера к автономным полетам | Проверить подключенное оборудование для автономных полетов. Убедиться в работоспособности подключения можно выполнив на Raspberry Pi: rostopic echo /mavros/state | | 7 | Подготовка коптера к автономным полетам | Проверить подключенное оборудование для автономных полетов. Убедиться в работоспособности подключения можно выполнив на Raspberry Pi: rostopic echo /mavros/state |
| 8 | Использование QGroundControl через Wi-Fi | Настроить беспроводное соединение для работы с PixHawk в QGroundControl. Предложить учащимся установить новую прошивку, которая подходит для автономных полетов и откалибровать коптер при беспроводном подключении. | | 8 | Использование QGroundControl через Wi-Fi | Настроить беспроводное соединение для работы с Pixhawk в QGroundControl. Предложить учащимся установить новую прошивку, которая подходит для автономных полетов и откалибровать коптер при беспроводном подключении. |
| 9 | Заключение | Подвести итоги занятия, спросить, есть ли у класса вопросы, их должно быть много, нужно заранее продумать ответы на них. Попросить учеников ответить на контрольные вопросы. Предложить ученикам по желанию провести в интернете дополнительное исследование на пройденную тему. Сообщить ученикам, какую тему они будут проходить на следующем занятии.| | 9 | Заключение | Подвести итоги занятия, спросить, есть ли у класса вопросы, их должно быть много, нужно заранее продумать ответы на них. Попросить учеников ответить на контрольные вопросы. Предложить ученикам по желанию провести в интернете дополнительное исследование на пройденную тему. Сообщить ученикам, какую тему они будут проходить на следующем занятии.|
| 10 | | | | 10 | | |

View File

@@ -19,4 +19,4 @@ Raspberry Pi означает «малиновый пирог». Этот сво
* домашний медиа-сервер * домашний медиа-сервер
* «мозговой центр» для автоматизированных станков или роботов * «мозговой центр» для автоматизированных станков или роботов
Собственно, в последнем качестве мы и будем его использовать, благодаря возможности подключения его к автопилоту PixHawk. Собственно, в последнем качестве мы и будем его использовать, благодаря возможности подключения его к автопилоту Pixhawk.

View File

@@ -53,4 +53,4 @@ sudo systemctl restart clever
* Если интерфейс пульта отображает явно неправильное напряжение (напр. > 5 V), проверьте, что значение PX4-параметра `BAT_N_CELLS` соответствует реальному количество элементов батареи. Если отображаемое напряжение все равно неверно, откалибруйте батарею (TODO: ссылка). * Если интерфейс пульта отображает явно неправильное напряжение (напр. > 5 V), проверьте, что значение PX4-параметра `BAT_N_CELLS` соответствует реальному количество элементов батареи. Если отображаемое напряжение все равно неверно, откалибруйте батарею (TODO: ссылка).
* Если вместо режима PX4 отображается текст "DISCONNECTED FROM FCU", проверьте [подключение Raspberry Pi к PixHawk](connection.md). * Если вместо режима PX4 отображается текст "DISCONNECTED FROM FCU", проверьте [подключение Raspberry Pi к Pixhawk](connection.md).

View File

@@ -30,3 +30,9 @@ export ROS_IP=192.168.11.1
В качестве reference frame рекомендуется установить фрейм `local_origin`. Для визуализации коптера можно добавить визуализационные маркеры из топика `/vehicle_markers`. Можно просмотреть картинку с дополненной реальностью из топика основной камеры `/main_camera/image_raw`. В качестве reference frame рекомендуется установить фрейм `local_origin`. Для визуализации коптера можно добавить визуализационные маркеры из топика `/vehicle_markers`. Можно просмотреть картинку с дополненной реальностью из топика основной камеры `/main_camera/image_raw`.
Axis или Grid настроенный на фрейм `aruco_map` будут визуализировать расположение [карты ArUco-меток](aruco.md). Axis или Grid настроенный на фрейм `aruco_map` будут визуализировать расположение [карты ArUco-меток](aruco.md).
Рекомендуется также установка набора дополнительных полезных плагинов [jsk_rviz_plugins](https://jsk-docs.readthedocs.io/en/latest/jsk_visualization/doc/jsk_rviz_plugins/index.html). Это набор позволяет визуализировать топики типа `TwistStamped` (скорость), `CameraInfo`, `PolygonArray` и многое другое. Для установки используйте команду:
```bash
sudo apt-get install ros-kinetic-jsk-visualization
```

View File

@@ -282,4 +282,4 @@
Далее: [Настройка-полетного-контролера](aruco.md#Настройка-полетного-контролера) Далее: [Настройка-полетного-контролера](aruco.md#Настройка-полетного-контролера)
Далее: [Подключение Raspberry Pi к PixHawk](connection.md). Далее: [Подключение Raspberry Pi к Pixhawk](connection.md).

View File

@@ -160,7 +160,7 @@ navigate(x=3, y=2, z=2, speed=1, frame_id='aruco_map', update_frame=True)
Вращение на месте со скоростью 0.5 рад/c (против часовой): Вращение на месте со скоростью 0.5 рад/c (против часовой):
```python ```python
navigate(x=0, y=0, z=0, speed=1, yaw=float('nan'), yaw_rate=0.5, frame_id='fcu_horiz') navigate(x=0, y=0, z=0, yaw=float('nan'), yaw_rate=0.5, frame_id='fcu_horiz')
``` ```
Полет вперед 3 метра со скоростью 0.5 м/с, вращаясь по рысканью со скоростью 0.2 рад/с: Полет вперед 3 метра со скоростью 0.5 м/с, вращаясь по рысканью со скоростью 0.2 рад/с:

View File

@@ -71,16 +71,29 @@ while True:
rospy.sleep(0.2) rospy.sleep(0.2)
``` ```
--
Определение, перевернут ли коптер:
```python
PI_2 = math.pi / 2
telem = get_telemetry()
flipped = not -PI_2 <= telem.pitch <= PI_2 or not -PI_2 <= telem.roll <= PI_2
```
--- ---
Рассчет общего угла коптера к горизонту: Рассчет общего угла коптера к горизонту:
TODO: fix
```python ```python
PI_2 = math.pi / 2
telem = get_telemetry() telem = get_telemetry()
flipped = not -PI_2 <= telem.pitch <= PI_2 or not -PI_2 <= telem.roll <= PI_2
angle_to_horizon = math.atan(math.hypot(math.tan(telem.pitch), math.tan(telem.roll))) angle_to_horizon = math.atan(math.hypot(math.tan(telem.pitch), math.tan(telem.roll)))
if flipped:
angle_to_horizon = math.pi - angle_to_horizon
``` ```
--- ---
@@ -107,6 +120,17 @@ while not rospy.is_shutdown():
--- ---
Повторять действие с частотой 10 Гц:
```python
r = rospy.Rate(10)
while not rospy.is_shutdown():
# Do anything
r.sleep()
```
---
Пример подписки на топики из MAVROS: Пример подписки на топики из MAVROS:

85
docs/uart.md Normal file
View File

@@ -0,0 +1,85 @@
# Интерфейс UART
UART последовательный асинхронный интерфейс для передачи данных, применяемый во многих устройствах. Например GPS-антенны, Wi-Fi роутеры или Pixhawk.
Интерфейс обычно содержит две линии: TX линия для передачи данных, RX линия для приёма данных. А также обычно использует 5-ти вольтовую логику.
Для соединения двух устройств необходимо линию TX первого устройства подать на RX второго. Аналогичную операцию нужно совершить с другой стороны, чтобы обеспечить двустороннюю передачу данных.
> Также необходимо синхронизировать уровни напряжений – соединить землю на двух устройствах.
Почитать больше про интерфейс и протокол можно в [этой статье](https://habr.com/post/109395/).
## Linux TTY
В Linux есть понятие Posix Terminal Interface (подробнее [здесь](https://ru.wikipedia.org/wiki/TTY-абстракция)). Это некоторая абстракция над последовательным или виртуальным интерфейсом, позволяющая работать с устройством нескольким агентам одновременно.
В качестве примера такой абстрации в Raspbian можно привести `/dev/tty1` устройство вывода текста на экран подключенный по HDMI.
## UART на Raspberry Pi 3
В Raspberry Pi 3 есть два аппаратных UART интерфейса:
1. `Mini UART` (/dev/ttyAMA0) для своей работы использует тактирование видеоядра RPi, в связи с чем ограничивает его частоту.
2. `PL011` (/dev/ttyS0) полноценный UART интерфейс выполненный на отдельном блоке кристалла микроконтроллера.
Подробнее про UART на Raspberry Pi в [официальной статье](https://www.raspberrypi.org/documentation/configuration/uart.md).
Данные интерфейсы с помощью вентелей микроконтроллера можно переключать между двуями физическими выходами:
1. разъём UART на GPIO;
2. Bluetooth модуль RPi.
По умолчанию в Raspberry Pi 3 `PL011` подключен к Bluetooth модулю. А `Mini UART` отключен с помощью значения директивы `enable_uart`, по дефолту равной `0`.
> Надо понимать, что директива `enable_uart` меняет свое дефолтное значение исходя из того, какой UART подключен к Bluetooth модулю RPi с помощью директивы `dtoverlay=pi3-miniuart-bt`.
Для удобства работы с этими выходами в Raspbian существуют алиасы:
* `/dev/serial0` всегда указывает на то TTY устройство, что подключено к GPIO портам.
* `/dev/serial1` всегда указывает на то TTY устройство, что подключено к Bluetooh модулю.
### Настройка UART на Raspberry Pi
Для настроек UART существуют директивы, которые находятся в `/boot/config.txt`.
Для включения UART интерфейса на GPIO:
```
enable_uart=1
```
Для отключения UART интерфейса от Bluetooth модуля:
```
dtoverlay=pi3-disable-bt
```
Для подключения `Mini UART` к Bluetooth модулю:
```
dtoverlay=pi3-miniuart-bt
```
В случае отключения Bluetooth модуля следует отключить `hciuart` сервис:
```bash
sudo systemctl disable hciuart.service
```
## Дефолтная настройка образа
На образе CLEVER мы изначально выключили `Mini UART` и Bluetooth модуль.
## Bugs
Если использовать подключение `Mini UART` к Bluetooth, `hciuart` падает с ошибкой:
![hciuart error](assets/hciuart_error.jpg)
В случае отключения Bluetooth
```
/dev/serial0 -> ttyAMA0
/dev/serial1 -> ttyS0
```

View File

@@ -7,7 +7,7 @@ pipeline {
string(name: 'BUILD_DIR', defaultValue: '/mnt/hdd_builder/workspace', description: 'Build workspace') string(name: 'BUILD_DIR', defaultValue: '/mnt/hdd_builder/workspace', description: 'Build workspace')
string(name: 'RPI_DONWLOAD_URL', defaultValue: 'https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2017-12-01/2017-11-29-raspbian-stretch-lite.zip') string(name: 'RPI_DONWLOAD_URL', defaultValue: 'http://director.downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2018-06-29/2018-06-27-raspbian-stretch-lite.zip')
// TODO: Add mirrorparameters // TODO: Add mirrorparameters
string(name: 'GWBT_URL', defaultValue: 'https://github.com/CopterExpress/clever.git') string(name: 'GWBT_URL', defaultValue: 'https://github.com/CopterExpress/clever.git')

View File

@@ -676,5 +676,5 @@
version: vision_opencv-release-release-kinetic-cv_bridge-1.12.8-0 version: vision_opencv-release-release-kinetic-cv_bridge-1.12.8-0
- tar: - tar:
local-name: web_video_server local-name: web_video_server
uri: https://github.com/RobotWebTools-release/web_video_server-release/archive/release/kinetic/web_video_server/0.0.7-0.tar.gz uri: https://github.com/RobotWebTools-release/web_video_server-release/archive/release/kinetic/web_video_server/0.1.0-0.tar.gz
version: web_video_server-release-release-kinetic-web_video_server-0.0.7-0 version: web_video_server-release-release-kinetic-web_video_server-0.1.0-0

View File

@@ -38,7 +38,8 @@ echo -e "\033[0;31m\033[1m$(date) | #6 Turn on UART\033[0m\033[0m"
# https://github.com/RPi-Distro/raspi-config/pull/75 # https://github.com/RPi-Distro/raspi-config/pull/75
/usr/bin/raspi-config nonint do_serial 1 /usr/bin/raspi-config nonint do_serial 1
/usr/bin/raspi-config nonint set_config_var enable_uart 1 /boot/config.txt /usr/bin/raspi-config nonint set_config_var enable_uart 1 /boot/config.txt
/usr/bin/raspi-config nonint set_config_var dtoverlay pi3-miniuart-bt /boot/config.txt /usr/bin/raspi-config nonint set_config_var dtoverlay pi3-disable-bt /boot/config.txt
systemctl disable hciuart.service
# After adding to Raspbian OS # After adding to Raspbian OS
# https://github.com/RPi-Distro/raspi-config/commit/d6d9ecc0d9cbe4aaa9744ae733b9cb239e79c116 # https://github.com/RPi-Distro/raspi-config/commit/d6d9ecc0d9cbe4aaa9744ae733b9cb239e79c116

View File

@@ -28,4 +28,11 @@ echo "$1" >> /etc/clever_version
# Origin image file name # Origin image file name
echo "${2%.*}" >> /etc/clever_origin echo "${2%.*}" >> /etc/clever_origin
echo -e "\033[0;31m\033[1m$(date) | #3 End initialisation of image\033[0m\033[0m"
echo -e "\033[0;31m\033[1m$(date) | #3 Set max space for syslogs\033[0m\033[0m"
# https://unix.stackexchange.com/questions/139513/how-to-clear-journalctl
sed -i 's/#SystemMaxUse=/SystemMaxUse=200M/' /etc/systemd/journald.conf
echo -e "\033[0;31m\033[1m$(date) | #4 End initialisation of image\033[0m\033[0m"

View File

@@ -55,7 +55,7 @@ then
cd /home/pi/ros_catkin_ws \ cd /home/pi/ros_catkin_ws \
&& rosinstall_generator \ && rosinstall_generator \
actionlib actionlib_msgs angles async_web_server_cpp bond bond_core bondcpp bondpy camera_calibration_parsers camera_info_manager catkin class_loader cmake_modules cpp_common cv_bridge cv_camera diagnostic_msgs diagnostic_updater dynamic_reconfigure eigen_conversions gencpp geneus genlisp genmsg gennodejs genpy geographic_msgs geometry_msgs geometry2 image_transport libmavconn mavlink mavros_msgs message_filters message_generation message_runtime mk nav_msgs nodelet orocos_kdl pluginlib python_orocos_kdl ros ros_comm rosapi rosauth rosbag rosbag_migration_rule rosbag_storage rosbash rosboost_cfg rosbridge_library rosbridge_server rosbridge_suite rosbuild rosclean rosconsole rosconsole_bridge roscpp roscpp_serialization roscpp_traits roscreate rosgraph rosgraph_msgs roslang roslaunch roslib roslint roslisp roslz4 rosmake rosmaster rosmsg rosnode rosout rospack rosparam rospy rospy_tutorials rosserial rosserial_client rosserial_msgs rosserial_python rosservice rostest rostime rostopic rosunit roswtf sensor_msgs smclib std_msgs std_srvs stereo_msgs tf tf2 tf2_bullet tf2_eigen tf2_geometry_msgs tf2_kdl tf2_msgs tf2_py tf2_ros tf2_sensor_msgs tf2_tools topic_tools trajectory_msgs urdf urdf_parser_plugin usb_cam uuid_msgs visualization_msgs web_video_server xmlrpcpp mavros opencv3 mavros_extras \ actionlib actionlib_msgs angles async_web_server_cpp bond bond_core bondcpp bondpy camera_calibration_parsers camera_info_manager catkin class_loader cmake_modules cpp_common cv_bridge cv_camera diagnostic_msgs diagnostic_updater dynamic_reconfigure eigen_conversions gencpp geneus genlisp genmsg gennodejs genpy geographic_msgs geometry_msgs geometry2 image_transport compressed_image_transport libmavconn mavlink mavros_msgs message_filters message_generation message_runtime mk nav_msgs nodelet orocos_kdl pluginlib python_orocos_kdl ros ros_comm rosapi rosauth rosbag rosbag_migration_rule rosbag_storage rosbash rosboost_cfg rosbridge_library rosbridge_server rosbridge_suite rosbuild rosclean rosconsole rosconsole_bridge roscpp roscpp_serialization roscpp_traits roscreate rosgraph rosgraph_msgs roslang roslaunch roslib roslint roslisp roslz4 rosmake rosmaster rosmsg rosnode rosout rospack rosparam rospy rospy_tutorials rosserial rosserial_client rosserial_msgs rosserial_python rosservice rostest rostime rostopic rosunit roswtf sensor_msgs smclib std_msgs std_srvs stereo_msgs tf tf2 tf2_bullet tf2_eigen tf2_geometry_msgs tf2_kdl tf2_msgs tf2_py tf2_ros tf2_sensor_msgs tf2_tools topic_tools trajectory_msgs urdf urdf_parser_plugin usb_cam uuid_msgs visualization_msgs web_video_server xmlrpcpp mavros opencv3 mavros_extras interactive_markers tf2_web_republisher interactive_marker_proxy \
--rosdistro kinetic --deps --wet-only --tar > kinetic-custom_ros.rosinstall \ --rosdistro kinetic --deps --wet-only --tar > kinetic-custom_ros.rosinstall \
&& wstool merge -t src kinetic-custom_ros.rosinstall \ && wstool merge -t src kinetic-custom_ros.rosinstall \
&& wstool update -t src && wstool update -t src

View File

@@ -27,8 +27,33 @@ apt-get install --no-install-recommends -y \
python3-pip=9.0.1-2+rpt2 \ python3-pip=9.0.1-2+rpt2 \
libjpeg8-dev=8d1-2 \ libjpeg8-dev=8d1-2 \
tcpdump \ tcpdump \
ltrace \
libpoco-dev=1.7.6+dfsg1-5+deb9u1 libpoco-dev=1.7.6+dfsg1-5+deb9u1
# Deny byobu to check available updates
sudo sed -i "s/updates_available//" /usr/share/byobu/status/status
# sudo sed -i "s/updates_available//" /home/pi/.byobu/status
# install Monkey web-server
cd /home/pi
git clone https://github.com/monkey/monkey.git
cd monkey
git checkout v1.6.9
./configure --malloc-libc --local
make
sudo setcap 'cap_net_bind_service=+ep' ./build/monkey # allow using 80 port
rm build/conf/sites/default
ln -s /home/pi/catkin_ws/src/clever/deploy/monkey ./build/conf/sites/default
cd /home/pi
# install and enable Butterfly (web terminal)
sudo apt-get install libffi-dev
sudo pip3 install butterfly
sudo pip3 install butterfly[systemd]
sudo ln -s /home/pi/catkin_ws/src/clever/deploy/butterfly.service /lib/systemd/system/
sudo ln -s /home/pi/catkin_ws/src/clever/deploy/butterfly.socket /lib/systemd/system/
sudo systemctl enable butterfly.socket
echo -e "\033[0;31m\033[1m$(date) | #2 Adding mjpg-streamer at /home/pi\033[0m\033[0m" echo -e "\033[0;31m\033[1m$(date) | #2 Adding mjpg-streamer at /home/pi\033[0m\033[0m"
# https://github.com/jacksonliam/mjpg-streamer # https://github.com/jacksonliam/mjpg-streamer
@@ -38,11 +63,12 @@ git clone https://github.com/jacksonliam/mjpg-streamer.git /home/pi/mjpg-streame
&& make install \ && make install \
&& chown -Rf pi:pi /home/pi/mjpg-streamer && chown -Rf pi:pi /home/pi/mjpg-streamer
echo -e "\033[0;31m\033[1m$(date) | Add .vimrc\033[0m\033[0m" echo -e "\033[0;31m\033[1m$(date) | Miscellaneous\033[0m\033[0m"
# vim settings # vim settings
echo "set mouse-=a echo "set mouse-=a
syntax on syntax on
autocmd BufNewFile,BufRead *.launch set syntax=xml
" > /home/pi/.vimrc " > /home/pi/.vimrc
echo -e "\033[0;31m\033[1m$(date) | End of network installation\033[0m\033[0m" echo -e "\033[0;31m\033[1m$(date) | End of network installation\033[0m\033[0m"