diff --git a/.editorconfig b/.editorconfig index da7471f2..f55e3aa5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,7 +5,7 @@ end_of_line = lf insert_final_newline = true charset = utf-8 -[*.{py,cpp,h,swift,launch}] +[*.{py,swift,launch}] indent_style = space indent_size = 4 diff --git a/.markdownlint.json b/.markdownlint.json index 20034b30..36f4a936 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -13,8 +13,8 @@ "WireShark", "Wi-Fi", "Raspberry Pi", - "PixHawk", - "PixRacer", + "Pixhawk", + "Pixracer", "ArUco" ], "code_blocks": false diff --git a/LICENSE.md b/LICENSE.md index 8d08f5cc..d72cd485 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ 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 of this software and associated documentation files (the "Software"), to deal diff --git a/apps/ios/Podfile b/apps/ios/Podfile index 2bffe4c7..4cf211d3 100644 --- a/apps/ios/Podfile +++ b/apps/ios/Podfile @@ -9,6 +9,5 @@ target 'cleverrc' do # Pods for cleverrc pod 'SwiftSocket', '~> 2.0' - pod 'NotificationBannerSwift' end diff --git a/apps/ios/Podfile.lock b/apps/ios/Podfile.lock index 23c9ad41..16fde5c4 100644 --- a/apps/ios/Podfile.lock +++ b/apps/ios/Podfile.lock @@ -1,21 +1,12 @@ PODS: - - MarqueeLabel/Swift (3.1.4) - - NotificationBannerSwift (1.5.4): - - MarqueeLabel/Swift - - SnapKit (~> 4.0) - - SnapKit (4.0.0) - SwiftSocket (2.0.2) DEPENDENCIES: - - NotificationBannerSwift - SwiftSocket (~> 2.0) SPEC CHECKSUMS: - MarqueeLabel: bf768455fe88d427f71476ebb23f9092b660f40b - NotificationBannerSwift: 4f6666c8421dcf11be0812dd1093d932c15921af - SnapKit: a42d492c16e80209130a3379f73596c3454b7694 SwiftSocket: 6f4c9c63fbc5c1d61188936bb3c599fd546f40ae -PODFILE CHECKSUM: fd5199f69c3ee8c1fbc0dd582477d890c8b2a24f +PODFILE CHECKSUM: 2044f57d00f536792fbc38c63ded4fa78dcc135c COCOAPODS: 1.4.0 diff --git a/apps/ios/cleverrc.xcodeproj/project.pbxproj b/apps/ios/cleverrc.xcodeproj/project.pbxproj index 896d5a79..10ae030d 100644 --- a/apps/ios/cleverrc.xcodeproj/project.pbxproj +++ b/apps/ios/cleverrc.xcodeproj/project.pbxproj @@ -226,16 +226,10 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-cleverrc/Pods-cleverrc-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/MarqueeLabel/MarqueeLabel.framework", - "${BUILT_PRODUCTS_DIR}/NotificationBannerSwift/NotificationBannerSwift.framework", - "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework", "${BUILT_PRODUCTS_DIR}/SwiftSocket/SwiftSocket.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MarqueeLabel.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NotificationBannerSwift.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftSocket.framework", ); runOnlyForDeploymentPostprocessing = 0; @@ -397,7 +391,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7QY6KJ2672; + DEVELOPMENT_TEAM = M8TDN3PAH2; INFOPLIST_FILE = cleverrc/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = coex.cleverrc; @@ -413,7 +407,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7QY6KJ2672; + DEVELOPMENT_TEAM = M8TDN3PAH2; INFOPLIST_FILE = cleverrc/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = coex.cleverrc; diff --git a/apps/ios/cleverrc/AppDelegate.swift b/apps/ios/cleverrc/AppDelegate.swift index 981c369a..cdc6307d 100644 --- a/apps/ios/cleverrc/AppDelegate.swift +++ b/apps/ios/cleverrc/AppDelegate.swift @@ -3,7 +3,7 @@ // cleverrc // // 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 diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Contents.json index ea0141b6..47b49d92 100644 --- a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -3,114 +3,176 @@ { "size" : "20x20", "idiom" : "iphone", - "filename" : "cleverrc40.png", + "filename" : "Icon-App-20x20@2x.png", "scale" : "2x" }, { "size" : "20x20", "idiom" : "iphone", - "filename" : "clever60.png", + "filename" : "Icon-App-20x20@3x.png", "scale" : "3x" }, { "size" : "29x29", "idiom" : "iphone", - "filename" : "clever58.png", + "filename" : "Icon-App-29x29@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", - "filename" : "clever87.png", + "filename" : "Icon-App-29x29@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", - "filename" : "clever80.png", + "filename" : "Icon-App-40x40@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", - "filename" : "clever120.png", + "filename" : "Icon-App-40x40@3x.png", "scale" : "3x" }, { "size" : "60x60", "idiom" : "iphone", - "filename" : "clever120-1.png", + "filename" : "Icon-App-60x60@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", - "filename" : "clever180-1.png", + "filename" : "Icon-App-60x60@3x.png", "scale" : "3x" }, { "size" : "20x20", "idiom" : "ipad", - "filename" : "clever20.png", + "filename" : "Icon-App-20x20@1x.png", "scale" : "1x" }, { "size" : "20x20", "idiom" : "ipad", - "filename" : "clever40.png", + "filename" : "Icon-App-20x20@2x-1.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "ipad", - "filename" : "clever29.png", + "filename" : "Icon-App-29x29@1x.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "ipad", - "filename" : "clever58-1.png", + "filename" : "Icon-App-29x29@2x-1.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "ipad", - "filename" : "clever40-1.png", + "filename" : "Icon-App-40x40@1x.png", "scale" : "1x" }, { "size" : "40x40", "idiom" : "ipad", - "filename" : "clever80-1.png", + "filename" : "Icon-App-40x40@2x-1.png", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", - "filename" : "clever76.png", + "filename" : "Icon-App-76x76@1x.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", - "filename" : "clever152.png", + "filename" : "Icon-App-76x76@2x.png", "scale" : "2x" }, { "size" : "83.5x83.5", "idiom" : "ipad", - "filename" : "clever167.png", + "filename" : "Icon-App-83.5x83.5@2x.png", "scale" : "2x" }, { "size" : "1024x1024", "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" } ], "info" : { "version" : 1, "author" : "xcode" + }, + "properties" : { + "pre-rendered" : true } } \ No newline at end of file diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 00000000..cdf46ee8 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png new file mode 100644 index 00000000..840f7162 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 00000000..840f7162 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 00000000..24935031 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 00000000..5502546f Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png new file mode 100644 index 00000000..44832dd2 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 00000000..44832dd2 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 00000000..afef87bd Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 00000000..840f7162 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png new file mode 100644 index 00000000..fb8d27a2 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 00000000..fb8d27a2 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 00000000..802fea72 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 00000000..802fea72 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 00000000..dd0b646f Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 00000000..030a6d80 Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 00000000..8ef6d5ce Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 00000000..5a0ec2ac Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png new file mode 100644 index 00000000..290fd47d Binary files /dev/null and b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever1024.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever1024.png deleted file mode 100644 index 18e6ddae..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever1024.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever120-1.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever120-1.png deleted file mode 100644 index df88d16e..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever120-1.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever120.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever120.png deleted file mode 100644 index df88d16e..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever120.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever152.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever152.png deleted file mode 100644 index ac26ada9..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever152.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever167.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever167.png deleted file mode 100644 index 092ae2c0..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever167.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever180-1.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever180-1.png deleted file mode 100644 index ede5637d..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever180-1.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever20.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever20.png deleted file mode 100644 index a6efdbf2..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever20.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever29.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever29.png deleted file mode 100644 index 76a04760..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever29.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever40-1.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever40-1.png deleted file mode 100644 index 43736655..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever40-1.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever40.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever40.png deleted file mode 100644 index 43736655..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever40.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever58-1.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever58-1.png deleted file mode 100644 index f5ef15a8..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever58-1.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever58.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever58.png deleted file mode 100644 index f5ef15a8..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever58.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever60.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever60.png deleted file mode 100644 index 273f23c5..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever60.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever76.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever76.png deleted file mode 100644 index 1267cf82..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever76.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever80-1.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever80-1.png deleted file mode 100644 index 9cb96a3f..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever80-1.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever80.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever80.png deleted file mode 100644 index 9cb96a3f..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever80.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever87.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever87.png deleted file mode 100644 index 6510f9f1..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/clever87.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/cleverrc40.png b/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/cleverrc40.png deleted file mode 100644 index 43736655..00000000 Binary files a/apps/ios/cleverrc/Assets.xcassets/AppIcon.appiconset/cleverrc40.png and /dev/null differ diff --git a/apps/ios/cleverrc/Assets.xcassets/Image.imageset/Contents.json b/apps/ios/cleverrc/Assets.xcassets/Image.imageset/Contents.json deleted file mode 100644 index f8f827e4..00000000 --- a/apps/ios/cleverrc/Assets.xcassets/Image.imageset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/apps/ios/cleverrc/Info.plist b/apps/ios/cleverrc/Info.plist index 8a892ff2..545606eb 100644 --- a/apps/ios/cleverrc/Info.plist +++ b/apps/ios/cleverrc/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 1.1 CFBundleVersion - 5 + 6 LSRequiresIPhoneOS UILaunchStoryboardName diff --git a/apps/ios/cleverrc/ViewController.swift b/apps/ios/cleverrc/ViewController.swift index b8fb8721..6d24a107 100644 --- a/apps/ios/cleverrc/ViewController.swift +++ b/apps/ios/cleverrc/ViewController.swift @@ -3,13 +3,12 @@ // cleverrc // // 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 WebKit import SwiftSocket -import NotificationBannerSwift import AudioToolbox.AudioServices class ViewController: UIViewController, WKScriptMessageHandler { @@ -62,15 +61,7 @@ class ViewController: UIViewController, WKScriptMessageHandler { } else if (message.name == "notification") { // Got notification message print(message) - let m = message.body as! NSDictionary; - let level = m["severity"] as! Int - if level == 4 { - let banner = NotificationBanner(title: m["text"] as! String, style: .warning) - banner.show() - } else { - let banner = NotificationBanner(title: m["text"] as! String, style: .danger) - banner.show() - } + tapticNotify() } } diff --git a/apps/ios/cleverrc/index.html b/apps/ios/cleverrc/index.html index 391ef631..b6cca6db 100644 --- a/apps/ios/cleverrc/index.html +++ b/apps/ios/cleverrc/index.html @@ -17,6 +17,7 @@
+
diff --git a/apps/ios/cleverrc/main.css b/apps/ios/cleverrc/main.css index 3f3f944d..be91c227 100644 --- a/apps/ios/cleverrc/main.css +++ b/apps/ios/cleverrc/main.css @@ -8,7 +8,7 @@ html, body { } * { - user-select: none; + user-select: none; } .stick { @@ -76,7 +76,8 @@ body.armed .telemetry .mode { body.low-battery .battery { color: #ff554b; - animation: scale 0.3s 1 ease-in-out} + animation: scale 0.3s 1 ease-in-out +} .logo { position: absolute; @@ -93,3 +94,32 @@ body.low-battery .battery { user-select: none; pointer-events: none; } + +.notifications { + pointer-events: none; + position: absolute; + top: 0; + left: 0; + right: 0; + color: white; +} + +.notifications.hidden { + transform: translateY(-100%); +} + +.notifications.anim { + transition: transform 0.2s ease; +} + +.notifications .item { + font-size: 4mm; + -webkit-text-size-adjust: none; + background: #fca83a; + padding: 3mm; + padding-bottom: 1.5mm; +} + +.notifications .item:last-child { + padding-bottom: 3mm; +} diff --git a/apps/ios/cleverrc/telemetry.js b/apps/ios/cleverrc/telemetry.js index 9606136f..bae841d8 100644 --- a/apps/ios/cleverrc/telemetry.js +++ b/apps/ios/cleverrc/telemetry.js @@ -1,6 +1,7 @@ var url = 'ws://192.168.11.1:9090'; var modeEl = document.querySelector('.telemetry .mode'); var batteryEl = document.querySelector('.battery'); +var notificationsEl = document.querySelector('.notifications'); var ros = new ROSLIB.Ros({ url: url }); @@ -60,6 +61,30 @@ new ROSLIB.Topic({ } }); +var notificationHideTimer; + +function notify(text, severity) { + var item = document.createElement('div'); + item.innerHTML = text; + item.classList.add('item'); + notificationsEl.prepend(item); + var itemHeight = item.offsetHeight; + notificationsEl.classList.remove('anim'); + notificationsEl.style.transform = 'translateY(' + -itemHeight + 'px)'; + setTimeout(function() { + notificationsEl.classList.add('anim'); + notificationsEl.style.transform = 'translateY(0)'; + }, 0); + clearTimeout(notificationHideTimer); + notificationHideTimer = setTimeout(function() { + notificationsEl.style.transform = ''; + notificationsEl.classList.add('hidden'); + setTimeout(function() { + notificationsEl.innerHTML = ''; + }, 210); + }, 4000); +} + new ROSLIB.Topic({ ros: ros, name: '/mavros/statustext/recv', @@ -73,6 +98,7 @@ new ROSLIB.Topic({ console.log('Filtered out message ' + message.text); return; } + notify(message.text, message.severity); callNativeApp('notification', message); } }); diff --git a/clever/CMakeLists.txt b/clever/CMakeLists.txt index 1f1223cd..6ce7ec76 100644 --- a/clever/CMakeLists.txt +++ b/clever/CMakeLists.txt @@ -21,6 +21,9 @@ find_package(catkin REQUIRED COMPONENTS tf tf2 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 catkin_package( # INCLUDE_DIRS include -# LIBRARIES clever + LIBRARIES clever # CATKIN_DEPENDS other_catkin_pkg # DEPENDS system_lib ) @@ -137,7 +140,11 @@ include_directories( ${catkin_INCLUDE_DIRS} ) -## Declare a C++ library +# Declare a C++ library +add_library(clever + src/optical_flow.cpp +) + add_library(fcu_horiz src/fcu_horiz.cpp ) @@ -156,8 +163,16 @@ add_library(aruco_vpe ## The recommended prefix ensures that target names across packages don't collide add_executable(rc src/rc.cpp) +add_executable(camera_markers src/camera_markers.cpp) + +add_executable(frames src/frames.cpp) + target_link_libraries(rc ${catkin_LIBRARIES}) +target_link_libraries(camera_markers ${catkin_LIBRARIES}) + +target_link_libraries(frames ${catkin_LIBRARIES}) + ## Rename C++ executable without prefix ## The above recommended prefix causes long target names, the following renames the ## target back to the shorter version for ease of user use @@ -169,6 +184,10 @@ target_link_libraries(rc ${catkin_LIBRARIES}) # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) ## Specify libraries to link a library or executable target against +target_link_libraries(clever + ${catkin_LIBRARIES} +) + target_link_libraries(fcu_horiz ${catkin_LIBRARIES} "/opt/ros/kinetic/lib/libtf2_ros.so" diff --git a/clever/launch/clever.launch b/clever/launch/clever.launch index c1d7a6a6..998ef361 100644 --- a/clever/launch/clever.launch +++ b/clever/launch/clever.launch @@ -2,27 +2,27 @@ - - + + - - + - + - - + + + @@ -30,6 +30,12 @@ + + + + + + @@ -37,11 +43,12 @@ - - + + + @@ -49,14 +56,14 @@ + + + + + - - - - - diff --git a/clever/launch/copter_visualization.launch b/clever/launch/copter_visualization.launch deleted file mode 100644 index 24006baf..00000000 --- a/clever/launch/copter_visualization.launch +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/clever/launch/main_camera.launch b/clever/launch/main_camera.launch index 480ba38f..da843ff7 100644 --- a/clever/launch/main_camera.launch +++ b/clever/launch/main_camera.launch @@ -1,4 +1,7 @@ + + + @@ -16,8 +19,14 @@ + + + + + + diff --git a/clever/launch/mavros.launch b/clever/launch/mavros.launch index ad3ab790..205107d9 100644 --- a/clever/launch/mavros.launch +++ b/clever/launch/mavros.launch @@ -1,58 +1,96 @@ - + - - + + - - + + - - + + - - - - - - - - + + + + + + + + - - + + - - - - - - - - - - safety_area - - image_pub - - vibration - - distance_sensor - - rangefinder - - 3dr_radio - - actuator_control - - hil_controls - - vfr_hud - - px4flow - - vision_speed_estimate - - fake_gps - - cam_imu_sync - - hil - - adsb - + + + distance_sensor: + rangefinder_0: + id: 0 + frame_id: "rangefinder" + orientation: PITCH_270 + field_of_view: 0.5 + rangefinder_1: + id: 1 + frame_id: "rangefinder" + orientation: PITCH_270 + field_of_view: 0.5 + rangefinder_2_sub: + subscriber: true + id: 2 + orientation: PITCH_270 + rangefinder_3_sub: + subscriber: true + id: 3 + orientation: PITCH_270 + + + + + + + + + + + - 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 + - home_position + + + + - + + + + + + + + + diff --git a/clever/launch/sitl.launch b/clever/launch/sitl.launch index 1e48052f..af9f08c4 100644 --- a/clever/launch/sitl.launch +++ b/clever/launch/sitl.launch @@ -7,11 +7,11 @@ + + - - diff --git a/clever/launch/web_server.launch b/clever/launch/web_server.launch deleted file mode 100644 index 9d8944ac..00000000 --- a/clever/launch/web_server.launch +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/clever/nodelet_plugins.xml b/clever/nodelet_plugins.xml index 9e1c2c67..36e583b6 100644 --- a/clever/nodelet_plugins.xml +++ b/clever/nodelet_plugins.xml @@ -1,3 +1,8 @@ + + + + + diff --git a/clever/requirements.txt b/clever/requirements.txt index 579c0031..8679c188 100644 --- a/clever/requirements.txt +++ b/clever/requirements.txt @@ -1,3 +1,5 @@ -flask==0.12.2 +flask==0.12.3 geopy==1.11.0 pymavlink==2.2.10 +smbus2==0.2.1 +VL53L1X==0.0.2 diff --git a/clever/src/camera_markers.cpp b/clever/src/camera_markers.cpp new file mode 100644 index 00000000..0f869056 --- /dev/null +++ b/clever/src/camera_markers.cpp @@ -0,0 +1,101 @@ +/* + * Visualization marker for camera alignment + * Copyright (C) 2018 Copter Express Technologies + * + * Author: Oleg Kalachev + * + * 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 +#include +#include +#include +#include + +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("camera_info", nh); + camera_frame = camera_info->header.frame_id; + + ros::Publisher markers_pub = nh.advertise("camera_markers", 1, true); + markers_pub.publish(createMarkers()); + + ROS_INFO("Camera markers initialized"); + ros::spin(); +} diff --git a/clever/src/frames.cpp b/clever/src/frames.cpp new file mode 100644 index 00000000..f0d5a8b0 --- /dev/null +++ b/clever/src/frames.cpp @@ -0,0 +1,63 @@ +/* + * Auxiliary TF frames for CLEVER drone kit: + * - Body frame (drone body with zero pitch and roll). + * - TODO: REP-0105 `odom` frame emulation: continuous frame without discrete jumps. + * - TODO: Terrain frame (base on ALTITUDE message). + * - TODO: map_upside_down frame + * - TODO: home frame? + * + * Copyright (C) 2018 Copter Express Technologies + * + * Author: Oleg Kalachev + * + * 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. + */ + +// TODO: consider implementing as a mavros plugin + +#include +#include +#include +#include +#include +#include +#include + +using std::string; + +static std::shared_ptr br; +static geometry_msgs::TransformStamped body; + +inline void publishBody(const geometry_msgs::PoseStamped& pose) +{ + // Get only yaw from pose + tf::Quaternion q; + q.setRPY(0, 0, tf::getYaw(pose.pose.orientation)); + tf::quaternionTFToMsg(q, body.transform.rotation); + + body.transform.translation.x = pose.pose.position.x; + body.transform.translation.y = pose.pose.position.y; + body.transform.translation.z = pose.pose.position.z; + body.header.frame_id = pose.header.frame_id; + body.header.stamp = pose.header.stamp; + br->sendTransform(body); +} + +void poseCallback(const geometry_msgs::PoseStamped& pose) +{ + publishBody(pose); +} + +int main(int argc, char **argv) { + ros::init(argc, argv, "frames"); + ros::NodeHandle nh, nh_priv("~"); + + nh_priv.param("body/frame_id", body.child_frame_id, "body"); + + br = std::make_shared(); + ros::Subscriber pose_sub = nh.subscribe("mavros/local_position/pose", 1, &poseCallback); + ROS_INFO("frames: ready"); + ros::spin(); +} diff --git a/clever/src/interactive.py b/clever/src/interactive.py new file mode 100755 index 00000000..1ec5d7ab --- /dev/null +++ b/clever/src/interactive.py @@ -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() diff --git a/clever/src/monkey b/clever/src/monkey new file mode 100755 index 00000000..d1fd8ca2 --- /dev/null +++ b/clever/src/monkey @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +exec /home/pi/monkey/build/monkey --port 80 --workers 1 diff --git a/clever/src/optical_flow.cpp b/clever/src/optical_flow.cpp new file mode 100644 index 00000000..02eae273 --- /dev/null +++ b/clever/src/optical_flow.cpp @@ -0,0 +1,200 @@ +/* + * Optical Flow node for PX4 + * Copyright (C) 2018 Copter Express Technologies + * + * Author: Oleg Kalachev + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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("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/px4flow/raw/send", 1); + velo_pub_ = nh_priv.advertise("angular_velocity", 1); + shift_pub_ = nh_priv.advertise("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(i, j) = cinfo->K[3 * i + j]; + } + } + for (int k = 0; k < cinfo->D.size(); k++) { + dist_coeffs_.at(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 points_dist = { shift }; + std::vector 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(0, 0); + double focal_length_y = camera_matrix_.at(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) diff --git a/clever/src/selfcheck.py b/clever/src/selfcheck.py index 570464a9..470e887d 100755 --- a/clever/src/selfcheck.py +++ b/clever/src/selfcheck.py @@ -1,93 +1,192 @@ #!/usr/bin/env python +import math +from subprocess import Popen, PIPE +import re +import traceback import rospy from std_srvs.srv import Trigger from sensor_msgs.msg import Image, CameraInfo, NavSatFix, Imu from mavros_msgs.msg import State -from geometry_msgs.msg import PoseStamped +from geometry_msgs.msg import PoseStamped, TwistStamped # TODO: roscore is running +# TODO: clever.service is running +# TODO: check attitude is present +# TODO: disk free space # TODO: local_origin, fcu, fcu_horiz # TODO: rc service -# TODO: perform commander check in PX4 +# TODO: perform commander check, ekf2 status on PX4 +# TODO: check if FCU params setter succeed +# TODO: selfcheck ROS service (with blacklists for checks) 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(): try: state = rospy.wait_for_message('mavros/state', State, timeout=3) if not state.connected: - raise Exception('No connection to the FCU') - except: - raise Exception('No mavros state') + failure('No connection to the FCU (check wiring)') + except rospy.ROSException: + failure('No MAVROS state (check wiring)') +@check('Camera') def check_camera(name): try: - rospy.wait_for_message(name + '/image_raw', Image, timeout=3) - except: - raise Exception('No %s camera images' % name) + img = rospy.wait_for_message(name + '/image_raw', Image, timeout=1) + except rospy.ROSException: + failure('%s: No images (is the camera connected properly?)', name) + return try: - rospy.wait_for_message(name + '/camera_info', CameraInfo, timeout=3) - except: - raise Exception('No %s camera camera info' % name) + info = rospy.wait_for_message(name + '/camera_info', CameraInfo, timeout=1) + except rospy.ROSException: + failure('%s: No calibration info', name) + return + if img.width != info.width: + failure('%s: Calibration width doesn\'t match image width (%d != %d)', name, info.width, img.width) + if img.height != info.height: + failure('%s: Calibration height doesn\'t match image height (%d != %d))', name, info.height, img.height) + + +@check('Aruco detector') def check_aruco(): try: - rospy.wait_for_message('aruco_pose/debug', Image, timeout=3) - except: - raise Exception('No aruco_pose/debug topic') + rospy.wait_for_message('aruco_pose/debug', Image, timeout=1) + except rospy.ROSException: + failure('No aruco_pose/debug messages') +@check('Simple offboard node') def check_simpleoffboard(): try: rospy.wait_for_service('navigate', timeout=3) rospy.wait_for_service('get_telemetry', timeout=3) rospy.wait_for_service('land', timeout=3) - except: - raise Exception('No simple_offboard services') + except rospy.ROSException: + failure('No simple_offboard services') +@check('IMU') def check_imu(): try: - rospy.wait_for_message('mavros/imu/data', Imu, timeout=3) - except: - raise Exception('No IMU data') + rospy.wait_for_message('mavros/imu/data', Imu, timeout=1) + except rospy.ROSException: + failure('No IMU data (check flight controller calibration)') +@check('Local position') def check_local_position(): try: - rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=3) - except: - raise Exception('No local position') + rospy.wait_for_message('mavros/local_position/pose', PoseStamped, timeout=1) + except rospy.ROSException: + failure('No local position') +@check('Velocity estimation') +def check_velocity(): + try: + velocity = rospy.wait_for_message('mavros/local_position/velocity', TwistStamped, timeout=1) + horiz = math.hypot(velocity.twist.linear.x, velocity.twist.linear.y) + vert = velocity.twist.linear.z + if abs(horiz) > 0.1: + failure('Horizontal velocity estimation is %.2f m/s; is copter staying still?' % horiz) + if abs(vert) > 0.1: + failure('Vertical velocity estimation is %.2f m/s; is copter staying still?' % vert) + + angular = velocity.twist.angular + ANGULAR_VELOCITY_LIMIT = 0.01 + if abs(angular.x) > ANGULAR_VELOCITY_LIMIT: + failure('Pitch rate estimation is %.2f rad/s (%.2f deg/s); is copter staying still?', + angular.x, math.degrees(angular.x)) + if abs(angular.y) > ANGULAR_VELOCITY_LIMIT: + failure('Pitch rate estimation is %.2f rad/s (%.2f deg/s); is copter staying still?', + angular.y, math.degrees(angular.y)) + if abs(angular.z) > ANGULAR_VELOCITY_LIMIT: + failure('Pitch rate estimation is %.2f rad/s (%.2f deg/s); is copter staying still?', + angular.z, math.degrees(angular.z)) + except rospy.ROSException: + failure('No velocity estimation') + + +@check('Global position (GPS)') def check_global_position(): try: - rospy.wait_for_message('mavros/global_position/global', PoseStamped, timeout=3) - except: - raise Exception('No global position') + rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=2) + except rospy.ROSException: + failure('No global position') -def check(name, fn): - try: - fn() - rospy.loginfo('%s: OK', name) - except Exception as e: - rospy.logwarn('%s: %s', name, str(e)) +@check('Boot duration') +def check_boot_duration(): + proc = Popen('systemd-analyze', stdout=PIPE) + proc.wait() + output = proc.communicate()[0] + r = re.compile(r'([\d\.]+)s$') + duration = float(r.search(output).groups()[0]) + if duration > 15: + failure('long Raspbian boot duration: %ss (systemd-analyze for analyzing)', 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(): - check('FCU', check_fcu) - check('Simple offboard node', check_simpleoffboard) - check('Main camera node', lambda: check_camera('main_camera')) - check('aruco_pose/debug topic', check_aruco) - check('IMU data', check_imu) - check('Local position', check_local_position) - check('Global position (GPS)', check_global_position) + check_fcu() + check_imu() + check_local_position() + check_velocity() + check_global_position() + check_camera('main_camera') + check_aruco() + check_simpleoffboard() + check_cpu_usage() + check_boot_duration() if __name__ == '__main__': diff --git a/clever/src/simple_offboard.py b/clever/src/simple_offboard.py index 218a258f..3d117f56 100755 --- a/clever/src/simple_offboard.py +++ b/clever/src/simple_offboard.py @@ -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)) ARM_TIMEOUT = rospy.Duration(rospy.get_param('~arm_timeout', 5)) LOCAL_POSITION_TIMEOUT = rospy.Duration(rospy.get_param('~local_position_timeout', 0.5)) -NAVIGATE_AFTER_ARMED = rospy.Duration(rospy.get_param('~navigate_after_armed', False)) +NAVIGATE_AFTER_ARMED = rospy.Duration(rospy.get_param('~navigate_after_armed', True)) TRANSFORM_TIMEOUT = rospy.Duration(rospy.get_param('~transform_timeout', 3)) SETPOINT_RATE = rospy.get_param('~setpoint_rate', 30) -LOCAL_FRAME = rospy.get_param('~local_frame', 'local_origin') +LOCAL_FRAME = rospy.get_param('mavros/local_position/frame_id', 'local_origin') LAND_MODE = rospy.get_param('~land_mode', 'AUTO.LAND') LAND_TIMEOUT = rospy.Duration(rospy.get_param('~land_timeout', 2)) +DEFAULT_SPEED = rospy.get_param('~default_speed', 0.5) def offboard_and_arm(): @@ -120,6 +121,8 @@ def offboard_and_arm(): ps = PoseStamped() vs = Vector3Stamped() +pt = PositionTarget() +at = AttitudeTarget() BRAKE_TIME = rospy.Duration(0) @@ -164,7 +167,7 @@ def get_publisher_and_message(req, stamp, continued=True, update_frame=True): if update_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.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) 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) yaw_rate_flag = math.isnan(req.yaw) - msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED, - type_mask=PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + - PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + - (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE), - position=setpoint, - yaw=euler_from_orientation(current_nav_finish.pose.orientation, 'szyx')[2] - math.pi / 2, - yaw_rate=req.yaw_rate) + msg = pt + msg.coordinate_frame = PT.FRAME_LOCAL_NED + msg.type_mask = PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + \ + PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + \ + (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE) + msg.position = setpoint + msg.yaw = euler_from_orientation(current_nav_finish.pose.orientation, 'sxyz')[2] + msg.yaw_rate = req.yaw_rate return position_pub, msg 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) yaw_rate_flag = math.isnan(req.yaw) - msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED, - type_mask=PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + - PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + - (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE), - position=pose_local.pose.position, - yaw=euler_from_orientation(pose_local.pose.orientation, 'szyx')[2] - math.pi / 2, - yaw_rate=req.yaw_rate) + msg = pt + msg.coordinate_frame = PT.FRAME_LOCAL_NED + msg.type_mask = PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + \ + PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + \ + (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE) + msg.position = pose_local.pose.position + msg.yaw = euler_from_orientation(pose_local.pose.orientation, 'sxyz')[2] + msg.yaw_rate = req.yaw_rate return position_pub, msg 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) yaw_rate_flag = math.isnan(req.yaw) - msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED, - type_mask=PT.IGNORE_PX + PT.IGNORE_PY + PT.IGNORE_PZ + - PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + - (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE), - velocity=vector_local.vector, - yaw=euler_from_orientation(pose_local.pose.orientation, 'szyx')[2] - math.pi / 2, - yaw_rate=req.yaw_rate) + msg = pt + msg.coordinate_frame = PT.FRAME_LOCAL_NED + msg.type_mask = PT.IGNORE_PX + PT.IGNORE_PY + PT.IGNORE_PZ + \ + PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + \ + (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE) + msg.velocity = vector_local.vector + msg.yaw = euler_from_orientation(pose_local.pose.orientation, 'sxyz')[2] + msg.yaw_rate = req.yaw_rate return position_pub, msg elif isinstance(req, srv.SetAttitudeRequest): ps.header.frame_id = req.frame_id or LOCAL_FRAME ps.pose.orientation = orientation_from_euler(req.roll, req.pitch, req.yaw) pose_local = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT) - msg = AttitudeTarget(orientation=pose_local.pose.orientation, - thrust=req.thrust, - type_mask=AT.IGNORE_YAW_RATE + AT.IGNORE_PITCH_RATE + AT.IGNORE_ROLL_RATE) + msg = at + msg.orientation = pose_local.pose.orientation + msg.thrust = req.thrust + msg.type_mask = AT.IGNORE_YAW_RATE + AT.IGNORE_PITCH_RATE + AT.IGNORE_ROLL_RATE return attitude_pub, msg elif isinstance(req, srv.SetRatesRequest): - msg = AttitudeTarget(thrust=req.thrust, - type_mask=AttitudeTarget.IGNORE_ATTITUDE, - body_rate=Vector3(req.roll_rate, req.pitch_rate, req.yaw_rate)) + msg = at + msg.thrust = req.thrust + 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 @@ -261,9 +271,12 @@ def handle(req): rospy.logwarn('No connection to the FCU') return {'message': 'No connection to the FCU'} - if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)) and req.speed <= 0: - rospy.logwarn('Navigate speed must be greater than zero, %s passed') - return {'message': 'Navigate speed must be greater than zero, %s passed' % req.speed} + if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)): + if req.speed < 0: + 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 \ (pose is None or rospy.get_rostime() - pose.header.stamp > LOCAL_POSITION_TIMEOUT): @@ -280,13 +293,13 @@ def handle(req): try: with handle_lock: - stamp = rospy.get_rostime() - current_req = req - current_pub, current_msg = get_publisher_and_message(req, stamp, False) - rospy.loginfo('Topic: %s, message: %s', current_pub.name, current_msg) + stamp = rospy.get_rostime() + current_req = req + current_pub, current_msg = get_publisher_and_message(req, stamp, False) + rospy.loginfo('Topic: %s, message: %s', current_pub.name, current_msg) - current_msg.header.stamp = stamp - current_pub.publish(current_msg) + current_msg.header.stamp = stamp + current_pub.publish(current_msg) if req.auto_arm: offboard_and_arm() diff --git a/clever/src/vl53l1x.py b/clever/src/vl53l1x.py new file mode 100755 index 00000000..78abfb7c --- /dev/null +++ b/clever/src/vl53l1x.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +from __future__ import division + +import rospy +import VL53L1X +from sensor_msgs.msg import Range + +rospy.init_node('vl53l1x') + + +# range_pub = rospy.Publisher('~range', Range, queue_size=5) +# TODO: why remmaping is not working? +range_pub = rospy.Publisher('mavros/distance_sensor/rangefinder_3_sub', Range, queue_size=10) + +msg = Range() +msg.radiation_type = Range.INFRARED +msg.field_of_view = 0.471239 +msg.min_range = 0 +msg.max_range = 4 +msg.header.frame_id = 'rangefinder' + +tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29) +tof.open() # Initialise the i2c bus and configure the sensor +tof.start_ranging(3) # Start ranging, 1 = Short Range, 2 = Medium Range, 3 = Long Range + +rospy.loginfo('vl53l1x: start ranging') + +r = rospy.Rate(14) +while not rospy.is_shutdown(): + msg.header.stamp = rospy.get_rostime() + msg.range = tof.get_distance() / 1000 + range_pub.publish(msg) + r.sleep() + +tof.stop_ranging() # Stop ranging diff --git a/clever/src/web_server.py b/clever/src/web_server.py deleted file mode 100755 index 86874760..00000000 --- a/clever/src/web_server.py +++ /dev/null @@ -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('/') -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) diff --git a/clever/static/index.html b/clever/static/index.html new file mode 100644 index 00000000..9c3074ca --- /dev/null +++ b/clever/static/index.html @@ -0,0 +1,13 @@ +

CLEVER Drone Kit Tools

+ + + + diff --git a/docs/3g.md b/docs/3g.md index a7972619..5cd94c4a 100644 --- a/docs/3g.md +++ b/docs/3g.md @@ -1,4 +1,6 @@ Использование внешнего 3G-модема === +Использование внешнего 3G-модема на Raspberry возможно с помощью пакета `sakis3g`. + TODO diff --git a/docs/README.md b/docs/README.md index 2ec33d4d..dad4ac70 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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)» и многие другие. @@ -24,7 +24,7 @@ * Raspbian Stretch * ROS Kinetic -* Настроенную работу с сетью +* Настроенную [работу с сетью](network.md) * OpenCV * mavros * Набор ПО для работы с Клевером diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index f97f45c4..918dd66a 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -2,17 +2,19 @@ * [Введение](README.md) * [Глоссарий](glossary.md) -* [Сборка](assemble.md) +* [Сборка Клевер 2](assemble.md) +* [Сборка Клевер 3](assemble_clever3_4in1.md) * [Первоначальная настройка](setup.md) * [Полетные режимы](modes.md) * [Raspberry Pi](raspberry.md) * [Образ операционной системы на RPi](microsd_images.md) -* [Подключение Raspberry Pi к PixHawk](connection.md) +* [Подключение Raspberry Pi к Pixhawk](connection.md) * [Подключение по Wi-Fi](wifi.md) * [Работа с QGroundControl через Wi-Fi](gcs_bridge.md) -* [Прошивка PixHawk/PixRacer](firmware.md) +* [Прошивка Pixhawk/Pixracer](firmware.md) * [Пилотирование со смартфона](rc.md) * [SSH-доступ](ssh.md) +* [Устройство UART](uart.md) * [Неисправности радиоаппаратуры](radioerrors.md) * [Безопасность](safety.md) * [Техника безопасности по пайке](tb.md) @@ -46,4 +48,6 @@ * [Прошивка ESC контроллеров с помощью Arduino](esc_firmware.md) * [Работа со светодиодной лентой](leds.md) * [Проекты на базе коптера "Клевер"](projects.md) + * [Тестовое описание Клевера по шаблону robots.ros.org/gapter/](testovoe-opisanie-klevera-po-shablonu-robotsrosorggapter.md) * [Полезные ссылки](links.md) + diff --git a/docs/aruco.md b/docs/aruco.md index cfc28ea8..6b2c74a2 100644 --- a/docs/aruco.md +++ b/docs/aruco.md @@ -110,7 +110,7 @@ _Примечание_: указанное выше определение пр Для правильной работы 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_. * Выключен компас: `ATT_W_MAG` = 0 * Вес угла по рысканью по зрению: `ATT_W_EXT_HDG` = 0.5 diff --git a/docs/assemble.md b/docs/assemble.md index 5a41a0ff..2d68dd6d 100644 --- a/docs/assemble.md +++ b/docs/assemble.md @@ -1,10 +1,8 @@ -Инструкция по сборке конструктора Клевер 2 -========================================== +# Инструкция по сборке конструктора Клевер 2 ![Clever](assets/Clevermain.png) -Состав конструктора -------------------- +## Состав конструктора ![Explosion](assets/explosion.png) @@ -27,7 +25,7 @@ * Зарядное устройство EFEST Luc V4 Li-lon x1. * Защитный бокс регуляторов x4. * Крепление под ножки x8. -* Полетный контроллер PIXHAWK x1. +* Полетный контроллер PixHawk x1. * Радиоприемник FlySky i6 x1. * Радиопульт FlySky i6 x1. * Зарядное устройство EFEST LUC V4 x1. @@ -37,7 +35,8 @@ * Батарейка АА х4 * Джампер, Bind-разъем -#### Крепежные элементы +### Крепежные элементы + * Пластиковые стойки 6 мм x28. * Пластиковые стойки 30 мм x32. * Винты М3x8 x48. @@ -54,10 +53,8 @@ * Ножницы канцелярские х1 * Ремешок для батареи 250 мм х1 +## Функционал радиопульта Flysky i6 - -Функционал радиопульта Flysky i6 ---------------------------- 1. Переключатель A (SwA). 2. Переключатель B (SwB). 3. Переключатель С (SwC). @@ -78,10 +75,9 @@ ![radio Transmitter](assets/radioTransmitter.png) +## Дополнительное оборудование -Дополнительное оборудование ---------------------------- -#### Данное оборудование не входит в состав конструктора Клевер 2, но оно необходимо для реализации сборочного процесса +### Данное оборудование не входит в состав конструктора Клевер 2, но оно необходимо для реализации сборочного процесса 1. Паяльник 2. Канифоль/ Флюс (нейтральный) @@ -94,11 +90,9 @@ ![Дополнительное оборудование](assets/addEqipment.jpg) - [Техника безопасности при пайке](tb.md) -Порядок сборки --------------- +## Порядок сборки ### Установка моторов @@ -107,11 +101,13 @@ ![Мотор brrc2205](assets/brrc2205.png) Зачистить + * снять 2мм термоизоляции с конца провода не повредив медные жилы. Скрутить провода. Залудить + * Нанести флюс на оголенную часть провода. * Покрыть припоем, используя пинцет. @@ -128,17 +124,19 @@ ![Вращение моторов](assets/brrc2205ondeck.png) +### Залудить три контактные площадки регулятора -#### Залудить три контактные площадки регулятора * Нанести флюс * Нанести припой Чтобы припой аккуратно заполнил всю площадку, необходимо прогреть площадку регулятора. Для этого нужно удерживать жало паяльника на контактной плащадке в течение 2 сек (или больше, если потребуется) ![Лужение контактных площадок регуляторов](assets/escDYSzap.png) + * Повторить данную операцию для оставшихся трех регуляторов -#### Припаять провода моторов к регуляторам +### Припаять провода моторов к регуляторам + Припаять ранее приготовленные провода моторов к контактным площадкам регуляторов. ![Припаять провода моторов к регуляторам](assets/solderingBrrc2205ondeckTOescDYSzap.png) @@ -146,6 +144,7 @@ * Повторить данную операцию для оставшихся трех регуляторов ### Монтаж разъемов питания + [Статья про силовые и управляющие цепи](powerConnection.md) #### Подготовка проводов для силовых разъемов XT60 @@ -169,10 +168,7 @@ 4. Припаять красный провод к “+” контакту разъема . 5. Нарезать термоусадку ф5 (2 отрезка по 10 мм). 6. Надеть термоусадку ф5 на провода так, чтобы она закрывала контактные площадки проводов с XT60 . -7. Усадить термоусадку феном. - -![Монтаж разъемов XT60](assets/mountxt60pinsocket.png) - +7. Усадить термоусадку феном. ![Монтаж разъемов XT60](assets/mountxt60pinsocket.png) 8. Повторить процедуру для разъема XT60 socket. #### Подготовка разъема питания управляющей цепи 5В @@ -193,15 +189,18 @@ ![Предпаячная проверка](assets/startPDBtest.jpg) Прозвонить следующие цепи на НЕЗАМКНУТОСТЬ (отсутствие звукового сигнала мультиметра): + * “BAT+” и “BAT-” * “12V” и “GND” * “5V” и “GND” Прозвонить следующие цепи на ЗАМКНУТОСТЬ (появление звукового сигнала мультиметра): + * “BAT-” c каждым контактом, обозначенным “-” и “GND” * “BAT+”, с каждым контактом, обозначенным “+” #### Залудить контактные площадки платы питания + 1. [Залудить*](zap.md) контактные площадки платы питания. 2. С помощью мультиметра проверить отсутствие контактного замыкания на плате (прозвонить) @@ -210,15 +209,18 @@ Чтобы припой аккуратно заполнил всю площадку, необходимо её прогреть. Для этого нужно удерживать жало паяльника на контактной плащадке в течение 2 сек (или больше, если потребуется) #### Пайка силового разъема питания XT60 + Припаять разъем для АКБ, соблюдая полярность на контактных площадках. ![Пайка XT60 на PDB](assets/solderingxt60socketTOpdb.png) ВАЖНО о полярности + * красный провод - это “+” * черный провод - это “-” #### Пайка разъема питания управляющей цепи 5В + Припаять разъем 5В, соблюдая полярность на контактных площадках. (на изображении: красный провод - это питание “+”) @@ -227,6 +229,7 @@ ### Монтаж отсека АКБ #### Подготовка перемычек (3 шт.) + ![Перемычка](assets/jumper.png) * Отрезать силовой провод длиной 2 см. @@ -237,60 +240,49 @@ * Прозвонить мультиметром. В случае необходимости зачистить наждачной бумагой. #### Подготовка отсека АКБ + ![Подготовка отсека АКБ](assets/casebattery.png) + * Приклеить наклейки с разметкой внутрь отсека АКБ, в соответствии с полярностью. * Приклеить ленту из скотча на дно отсека. - ### Монтаж платы распределения питания -* Установить плату питания на раму винтами М3х8 и пластиковыми гайками. -![Установка платы PDB](assets/mountPDB.png) - -* ВАЖНО -Стрелочка на плате направлена в сторону носового выреза +* Установить плату питания на раму винтами М3х8 и пластиковыми гайками. ![Установка платы PDB](assets/mountPDB.png) + > **ВАЖНО** Стрелочка на плате направлена в сторону носового выреза ![Установка платы PDB](assets/topviewmountPDB.png) - #### Монтаж элементов -1. Установить гайки в пластиковые держатели -![Монтаж пластиковых держателей](assets/holderLegs.png) - +1. Установить гайки в пластиковые держатели. ![Монтаж пластиковых держателей](assets/holderLegs.png) 2. Установить лучи на раму винтами М3х16 -*Лучи устанавливаются поверх рамы -*Пластиковые держатели устанавливаются снизу рамы -![Монтаж лучей](assets/mountBeams.png) - -3. Расположение моторов -Проверить расположение моторов (моторы с черной гайкой в левом верхнем углу и в правом нижнем). -![Расположение моторов](assets/motorsTopview.png) - -4. Продеть силовые провода регуляторов в отверстия. -![силовые провода моторов](assets/escWires.png) - + * Лучи устанавливаются поверх рамы + * Пластиковые держатели устанавливаются снизу рамы. ![Монтаж лучей](assets/mountBeams.png) +3. Расположение моторов. Проверить расположение моторов (моторы с черной гайкой в левом верхнем углу и в правом нижнем). ![Расположение моторов](assets/motorsTopview.png) +4. Продеть силовые провода регуляторов в отверстия. ![силовые провода моторов](assets/escWires.png) #### Пайка силовой цепи платы питания + Припаять силовые провода регуляторов к плате питания, соблюдая полярность. + ![Пайка силовых проводов на PDB](assets/solderingPowerwires.png) ВАЖНО о полярности -*красный провод - это “+” -*черный провод - это “-” +* красный провод - это “+” +* черный провод - это “-” ### Сопряжение приемника и пульта -1. Подключить радиоприемник к разъему 5В. В любой разъем, GND внизу. На схеме питание обозначено как 5V -![Подключение питания приемника](assets/receiver5V.png) -3. Подключить АКБ. -Светодиод на радиоприемнике должен мигать. -![Подключение АКБ](assets/connectBattery.png) +1. Подключить радиоприемник к разъему 5В. В любой разъем, GND внизу. На схеме питание обозначено как 5V ![Подключение питания приемника](assets/receiver5V.png) +2. Подключить АКБ. Светодиод на радиоприемнике должен мигать. ![Подключение АКБ] #### БЕЗОПАСНОСТЬ при работе с АКБ + ![БЕЗОПАСНОСТЬ при работе с АКБ](assets/safetyPower.png) #### Включение радиопульта + 1. Вставить джампер в B/VCC радиоприемника (замкнуть "землю" и "сигнал") 2. На пульте зажать кнопку BIND KEY. 3. Включить пульт (перещелкнуть POWER, BIND KEY не отпускаем). @@ -302,63 +294,42 @@ ![Подключение питания приемника](assets/connectingRadio.png) [Мануал по неисправностям радиоаппаратуры](radioerrors1.md) + ### Проверка направления вращения моторов + 1. Наклеить наклейки на АКБ 18650. -2. Установить 18650 в отсек АКБ, соблюдая полярность. - -![Готовность отсека АКБ](assets/readyBatteryholder.png) - +2. Установить 18650 в отсек АКБ, соблюдая полярность. ![Готовность отсека АКБ](assets/readyBatteryholder.png) 3. Проверить, что разъем питания 5В подключен к приемнику по схеме. -4. Подключить регулятор мотора к 3 каналу приемника CH3 по схеме. -![Подключение регулятора к приемнику](assets/connectionESCtoReceiver.png) - +4. Подключить регулятор мотора к 3 каналу приемника CH3 по схеме. ![Подключение регулятора к приемнику](assets/connectionESCtoReceiver.png) 5. Подключить внешнее питание (АКБ). 6. Включить пульт. 7. Подать левым стиком газ (throttle) на 10%. -8. Проверить направления вращения мотора по схеме. -![Проверка вращения моторов](assets/testMotors.png) - -9. Если необходимо изменить направление вращения, то меняем любые два фазных провода мотора (нужно перепаять). - -![Перепайка фазных проводов](assets/resolderingESC.png) - +8. Проверить направления вращения мотора по схеме. ![Проверка вращения моторов](assets/testMotors.png) +9. Если необходимо изменить направление вращения, то меняем любые два фазных провода мотора (нужно перепаять). ![Перепайка фазных проводов](assets/resolderingESC.png) ### Монтаж радиоприемника + 1. Установить пластиковые стойки 30 мм на раму винтами М3х8. -2. Разъем питания 5В продеть в прорезь. -![Установка стоек и прорезь](assets/mountReceiverStud.png) - -3. Приемник прикрепить к нижней дополнительной раме, используя двухсторонний скотч и ориентируясь на гравировку. Антенны направлены вперед. - - ![Установка радиоприемника на деку](assets/mountReceiverDeck.png) - -4. Установить 3х проводной шлейф в канал PPM / CH1. -![Подключение радиоприемника](assets/receiverPPM.png) - +2. Разъем питания 5В продеть в прорезь. ![Установка стоек и прорезь](assets/mountReceiverStud.png) +3. Приемник прикрепить к нижней дополнительной раме, используя двухсторонний скотч и ориентируясь на гравировку. Антенны направлены вперед. ![Установка радиоприемника на деку](assets/mountReceiverDeck.png) +4. Установить 3х проводной шлейф в канал PPM / CH1. ![Подключение радиоприемника](assets/receiverPPM.png) 5. Продеть в прорезь к разъему 5 В. -6. Прикрутить нижнюю дополнительную раму к стойкам на центральной раме винтами М3х8. -![Установка нижней деки](assets/mountBottomDeck.png) - -##### ВАЖНО -Направление стрелок на плате питания и на дополнительной раме совпадают +6. Прикрутить нижнюю дополнительную раму к стойкам на центральной раме винтами М3х8. ![Установка нижней деки](assets/mountBottomDeck.png) + > **ВАЖНО** Направление стрелок на плате питания и на дополнительной раме совпадают ### Монтаж полетного контроллера + #### Переворачиваем сборку + ![Переворачиваем сборку](assets/topPreview.png) -#### Установка полетного контроллера Pixhawk -1. Клеим 2х сторонний скотч по углам полетного контроллера - ![Полетный контроллер](assets/pixhawk.png) +#### Установка полетного контроллера PixHawk -##### ВАЖНО -При работе моторов возникают вибрации, отрицательно влияющие на показания датчиков полетного контроллера Pixhawk. Чтобы избежать этого эффекта, количество слоев двустороннего скотча +1. Клеим 2х сторонний скотч по углам полетного контроллера. ![Полетный контроллер](assets/pixhawk.png) + > **ВАЖНО** При работе моторов возникают вибрации, отрицательно влияющие на показания датчиков полетного контроллера PixHawk. Чтобы избежать этого эффекта, количество слоев двустороннего скотча лучше увеличить до 4-5. - -2. Установить полетный контроллер в центр рамы - - ![Полетный контроллер](assets/topviewpixhawk.png) -##### ВАЖНО -Стрелки на раме и pixhawk должны быть сонаправлены +2. Установить полетный контроллер в центр рамы. ![Полетный контроллер](assets/topviewpixhawk.png) + > **ВАЖНО** Стрелки на раме и PixHawk должны быть сонаправлены #### Подключение полетного контроллера по схеме @@ -368,47 +339,31 @@ ![Подключение полетного контроллера](assets/connectionPixhawk.png) - ### Сборка регуляторов -1. Клеим 2х сторонний скотч на основание защитного бокса регуляторов -![Скотч на бокс регулей](assets/escCase.png) - -2. Укладываем регуляторы в защитные боксы. Крепим полученную сборку к лучам рамы. -![Вид сверху с боксами для регулей](assets/topESCcaseview.png) +1. Клеим 2х сторонний скотч на основание защитного бокса регуляторов. ![Скотч на бокс регулей](assets/escCase.png) +2. Укладываем регуляторы в защитные боксы. Крепим полученную сборку к лучам рамы. ![Вид сверху с боксами для регулей](assets/topESCcaseview.png) ### Установка защиты -1. Закрепить нижнюю защиту винтами М3х16 на лучах рамы -![Установка лучевой защиты](assets/lowsafeDeck.png) - -2. Закрепить ножки к пластиковым держателям винтами М3х16 -![Установка ножек](assets/safeLegs.png) - -3. Закрепить стойки 30 мм в отверстия нижней защиты винтами М3х12 -![Установка нижней радиальной защиты](assets/safelowRadial.png) - -4. Закрепить верхнюю защиту винтами М3х12 -![Установка верхней радиальной защиты](assets/safehighRadial.png) +1. Закрепить нижнюю защиту винтами М3х16 на лучах рамы. ![Установка лучевой защиты](assets/lowsafeDeck.png) +2. Закрепить ножки к пластиковым держателям винтами М3х16. ![Установка ножек](assets/safeLegs.png) +3. Закрепить стойки 30 мм в отверстия нижней защиты винтами М3х12. ![Установка нижней радиальной защиты](assets/safelowRadial.png) +4. Закрепить верхнюю защиту винтами М3х12. ![Установка верхней радиальной защиты](assets/safehighRadial.png) ### Монтаж отсека АКБ -Необходимые компоненты +Необходимые компоненты: + * Винты М3х12 (4 шт) * Гайки М3 (4 шт) * Рама дополнительная (1 шт) * Батарейный отсек (1 шт) -1. Прикрепить батарейный отсек на верхнюю дополнительную раму винтами М3х12 и гайками. -![Монтаж отсека АКБ](assets/mountHolder.png) - -2. Прикрепить верхнюю дополнительную раму на стойки винтами М3х8. - -![Монтаж отсека АКБ](assets/isoViewmountHolder.png) - +1. Прикрепить батарейный отсек на верхнюю дополнительную раму винтами М3х12 и гайками. ![Монтаж отсека АКБ](assets/mountHolder.png) +2. Прикрепить верхнюю дополнительную раму на стойки винтами М3х8. ![Монтаж отсека АКБ](assets/isoViewmountHolder.png) 3. Установить АКБ в отсек. - ### Монтаж антенн 1. Крепим антенны на 2х сторонний скотч или изоленту, а усики продеваем в передние отверстия верхней дополнительной рамы. @@ -417,16 +372,11 @@ Коптер готов к настройке! - ## Безопасность при сборке и настройке 1. Снять пропеллеры.“Все наземные операции производить со снятыми пропеллерами. Устанавливать пропеллеры на моторы только перед полётом.” - -2. Отключить аккумулятор. Держать питание выключенным. -“Сборку, настройку и ремонт производить с отключенным питанием. Подключать питание только для тестирования электронных компонентов коптера. После тестирования перед другими работами питание сразу отключить.” - -3. Позвать на помощь -“Если при выполнении работ возникли какие-либо проблемы, необходимо обратиться к преподавателю или учителю, а не пытаться решить проблему самостоятельно.” +2. Отключить аккумулятор. Держать питание выключенным. “Сборку, настройку и ремонт производить с отключенным питанием. Подключать питание только для тестирования электронных компонентов коптера. После тестирования перед другими работами питание сразу отключить.” +3. Позвать на помощь. “Если при выполнении работ возникли какие-либо проблемы, необходимо обратиться к преподавателю или учителю, а не пытаться решить проблему самостоятельно.” ![Безопасность при сборке](assets/safetybyassem.png) @@ -436,4 +386,4 @@ 2. При подключении (отключении) аккумуляторов держаться только за разъёмы, тянуть или дергать за провода запрещается. 3. В случае обрыва разъемов, обнаружения нарушений целостности изоляции или корпуса аккумулятора, не трогая его, немедленно сообщить преподавателю. -## [ТЕХНИКА БЕЗОПАСНОСТИ ПРИ ПАЙКЕ И ЛЁТНОЙ ЭКСПЛУАТАЦИИ КОПТЕРОВ](safety.md) +[ТЕХНИКА БЕЗОПАСНОСТИ ПРИ ПАЙКЕ И ЛЁТНОЙ ЭКСПЛУАТАЦИИ КОПТЕРОВ](safety.md) diff --git a/docs/assemble_clever3_4in1.md b/docs/assemble_clever3_4in1.md new file mode 100644 index 00000000..60bcb461 --- /dev/null +++ b/docs/assemble_clever3_4in1.md @@ -0,0 +1,154 @@ +# Инструкция по сборке конструктора Клевер 3 + +В данной инструкции рассматривается сборка комплекта COEX Clever 3 с платой регуляторов 4в1 + +![Clever](assets/clever3_main.jpg) + +## Состав конструктора + +TODO + +## Дополнительное оборудование + +![Дополнительное оборудование](assets/additonal_eqipment.jpg) + +## Условное обозначение + +![Условные обозначения](assets/conditional_refer.jpg) + +## Техника безопасности при пайке + +Перед использованием паяльного оборудования обязательно ознакомьтесь с техникой безопасности +[Техника безопасности при пайке](tb.md) + +## Установка моторов + +1. Распаковать моторы +2. Закрепить мотор на луче шестигранными винтами М3х6 (самые короткие винты в комплекте с моторами). *Шестигранный ключ в комплекте. +3. Вставить гайки М3 (4 шт) в пластиковый держатель. + > Для удобства можно использовать длинный винт, либо плоскогубцы +4. Закрепить луч, нижнюю защиту луча и держатель винтами М3х12, используя крестовую отвертку. +5. Скрепить хомутом луч и нижнюю защиту луча. + > Хвост от хомута (стяжки) отрезать ножницами ![Подготовка моторов](assets/cl3_prepareMotors.JPG) + +## Монтаж каркасных элементов + +1. Установить пластиковые гайки М3 (4 шт) для крепления PDB на раму винтами М3х8 +2. Установить стойки 6 мм (4 шт) для крепления Raspberry Pi на раму винтами М3х8 +3. Установить на раму собранную конструкцию, соблюдая схему, винтами М3х16 +4. Установить каркас для светодиодной ленты, используя прорези в держателях для ножек + +![Монтаж стоек на раму](assets/cl3_mountElements.JPG) + +## Монтаж преобразователя напряжения BEC (Припаять и проверить) + +1. Распаковать плату питания и установить шлейф питания +2. Включить мультиметр в режим измерения постоянного напряжения (диапазон 20В или 200В) +3. Проверяем работоспособность платы питания, подключив АКБ + * a. Выходное напряжение на разъеме XT30 должно равняться напряжению на АКБ (от 10В до 12.6В) + * b. Выходное напряжение на шлейфе питания должно быть в пределах 4.9В до 5.3В + > Измеряем между черным и красным проводами +4. Распаковываем преобразователь напряжения и снимаем прозрачную изоляцию +5. Припаиваем два дополнительных провода на BEC + * a. Берем из набора 3 провода папа-мама (красный, черный и любого цвета) + * b. Красный и черный [залуживаем](zap.md) с обеих сторон, используя пинцет. На синем проводе залуживаем со стороны коннектора ПАПА. + Залудить - это: + * Нанести флюс на оголенную часть провода. + * Покрыть припоем. + * c. Припаиваем красный и черный провода к BEC: ЧЕРНЫЙ -> OUT-, КРАСНЫЙ -> OUT+ +6. Проверяем работу BEC + * a. Припаиваем BEC на плату питания. ЧЕРНЫЙ -> -, КРАСНЫЙ -> + + * b. Подключаем АКБ и проверяем напряжение на припаянных проводах к BEC (из пункта 5) 5В - все правильно! больше 10В - отключите питание и переставьте желтую перемычку на другой пинцет, 0В - плохо спаяли + * с. Если BEC выдает 5В, то изолируем паячное соединение черной термоусадкой. +7. Монтаж светодиодной ленты. Припаять провода от BEC (из пункта 5) к светодиодной ленте + * a. Удалить силиконовый слой на ленте (надрезать ножом и оторвать) + * b. [Залудить](zap.md) контакты светодиодной ленты + * c. + * Красный -> +5V + * Черный -> GND + * Синий -> Din + +![Монтаж преобразователя напряжения BEC ](assets/cl3_mountBEC.JPG) + +## Монтаж платы регуляторов 4в1 и платы питания PDB + +1. Установить плату регуляторов 4в1 как показано на картинке. Соединить фазные провода моторов с проводами регуляторов. +2. Закрепить плату регуляторов стойками 6 мм (4 шт.). На стойки накрутить пластиковые гайки М3 (4 шт.). +3. Установить плату распределения питания PDB как показано на картинке (разъем XT60 направлен к хвосту коптера). +4. Соединить разъемы питания платы питания и платы регуляторов XT30. + +![Монтаж платы питания](assets/cl3_mountESC.JPG) + +## Сопряжение приемника и пульта + +1. Подключаем провод 5В от BEC в разъем приемника. Устанавливаем BIND разъем в крайний правый порт B/VCC +2. Подключаем АКБ. Индикатор на приемники должен быстро мигать (режим сброса). +3. Зажимаем и удерживаем кнопку BIND на пульте и включаем пульт. На пульте отображается процесс сопряжения RXBinding. +4. После установки сопряжения (появление доп строк на дисплее пульта), убираем BIND разъем из приемника. Отключаем АКБ. + +![Сопряжение приемника и пульта](assets/cl3_bindFlysky.JPG) + +> Если пульт не включается или заблокирован, то смотри здесь +[Неисправности пульта](radioerrors1.md) + +## Проверка направления вращения моторов + +1. Включить пульт. Убедиться, что ppm в меню RX Setup отключен ([раздел "Нет связи с полетным контроллером"](radioerrors1.md) в пункте 3 выберите “RX setup” > “PPM OUTPUT” > “Off”. Сохраните изменения (удерживаем нажатой кнопку “CANCEL”) +2. Подключите оранжевый провод S1 от платы регуляторов в CH3 на приемнике. Подключить внешнее питание. +3. Подать левым стиком газ (throttle) на 10%. +4. Проверить направления вращения мотора по схеме.Повторить для каждого мотора. Таким образом, будет понятно каким именно мотором мы управляем +5. Если необходимо изменить направление вращения, то меняем любые два фазных провода мотора (нужно переподключить). + +![Проверка направления вращения моторов](assets/cl3_testMotorsFlysky.JPG) + +## Монтаж и подключение полетного контроллера PixRacer + +1. Установить Полетный контроллер PixRacer на двухстороний скотч 3М (2-3 слоя). *также полетный контроллер можно извлечь из корпуса и жестко установить на стойки М3х6 + +2. Установить стойки 40 мм, используя винты М3х8. Подключить разъем POWER + +3. Подключить регуляторы, как на картинке. Подробно [про подключение регуляторов 4в1](cl3_connectESC4in1.md) +4. Подключить шлейф радиоприемника в разъем RCIN в PixRacer ![Монтаж полетного контроллера](assets/cl3_mountPixracer.JPG) + +## Монтаж Raspberry Pi + +1. Перевернуть коптер. Установить Raspberry на стойки, используя монтажные отверстия Raspberry. USB-разъемы направлены к хвостовой части коптера +2. Установка шлейфа для камеры + * a. поднять защелку + * b. подключить шлейф + * c. закрыть защелку +3. Подключение питания Raspberry + * 5В -> pin 04 (DC power 5v) + * GND -> pin 06 (Ground) + * Подключение светодиодной ленты pin 40 (GPIO21) +4. Сборка маунта для камеры Raspberry Pi. Используйте винт М3х16 и гайку М3. ![Монтаж Raspberry Pi Model B](assets/cl3_mountRaspberryPi.JPG) + +## Монтаж Arduino и радиоприемника FlySky + +1. Произведите монтаж пинов микроконтроллера Arduino Nano, используя пайку +2. Установить миконтроллер в специальной маунт и прикрепите к нижней деке, используя винты М3х16 (4 шт.) +3. Используя 2хсторонний скотч прикрепите приемник, как показано на рисунке +4. Подключите шлейф радиоприемника от PixRacer как на рисунке: + * белый -> PPM + * красный -> 5V + * черный -> GND + * оранжевый, зеленый -> сейчас не используются. Устанавливаются в неиспользуемые пины радиоприемника. ![Монтаж Arduino nano и радиоприемника Flysky i6](assets/cl3_mountArduinoandFlysky.JPG) + +## Монтаж камеры Raspberry Pi + +1. Установить маунт для камеры Raspberry Pi в сборе на нижнюю деку винтами М3х12 (2 шт.) +2. Подключить шлейф к камере Raspberry Pi +3. Установить камеру в маунт, закрепить саморезами М2 +4. Закрепить Raspberry стойками 30 мм (4 шт.). Установить нижнюю деку в сборе на стойки винтами М3х8 (4шт.). +5. Установить ножки в маунты (4 шт.) ![Монтаж камеры RPi](assets/cl3_mountRpiCamera.JPG). + +## Монтаж остальных конструктивных элементов + +1. Установка нижней защиты, используя винты М3х12 (8 шт.) и стойки 30 мм (8 шт.) +2. Установка верхней защиты, используя винты М3х12 (8 шт.) +3. Установка ремешка верхнюю деку для фиксации АКБ. Закрепить верхнюю деку винтами М3х8 (4 шт.). ![Монтаж остальных конструктивных элементов](assets/cl3_mountOtherElements.JPG) + +## Монтаж USB соединителей + +1. Соедините PixRacer и Raspberry Pi, используя micro USB - USB кабель +2. Соедините Arduino и Raspberry Pi, используя micro USB - USB кабель. ![Монтаж USB соединителей](assets/cl3_mountUSBconnectors.JPG) diff --git a/docs/assets/additonal_eqipment.jpg b/docs/assets/additonal_eqipment.jpg new file mode 100644 index 00000000..5866d35a Binary files /dev/null and b/docs/assets/additonal_eqipment.jpg differ diff --git a/docs/assets/cl3_bindFlysky.JPG b/docs/assets/cl3_bindFlysky.JPG new file mode 100644 index 00000000..8f70e81d Binary files /dev/null and b/docs/assets/cl3_bindFlysky.JPG differ diff --git a/docs/assets/cl3_mountArduinoandFlysky.JPG b/docs/assets/cl3_mountArduinoandFlysky.JPG new file mode 100644 index 00000000..df954e18 Binary files /dev/null and b/docs/assets/cl3_mountArduinoandFlysky.JPG differ diff --git a/docs/assets/cl3_mountBEC.JPG b/docs/assets/cl3_mountBEC.JPG new file mode 100644 index 00000000..764ba475 Binary files /dev/null and b/docs/assets/cl3_mountBEC.JPG differ diff --git a/docs/assets/cl3_mountESC.JPG b/docs/assets/cl3_mountESC.JPG new file mode 100644 index 00000000..ab9c673e Binary files /dev/null and b/docs/assets/cl3_mountESC.JPG differ diff --git a/docs/assets/cl3_mountElements.JPG b/docs/assets/cl3_mountElements.JPG new file mode 100644 index 00000000..2dd29af2 Binary files /dev/null and b/docs/assets/cl3_mountElements.JPG differ diff --git a/docs/assets/cl3_mountElements2.png b/docs/assets/cl3_mountElements2.png new file mode 100644 index 00000000..4b17add9 Binary files /dev/null and b/docs/assets/cl3_mountElements2.png differ diff --git a/docs/assets/cl3_mountOtherElements.JPG b/docs/assets/cl3_mountOtherElements.JPG new file mode 100644 index 00000000..20983c63 Binary files /dev/null and b/docs/assets/cl3_mountOtherElements.JPG differ diff --git a/docs/assets/cl3_mountPDB1.png b/docs/assets/cl3_mountPDB1.png new file mode 100644 index 00000000..a00d1815 Binary files /dev/null and b/docs/assets/cl3_mountPDB1.png differ diff --git a/docs/assets/cl3_mountPixracer.JPG b/docs/assets/cl3_mountPixracer.JPG new file mode 100644 index 00000000..51c42a1c Binary files /dev/null and b/docs/assets/cl3_mountPixracer.JPG differ diff --git a/docs/assets/cl3_mountRaspberryPi.JPG b/docs/assets/cl3_mountRaspberryPi.JPG new file mode 100644 index 00000000..090de8b5 Binary files /dev/null and b/docs/assets/cl3_mountRaspberryPi.JPG differ diff --git a/docs/assets/cl3_mountRpiCamera.JPG b/docs/assets/cl3_mountRpiCamera.JPG new file mode 100644 index 00000000..7c496fdf Binary files /dev/null and b/docs/assets/cl3_mountRpiCamera.JPG differ diff --git a/docs/assets/cl3_mountUSBconnectors.JPG b/docs/assets/cl3_mountUSBconnectors.JPG new file mode 100644 index 00000000..3b961b98 Binary files /dev/null and b/docs/assets/cl3_mountUSBconnectors.JPG differ diff --git a/docs/assets/cl3_mountingMotors.png b/docs/assets/cl3_mountingMotors.png new file mode 100644 index 00000000..75eebfc8 Binary files /dev/null and b/docs/assets/cl3_mountingMotors.png differ diff --git a/docs/assets/cl3_prepareMotors.JPG b/docs/assets/cl3_prepareMotors.JPG new file mode 100644 index 00000000..f1290b47 Binary files /dev/null and b/docs/assets/cl3_prepareMotors.JPG differ diff --git a/docs/assets/cl3_testMotorsFlysky.JPG b/docs/assets/cl3_testMotorsFlysky.JPG new file mode 100644 index 00000000..988d701d Binary files /dev/null and b/docs/assets/cl3_testMotorsFlysky.JPG differ diff --git a/docs/assets/clever3_main.jpg b/docs/assets/clever3_main.jpg new file mode 100644 index 00000000..993a6776 Binary files /dev/null and b/docs/assets/clever3_main.jpg differ diff --git a/docs/assets/conditional_refer.jpg b/docs/assets/conditional_refer.jpg new file mode 100644 index 00000000..f533b7bb Binary files /dev/null and b/docs/assets/conditional_refer.jpg differ diff --git a/docs/assets/hciuart_error.jpg b/docs/assets/hciuart_error.jpg new file mode 100644 index 00000000..b7ece83a Binary files /dev/null and b/docs/assets/hciuart_error.jpg differ diff --git a/docs/bundle.md b/docs/bundle.md index 770d094c..32a2c708 100644 --- a/docs/bundle.md +++ b/docs/bundle.md @@ -26,6 +26,6 @@ * ОС [Raspbian Jessie](https://www.raspberrypi.org/downloads/raspbian/) * Фреймворк [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 и другие * Пакет программ clever_bundle diff --git a/docs/connection.md b/docs/connection.md index 66d00ede..4972996f 100644 --- a/docs/connection.md +++ b/docs/connection.md @@ -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: @@ -14,7 +14,7 @@ rostopic echo /mavros/state Подключение по 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: @@ -28,7 +28,7 @@ rostopic echo /mavros/state sudo systemctl restart clever ``` -> **Hint** Для корректной работы подключения Raspberry Pi и PixHawk по USB необходимо установить значение параметра `CBRK_USB_CHK` на 197848. +> **Hint** Для корректной работы подключения Raspberry Pi и Pixhawk по USB необходимо установить значение параметра `CBRK_USB_CHK` на 197848. Подключение по UART --- @@ -47,7 +47,7 @@ TODO схема подключения sudo systemctl restart clever ``` -> **Hint** Для корректной работы подключения Raspberry Pi и PixHawk по UART необходимо установить значение параметра `SYS_COMPANION` на 921600. +> **Hint** Для корректной работы подключения Raspberry Pi и Pixhawk по UART необходимо установить значение параметра `SYS_COMPANION` на 921600. Подключение к SITL --- diff --git a/docs/drugoe.md b/docs/drugoe.md new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/docs/drugoe.md @@ -0,0 +1,2 @@ + + diff --git a/docs/firmware.md b/docs/firmware.md index 07a829a6..e54edc72 100644 --- a/docs/firmware.md +++ b/docs/firmware.md @@ -1,16 +1,16 @@ -Прошивка PixHawk / PixRacer +Прошивка Pixhawk / Pixracer === -PixHawk или PixRacer можно прошить, используя QGroundControl или утилиты командной строки. +Pixhawk или Pixracer можно прошить, используя QGroundControl или утилиты командной строки. Различные варианты сборок стабильных прошивок PX4 можно скачать в разделе [Releases на GitHub](https://github.com/PX4/Firmware/releases). В названии файла прошивки кодируется информации о целевой плате и варианте сборки. Примеры: -* `px4fmu-v2_default.px4` — прошивка для PixHawk с EKF2. -* `px4fmu-v2_lpe.px4` — прошивка для PixHawk с LPE. -* `px4fmu-v4_default.px4` — прошивка для PixRacer с EKF2 и LPE (*Клевер 3*). -* `px4fmu-v3_default.px4` — прошивка для более новых версий PixHawk (чип ревизии 3, см. илл. + Bootloader v5) с EKF2 и LPE. +* `px4fmu-v2_default.px4` — прошивка для Pixhawk с EKF2. +* `px4fmu-v2_lpe.px4` — прошивка для Pixhawk с LPE. +* `px4fmu-v4_default.px4` — прошивка для Pixracer с EKF2 и LPE (*Клевер 3*). +* `px4fmu-v3_default.px4` — прошивка для более новых версий Pixhawk (чип ревизии 3, см. илл. + Bootloader v5) с EKF2 и LPE. ![](assets/stmrev.jpg) @@ -19,9 +19,9 @@ PixHawk или PixRacer можно прошить, используя QGroundCon 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-кабель до окончания процесса прошивки. @@ -46,7 +46,7 @@ make px4fmu-v4_default upload Где `px4fmu-v4_default` – требуемый вариант прошивки. -Для загрузки прошивки `v3` в PixHawk может понадобиться команда `force_upload`: +Для загрузки прошивки `v3` в Pixhawk может понадобиться команда `force_upload`: ``` make px4fmu-v3_default force-upload diff --git a/docs/flight_logs.md b/docs/flight_logs.md index aaea03dd..f3ee9745 100644 --- a/docs/flight_logs.md +++ b/docs/flight_logs.md @@ -38,7 +38,7 @@ Мониторинг топиков в режиме реального времени --- -Для более новых версий платы PixHawk (`px4fmu-v3`), а также для плат PixRacer, в прошивку включен модуль `topic_listener`, который позволяет просматривать значения топиков в режиме реального времени (в том числе в полете). +Для более новых версий платы Pixhawk (`px4fmu-v3`), а также для плат Pixracer, в прошивку включен модуль `topic_listener`, который позволяет просматривать значения топиков в режиме реального времени (в том числе в полете). Для ее использования нужно выбрать вкладку Mavlink Console в QGroundControl: diff --git a/docs/glossary.md b/docs/glossary.md index 97ea72c1..dc17c597 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -11,7 +11,7 @@ ## Полетный контроллер / автопилот **1\.** Специализированная плата, спроектированная для управления мультикоптером, самолетом или другим аппаратом. Примеры: -PixHawk, Ardupilot, Naze32, CC3D. +Pixhawk, Ardupilot, Naze32, CC3D. **2\.** Программное обеспечение для платы управления мультикоптером. Примеры: PX4, APM, CleanFlight. @@ -47,11 +47,11 @@ Armed – состояние коптера готовности к полету ## PX4 -Популярный полетный контроллер с открытым исходным кодом, работащий на платах PixHawk, PixRacer и других. PX4 рекомендуется для использования на Клевере. +Популярный полетный контроллер с открытым исходным кодом, работащий на платах Pixhawk, Pixracer и других. PX4 рекомендуется для использования на Клевере. ## APM / ArduPilot -Полетный контроллер с открытым исходным кодом, изначально созданный для платы Arduino. Впоследствии был портирован на PixHawk, PixRacer и другие платы. +Полетный контроллер с открытым исходным кодом, изначально созданный для платы Arduino. Впоследствии был портирован на Pixhawk, Pixracer и другие платы. ## MAVLink @@ -64,3 +64,7 @@ Armed – состояние коптера готовности к полету ## MAVROS Библиотека-связующее звено между аппаратом, работающем по протоколу MAVLink, и ROS. + +## UART + +Последовательный асинхронный интерфейс передачи данных, применяемый во многих устройствах. Например GPS антенны, Wi-Fi роутеры или Pixhawk. diff --git a/docs/lessons.md b/docs/lessons.md index 38d0351f..e5f9fe68 100644 --- a/docs/lessons.md +++ b/docs/lessons.md @@ -49,3 +49,8 @@ Часть 6 + +Автономные полеты + + + diff --git a/docs/mavlink.md b/docs/mavlink.md index 0e34dcc4..45934c1e 100644 --- a/docs/mavlink.md +++ b/docs/mavlink.md @@ -2,7 +2,7 @@ Основная документация: https://mavlink.io/en/. -MAVLink – это протокол для организации связи между автономными летательными и транспортными системами (дронами, самолетами, автомобилями). Проктол MAVLink лежит в основе взаимодействия между PixHawk и Raspberry Pi. +MAVLink – это протокол для организации связи между автономными летательными и транспортными системами (дронами, самолетами, автомобилями). Проктол MAVLink лежит в основе взаимодействия между Pixhawk и Raspberry Pi. В Клевер включено 2 обертки над этим протоколом: [MAVROS](mavros.md) и [simple_offboard](simple_offboard.md). diff --git a/docs/mavros.md b/docs/mavros.md index c61a4333..5fa901b4 100644 --- a/docs/mavros.md +++ b/docs/mavros.md @@ -1,6 +1,6 @@ # MAVROS -Основная статья: [http://wiki.ros.org/mavros](http://wiki.ros.org/mavros) +Основная документация: [http://wiki.ros.org/mavros](http://wiki.ros.org/mavros) MAVROS \(MAVLink + ROS\) — это пакет для ROS, предоставляющий возможность управлять беспилотниками по протоколу [MAVLink](mavlink.md). MAVROS поддерживает полетные стеки PX4 и APM. Связь организовывается по UART, USB, TCP или UDP. @@ -8,6 +8,10 @@ MAVROS подписывается определенные ROS-топики в Нода MAVROS автоматически запускается в launch-файле Клевера. Для [настройки типа подключения](connection.md) см. аргумент `fcu_conn`. +> **Hint** Упрощенное взаимодействие с коптером возможно с использованием пакета [`simple_offboard`](simple_offboard.md). + +> **Note** В пакете `clever` некоторые плагины MAVROS отключены (в целях сохранения ресурсов). Подробнее см. параметр `plugin_blacklist` в файле `/home/pi/catkin_ws/src/clever/clever/launch/mavros.launch`. + ## Основные сервисы `/mavros/set_mode` — установить [полетный режим](modes.md) контроллера. Обычно устанавливается режим OFFBOARD \(для управления с Raspberry Pi\). @@ -18,7 +22,7 @@ MAVROS подписывается определенные ROS-топики в `/mavros/state` — статус подключения к полетному контроллеру. Режим полетного контроллера. -`/mavros/local_position/pose` — локальная позиция коптера в системе координат ENU. +`/mavros/local_position/pose` — локальная позиция коптера в системе координат ENU и его ориентация. `/mavros/local_position/velocity` — текущая скорость в локальных координатах. Угловые скорости. @@ -28,6 +32,8 @@ MAVROS подписывается определенные ROS-топики в `/mavros/global_position/rel_alt` — относительная высота \(относительно высоты включения моторов\). +Просмотр сообщений, публикуемых в топики возможен с помощью утилиты `rostopic`, например `rostopic echo /mavros/state`. Подробнее см. [работа с ROS](ros.md). + ## Основные топики для публикации `/mavros/setpoint_position/local` — установить целевую позицию и рысканье \(yaw\) беспилотника \(в системе координат ENU\). @@ -45,5 +51,3 @@ MAVROS подписывается определенные ROS-топики в `/mavros/setpoint_raw/attitude` — отправка пакета [SET\_ATTITUDE\_TARGET](https://pixhawk.ethz.ch/mavlink/#SET_ATTITUDE_TARGET). Позвлояет установить целевую ориенатацию /угловые скорости и уровень газа. Выбор устанавливаемых величин осуществляется с помощью поля `type_mask` `/mavros/setpoint_raw/global` — отправка пакета [SET\_POSITION\_TARGET\_GLOBAL\_INT](https://pixhawk.ethz.ch/mavlink/#SET_POSITION_TARGET_GLOBAL_INT). Позволяет установить целевую позицию в глобальных координатах \(ширина, долгота, высота\), а также скорости полета. **Не поддерживается в PX4** \([issue](https://github.com/PX4/Firmware/issues/7552)\). - -[Упрощенное управление коптером с помощью Simple Offboard](simple_offboard.md). diff --git a/docs/metodmaterials.md b/docs/metodmaterials.md index fadf5285..f926c829 100644 --- a/docs/metodmaterials.md +++ b/docs/metodmaterials.md @@ -50,7 +50,7 @@ **Подведение итогов** -Ниже предложен один из вариантов подведения итогов курса. +Ниже предложен один из вариантов подведения итогов курса. Финальное мероприятие включает 3 раздела: @@ -155,7 +155,7 @@ | 5 | Заключение | Подвести итоги занятия, спросить, есть ли у класса вопросы. Спросить, что из изученного на занятии было для них интереснее всего. Попросить учеников ответить на контрольные вопросы. Предложить ученикам по желанию провести в интернете дополнительное исследование на пройденную тему. Сообщить ученикам, какую тему они будут проходить на следующем занятии. | | 6 | Резервное время | Показать видео и рассказать классу интересные факты по пройденной теме, не вошедшие в программу. | -## Урок №6. Тема: «Бесколлекторные двигатели и регуляторы их хода» +## Урок №6. Тема: «Бесколлекторные двигатели и регуляторы их хода» **Цель урока:** закрепить теоретические знания о строении и работе бесколлекторных электродвигателей. Сформировать знания о работе и настройке регуляторов хода, @@ -381,7 +381,7 @@ | 5 | Меняем SSID | Рассказать, что такое SSID. Научить изменять имя wi-fi сети. Объяснить что такое демоны и в какой момент они запускаются. Проработать с конфигурацией одного из них. | | 6 | Используем права суперпользователя | Рассказать о типах и правах пользователей системы. Показать примеры использования sudo. | | 7 | Подготовка коптера к автономным полетам | Проверить подключенное оборудование для автономных полетов. Убедиться в работоспособности подключения можно выполнив на Raspberry Pi: rostopic echo /mavros/state | -| 8 | Использование QGroundControl через Wi-Fi | Настроить беспроводное соединение для работы с PixHawk в QGroundControl. Предложить учащимся установить новую прошивку, которая подходит для автономных полетов и откалибровать коптер при беспроводном подключении. | +| 8 | Использование QGroundControl через Wi-Fi | Настроить беспроводное соединение для работы с Pixhawk в QGroundControl. Предложить учащимся установить новую прошивку, которая подходит для автономных полетов и откалибровать коптер при беспроводном подключении. | | 9 | Заключение | Подвести итоги занятия, спросить, есть ли у класса вопросы, их должно быть много, нужно заранее продумать ответы на них. Попросить учеников ответить на контрольные вопросы. Предложить ученикам по желанию провести в интернете дополнительное исследование на пройденную тему. Сообщить ученикам, какую тему они будут проходить на следующем занятии.| | 10 | | | diff --git a/docs/network.md b/docs/network.md index b5c4d316..a1469588 100644 --- a/docs/network.md +++ b/docs/network.md @@ -5,7 +5,7 @@ Wi-Fi адаптер на Raspberry Pi имеет два основных реж 1. **Режим клиента** – RPi подключается к существующей Wi-Fi сети. 2. **Режим точки доступа** – RPi создает Wi-Fi сеть, к которой вы можете подключиться. -При использовании [образа для RPi](microsd_images.md) по умолчанию Wi-Fi адаптер работает в режиме точки доступа. +При использовании [образа для RPi](microsd_images.md) по умолчанию Wi-Fi адаптер работает в [режиме точки доступа](wifi.md). ## Инструкция для переключения адаптера в режим клиента diff --git a/docs/rasp1.md b/docs/rasp1.md index ba62c256..45f0e175 100644 --- a/docs/rasp1.md +++ b/docs/rasp1.md @@ -19,4 +19,4 @@ Raspberry Pi означает «малиновый пирог». Этот сво * домашний медиа-сервер * «мозговой центр» для автоматизированных станков или роботов -Собственно, в последнем качестве мы и будем его использовать, благодаря возможности подключения его к автопилоту PixHawk. +Собственно, в последнем качестве мы и будем его использовать, благодаря возможности подключения его к автопилоту Pixhawk. diff --git a/docs/rc.md b/docs/rc.md index 961a598c..6ac7f326 100644 --- a/docs/rc.md +++ b/docs/rc.md @@ -16,6 +16,8 @@ > **Note** Мобильный пульт конфликтует с реальной аппаратурой радиоуправления. Во время использования мобильного пульта она должна быть выключена. +> **Warning** Открытое соединение QGroundControl или rviz пересылает большие объемы данных по Wi-Fi, что может негативно сказаться на отзывчивости мобильного пульта. Рекомендуется не использовать эти приложения одновременно с ним. + Установите [образ Clever на RPi](microsd_images.md). Для работы приложения параметры `rosbridge` и `rc` в launch-файле (`~/catkin_ws/src/clever/clever/launch/clever.launch`) должны быть включены: ```xml @@ -53,4 +55,4 @@ sudo systemctl restart clever * Если интерфейс пульта отображает явно неправильное напряжение (напр. > 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). diff --git a/docs/rviz.md b/docs/rviz.md index cf7bfa11..a549baf2 100644 --- a/docs/rviz.md +++ b/docs/rviz.md @@ -30,3 +30,9 @@ export ROS_IP=192.168.11.1 В качестве reference frame рекомендуется установить фрейм `local_origin`. Для визуализации коптера можно добавить визуализационные маркеры из топика `/vehicle_markers`. Можно просмотреть картинку с дополненной реальностью из топика основной камеры `/main_camera/image_raw`. 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 +``` diff --git a/docs/setup.md b/docs/setup.md index 9967dc06..7ff298f3 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -282,4 +282,4 @@ Далее: [Настройка-полетного-контролера](aruco.md#Настройка-полетного-контролера) -Далее: [Подключение Raspberry Pi к PixHawk](connection.md). +Далее: [Подключение Raspberry Pi к Pixhawk](connection.md). diff --git a/docs/simple_offboard.md b/docs/simple_offboard.md index 931f1876..b508f0ab 100644 --- a/docs/simple_offboard.md +++ b/docs/simple_offboard.md @@ -1,9 +1,7 @@ Simple offboard === -> **Warning** Это описание API версии 0.5. См. [описание API предыдущих версий](https://github.com/CopterExpress/clever/blob/67051b21a05b12e2e9e519cb640565bccb80fbe3/docs/simple_offboard.md). - -Модуль `simple_offboard` пакета `clever` предназначен для упрощенного программирования автономного дрона (режим `OFFBOARD`). Он позволяет устанавливать желаемые полетные задачи и автоматически трансформирует [систему координат](frames.md). +Модуль `simple_offboard` пакета `clever` предназначен для упрощенного программирования автономного дрона ([режим](modes.md) `OFFBOARD`). Он позволяет устанавливать желаемые полетные задачи и автоматически трансформирует [систему координат](frames.md). `simple_offboard` является высокоуровневым способом взаимодействия с полетным контроллером. Для более низкоуровневой работы см. [mavros](mavros.md). @@ -162,7 +160,7 @@ navigate(x=3, y=2, z=2, speed=1, frame_id='aruco_map', update_frame=True) Вращение на месте со скоростью 0.5 рад/c (против часовой): ```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 рад/с: diff --git a/docs/snippets.md b/docs/snippets.md index 536bf97d..34c248ec 100644 --- a/docs/snippets.md +++ b/docs/snippets.md @@ -71,16 +71,29 @@ while True: 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 +PI_2 = math.pi / 2 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))) +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: diff --git a/docs/ssh.md b/docs/ssh.md index 4082057e..a7cb048c 100644 --- a/docs/ssh.md +++ b/docs/ssh.md @@ -13,4 +13,6 @@ ssh pi@192.168.11.1 Для доступа по SSH из Windows можно использовать [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html). +Также можно получить доступ по SSH со смартфона с помощью приложения [Termius](https://www.termius.com). + Подробнее: https://www.raspberrypi.org/documentation/remote-access/ssh/README.md diff --git a/docs/testovoe-opisanie-klevera-po-shablonu-robotsrosorggapter.md b/docs/testovoe-opisanie-klevera-po-shablonu-robotsrosorggapter.md new file mode 100644 index 00000000..8a303923 --- /dev/null +++ b/docs/testovoe-opisanie-klevera-po-shablonu-robotsrosorggapter.md @@ -0,0 +1,2 @@ +https://robots.ros.org/gapter/ + diff --git a/docs/uart.md b/docs/uart.md new file mode 100644 index 00000000..5a02f6b8 --- /dev/null +++ b/docs/uart.md @@ -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 +```