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/.gitignore b/.gitignore index 960e17c6..2d9f8e04 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -/deploy/ros_lib/ *.pyc +*.DS_Store +/images \ No newline at end of file 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/.travis.yml b/.travis.yml new file mode 100644 index 00000000..ab5164e8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,35 @@ +sudo: required +language: generic +services: + - docker +env: + global: + - DOCKER="smirart/img-tool:v0.1" + - TARGET_REPO="https://github.com/${TRAVIS_REPO_SLUG}.git" + - if [[ -z ${TRAVIS_TAG} ]]; then IMAGE_VERSION="${TRAVIS_COMMIT}}"; else IMAGE_VERSION="${TRAVIS_TAG}"; fi + - IMAGE_NAME="$(basename -s '.git' ${TARGET_REPO})_${IMAGE_VERSION}.img" +git: + depth: 1 +before_script: + - docker pull ${DOCKER} +script: + - docker run --privileged --rm -v /dev:/dev -v $(pwd):/builder/repo -e TRAVIS_TAG="${TRAVIS_TAG}" ${DOCKER} +before_deploy: + # Set up git user name and tag this commit + - git config --local user.name "urpylka" + - git config --local user.email "urpylka@gmail.com" + - sudo chmod -R 777 * + - cd images && zip ${IMAGE_NAME}.zip ${IMAGE_NAME} +deploy: + provider: releases + api_key: ${GITHUB_OAUTH_TOKEN} + file: ${IMAGE_NAME}.zip + skip_cleanup: true + on: + tags: true + +# More info there +# https://github.com/travis-ci/travis-ci/issues/6893 +# https://docs.travis-ci.com/user/customizing-the-build/ +# https://docs.travis-ci.com/user/deployment/releases +# https://docs.travis-ci.com/user/environment-variables/ 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/README.md b/README.md index 1731917a..4c9b63a4 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Use it to learn how to assemble, configure, pilot and program autonomous CLEVER **Preconfigured image for Raspberry Pi 3 with installed and configured software, ready to fly, is available [in the Releases section](https://github.com/CopterExpress/clever/releases).** -[![Build Status](http://builder.coex.space/job/CopterExpress---clever/badge/icon)](http://builder.coex.space/job/CopterExpress---clever/) +[![Build Status](https://travis-ci.org/CopterExpress/clever.svg?branch=master)](https://travis-ci.org/CopterExpress/clever) Image includes: diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 742dfa97..00000000 --- a/_config.yml +++ /dev/null @@ -1,2 +0,0 @@ -theme: jekyll-theme-cayman -tagline: Конструктор программируемого квадрокоптера 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/aruco_pose/package.xml b/aruco_pose/package.xml index b4da81c3..f3dece62 100644 --- a/aruco_pose/package.xml +++ b/aruco_pose/package.xml @@ -4,59 +4,32 @@ 0.0.0 ArUco maps precise pose estimation nodelet - - - Oleg Kalachev + MIT + + Oleg Kalachev + Artem Smirnov - - - - TODO - - - - - - - - - - - - - - - - - - - - - - - - - catkin - nodelet roscpp image_transport cv_bridge tf - + + catkin + nodelet roscpp image_transport cv_bridge - tf + + - + - diff --git a/book.json b/book.json index d996280a..65a9c13b 100644 --- a/book.json +++ b/book.json @@ -14,6 +14,9 @@ }, "yametrika": { "id": 49359238 + }, + "image-captions": { + "caption": "_CAPTION_" } }, "structure": { diff --git a/builder/assets/butterfly.service b/builder/assets/butterfly.service new file mode 100644 index 00000000..a822c816 --- /dev/null +++ b/builder/assets/butterfly.service @@ -0,0 +1,6 @@ +[Unit] +Description=Butterfly Terminal Server + +[Service] +ExecStart=/usr/local/bin/butterfly.server.py --host="0.0.0.0" --unsecure +User=pi diff --git a/builder/assets/butterfly.socket b/builder/assets/butterfly.socket new file mode 100644 index 00000000..4cf35362 --- /dev/null +++ b/builder/assets/butterfly.socket @@ -0,0 +1,5 @@ +[Socket] +ListenStream=57575 + +[Install] +WantedBy=sockets.target diff --git a/deploy/clever.service b/builder/assets/clever.service similarity index 77% rename from deploy/clever.service rename to builder/assets/clever.service index 282ab0af..1aeb0604 100644 --- a/deploy/clever.service +++ b/builder/assets/clever.service @@ -4,7 +4,7 @@ Requires=roscore.service After=roscore.service [Service] -EnvironmentFile=/home/pi/catkin_ws/src/clever/deploy/roscore.env +EnvironmentFile=/lib/systemd/system/roscore.env ExecStart=/opt/ros/kinetic/bin/roslaunch clever clever.launch --wait Restart=on-abort diff --git a/builder/assets/hardware_setup.sh b/builder/assets/hardware_setup.sh new file mode 100755 index 00000000..901f4dea --- /dev/null +++ b/builder/assets/hardware_setup.sh @@ -0,0 +1,78 @@ +#! /usr/bin/env bash + +# +# Script for build the image. Used builder script of the target repo +# For build: docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/builder/repo smirart/builder +# +# Copyright (C) 2018 Copter Express Technologies +# +# Author: Artem Smirnov +# + +set -e # Exit immidiately on non-zero result + +echo_stamp() { + # TEMPLATE: echo_stamp + # TYPE: SUCCESS, ERROR, INFO + + # More info there https://www.shellhacks.com/ru/bash-colors/ + + TEXT="$(date '+[%Y-%m-%d %H:%M:%S]') $1" + TEXT="\e[1m$TEXT\e[0m" # BOLD + + case "$2" in + SUCCESS) + TEXT="\e[32m${TEXT}\e[0m";; # GREEN + ERROR) + TEXT="\e[31m${TEXT}\e[0m";; # RED + *) + TEXT="\e[34m${TEXT}\e[0m";; # BLUE + esac + echo -e ${TEXT} +} + +################################################## +# Configure hardware interfaces +################################################## + +# 1. Enable sshd +echo_stamp "#1 Turn on sshd" +touch /boot/ssh +# /usr/bin/raspi-config nonint do_ssh 0 + +# 2. Enable GPIO +echo_stamp "#2 GPIO enabled by default" + +# 3. Enable I2C +echo_stamp "#3 Turn on I2C" +/usr/bin/raspi-config nonint do_i2c 0 + +# 4. Enable SPI +echo_stamp "#4 Turn on SPI" +/usr/bin/raspi-config nonint do_spi 0 + +# 5. Enable raspicam +echo_stamp "#5 Turn on raspicam" +/usr/bin/raspi-config nonint do_camera 0 + +# 6. Enable hardware UART +echo_stamp "#6 Turn on UART" +# Temporary solution +# https://github.com/RPi-Distro/raspi-config/pull/75 +/usr/bin/raspi-config nonint do_serial 1 +/usr/bin/raspi-config nonint set_config_var enable_uart 1 /boot/config.txt +/usr/bin/raspi-config nonint set_config_var dtoverlay pi3-disable-bt /boot/config.txt +systemctl disable hciuart.service + +# After adding to Raspbian OS +# https://github.com/RPi-Distro/raspi-config/commit/d6d9ecc0d9cbe4aaa9744ae733b9cb239e79c116 +#/usr/bin/raspi-config nonint do_serial 2 + +# 7. Enable V4L driver http://robocraft.ru/blog/electronics/3158.html +#echo "bcm2835-v4l2" >> /etc/modules +echo_stamp "#7 Turn on v4l2 driver" +if ! grep -q "^bcm2835-v4l2" /etc/modules; +then printf "bcm2835-v4l2\n" >> /etc/modules +fi + +echo_stamp "#8 End of configure hardware interfaces" diff --git a/builder/assets/index.html b/builder/assets/index.html new file mode 100644 index 00000000..9c3074ca --- /dev/null +++ b/builder/assets/index.html @@ -0,0 +1,13 @@ +

CLEVER Drone Kit Tools

+ + + + diff --git a/builder/assets/init_rpi.sh b/builder/assets/init_rpi.sh new file mode 100755 index 00000000..94873288 --- /dev/null +++ b/builder/assets/init_rpi.sh @@ -0,0 +1,43 @@ +#! /usr/bin/env bash + +# +# Script for build the image. Used builder script of the target repo +# For build: docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/builder/repo smirart/builder +# +# Copyright (C) 2018 Copter Express Technologies +# +# Author: Artem Smirnov +# + +set -e # Exit immidiately on non-zero result + +echo_stamp() { + # TEMPLATE: echo_stamp + # TYPE: SUCCESS, ERROR, INFO + + # More info there https://www.shellhacks.com/ru/bash-colors/ + + TEXT="$(date '+[%Y-%m-%d %H:%M:%S]') $1" + TEXT="\e[1m$TEXT\e[0m" # BOLD + + case "$2" in + SUCCESS) + TEXT="\e[32m${TEXT}\e[0m";; # GREEN + ERROR) + TEXT="\e[31m${TEXT}\e[0m";; # RED + *) + TEXT="\e[34m${TEXT}\e[0m";; # BLUE + esac + echo -e ${TEXT} +} + +echo_stamp "Rename SSID" +sudo sed -i.OLD "s/CLEVER/CLEVER-$(head -c 100 /dev/urandom | xxd -ps -c 100 | sed -e 's/[^0-9]//g' | cut -c 1-4)/g" /etc/wpa_supplicant/wpa_supplicant.conf + +echo_stamp "Harware setup" +/root/hardware_setup.sh + +echo_stamp "Remove init scripts" +rm /root/init_rpi.sh /root/hardware_setup.sh + +echo_stamp "End of initialization of the image" diff --git a/image_builder/kinetic-ros-coex.rosinstall b/builder/assets/kinetic-ros-clever.rosinstall similarity index 99% rename from image_builder/kinetic-ros-coex.rosinstall rename to builder/assets/kinetic-ros-clever.rosinstall index f5b7c7eb..eda4a821 100644 --- a/image_builder/kinetic-ros-coex.rosinstall +++ b/builder/assets/kinetic-ros-clever.rosinstall @@ -418,10 +418,6 @@ local-name: nodelet_core/nodelet uri: https://github.com/ros-gbp/nodelet_core-release/archive/release/kinetic/nodelet/1.9.14-0.tar.gz version: nodelet_core-release-release-kinetic-nodelet-1.9.14-0 -- tar: - local-name: opencv3 - uri: https://github.com/ros-gbp/opencv3-release/archive/release/kinetic/opencv3/3.3.1-5.tar.gz - version: opencv3-release-release-kinetic-opencv3-3.3.1-5 - tar: local-name: orocos_kinematics_dynamics/orocos_kdl uri: https://github.com/smits/orocos-kdl-release/archive/release/kinetic/orocos_kdl/1.3.1-0.tar.gz @@ -676,5 +672,5 @@ version: vision_opencv-release-release-kinetic-cv_bridge-1.12.8-0 - tar: local-name: web_video_server - uri: https://github.com/RobotWebTools-release/web_video_server-release/archive/release/kinetic/web_video_server/0.0.7-0.tar.gz - version: web_video_server-release-release-kinetic-web_video_server-0.0.7-0 + uri: https://github.com/RobotWebTools-release/web_video_server-release/archive/release/kinetic/web_video_server/0.1.0-0.tar.gz + version: web_video_server-release-release-kinetic-web_video_server-0.1.0-0 diff --git a/builder/assets/kinetic-rosdep-clever.yaml b/builder/assets/kinetic-rosdep-clever.yaml new file mode 100644 index 00000000..80ad31f5 --- /dev/null +++ b/builder/assets/kinetic-rosdep-clever.yaml @@ -0,0 +1,528 @@ +actionlib: + debian: + stretch: [ros-kinetic-actionlib] +actionlib_msgs: + debian: + stretch: [ros-kinetic-actionlib-msgs] +angles: + debian: + stretch: [ros-kinetic-angles] +async_web_server_cpp: + debian: + stretch: [ros-kinetic-async-web-server-cpp] +bond: + debian: + stretch: [ros-kinetic-bond] +bondcpp: + debian: + stretch: [ros-kinetic-bondcpp] +bondpy: + debian: + stretch: [ros-kinetic-bondpy] +camera_calibration_parsers: + debian: + stretch: [ros-kinetic-camera-calibration-parsers] +camera_info_manager: + debian: + stretch: [ros-kinetic-camera-info-manager] +catkin: + debian: + stretch: [ros-kinetic-catkin] +class_loader: + debian: + stretch: [ros-kinetic-class-loader] +cmake_modules: + debian: + stretch: [ros-kinetic-cmake-modules] +cpp_common: + debian: + stretch: [ros-kinetic-cpp-common] +cv_bridge: + debian: + stretch: [ros-kinetic-cv-bridge] +cv_camera: + debian: + stretch: [ros-kinetic-cv-camera=0.3.1-0stretch] +diagnostic_msgs: + debian: + stretch: [ros-kinetic-diagnostic-msgs] +diagnostic_updater: + debian: + stretch: [ros-kinetic-diagnostic-updater] +eigen_conversions: + debian: + stretch: [ros-kinetic-eigen-conversions] +gencpp: + debian: + stretch: [ros-kinetic-gencpp] +geneus: + debian: + stretch: [ros-kinetic-geneus] +genlisp: + debian: + stretch: [ros-kinetic-genlisp] +genmsg: + debian: + stretch: [ros-kinetic-genmsg] +gennodejs: + debian: + stretch: [ros-kinetic-gennodejs] +genpy: + debian: + stretch: [ros-kinetic-genpy] +geographic_msgs: + debian: + stretch: [ros-kinetic-geographic-msgs] +geometry_msgs: + debian: + stretch: [ros-kinetic-geometry-msgs] +image_transport: + debian: + stretch: [ros-kinetic-image-transport] +libmavconn: + debian: + stretch: [ros-kinetic-libmavconn] +lxml: + debian: + stretch: [python-lxml=3.7.1-1] +mavlink: + debian: + stretch: [ros-kinetic-mavlink] +mavros: + debian: + stretch: [ros-kinetic-mavros] +mavros_msgs: + debian: + stretch: [ros-kinetic-mavros-msgs] +mavros_extras: + debian: + stretch: [ros-kinetic-mavros-extras] +message_filters: + debian: + stretch: [ros-kinetic-message-filters] +message_generation: + debian: + stretch: [ros-kinetic-message-generation] +message_runtime: + debian: + stretch: [ros-kinetic-message-runtime] +mjpg-streamer: + debian: + stretch: [mjpg-streamer=2.0] +mk: + debian: + stretch: [ros-kinetic-mk] +nav_msgs: + debian: + stretch: [ros-kinetic-nav-msgs] +nodelet: + debian: + stretch: [ros-kinetic-nodelet] +opencv3: + debian: + stretch: [ros-kinetic-opencv3] +orocos_kdl: + debian: + stretch: [ros-kinetic-orocos-kdl] +pluginlib: + debian: + stretch: [ros-kinetic-pluginlib] +python_orocos_kdl: + debian: + stretch: [ros-kinetic-python-orocos-kdl] +ros: + debian: + stretch: [ros-kinetic-ros] +ros_comm: + debian: + stretch: [ros-kinetic-ros-comm] +ros_environment: + debian: + stretch: [ros-kinetic-ros-environment] +rosapi: + debian: + stretch: [ros-kinetic-rosapi] +rosauth: + debian: + stretch: [ros-kinetic-rosauth] +rosbag: + debian: + stretch: [ros-kinetic-rosbag] +rosbag_migration_rule: + debian: + stretch: [ros-kinetic-rosbag-migration-rule] +rosbag_storage: + debian: + stretch: [ros-kinetic-rosbag-storage] +rosbash: + debian: + stretch: [ros-kinetic-rosbash] +rosboost_cfg: + debian: + stretch: [ros-kinetic-rosboost-cfg] +rosbridge_library: + debian: + stretch: [ros-kinetic-rosbridge-library] +rosbridge_server: + debian: + stretch: [ros-kinetic-rosbridge-server] +rosbuild: + debian: + stretch: [ros-kinetic-rosbuild] +rosclean: + debian: + stretch: [ros-kinetic-rosclean] +rosconsole: + debian: + stretch: [ros-kinetic-rosconsole] +rosconsole_bridge: + debian: + stretch: [ros-kinetic-rosconsole-bridge] +roscpp: + debian: + stretch: [ros-kinetic-roscpp] +roscpp_serialization: + debian: + stretch: [ros-kinetic-roscpp-serialization] +roscpp_traits: + debian: + stretch: [ros-kinetic-roscpp-traits] +roscreate: + debian: + stretch: [ros-kinetic-roscreate] +rosgraph: + debian: + stretch: [ros-kinetic-rosgraph] +rosgraph_msgs: + debian: + stretch: [ros-kinetic-rosgraph-msgs] +roslang: + debian: + stretch: [ros-kinetic-roslang] +roslaunch: + debian: + stretch: [ros-kinetic-roslaunch] +roslib: + debian: + stretch: [ros-kinetic-roslib] +roslint: + debian: + stretch: [ros-kinetic-roslint] +roslisp: + debian: + stretch: [ros-kinetic-roslisp] +roslz4: + debian: + stretch: [ros-kinetic-roslz4] +rosmake: + debian: + stretch: [ros-kinetic-rosmake] +rosmaster: + debian: + stretch: [ros-kinetic-rosmaster] +rosmsg: + debian: + stretch: [ros-kinetic-rosmsg] +rosnode: + debian: + stretch: [ros-kinetic-rosnode] +rosout: + debian: + stretch: [ros-kinetic-rosout] +rospack: + debian: + stretch: [ros-kinetic-rospack] +rosparam: + debian: + stretch: [ros-kinetic-rosparam] +rospy: + debian: + stretch: [ros-kinetic-rospy] +rospy_tutorials: + debian: + stretch: [ros-kinetic-rospy-tutorials] +rosserial_client: + debian: + stretch: [ros-kinetic-rosserial-client] +rosserial_msgs: + debian: + stretch: [ros-kinetic-rosserial-msgs] +rosserial_python: + debian: + stretch: [ros-kinetic-rosserial-python] +rosservice: + debian: + stretch: [ros-kinetic-rosservice] +rostest: + debian: + stretch: [ros-kinetic-rostest] +rostime: + debian: + stretch: [ros-kinetic-rostime] +rostopic: + debian: + stretch: [ros-kinetic-rostopic] +rosunit: + debian: + stretch: [ros-kinetic-rosunit] +roswtf: + debian: + stretch: [ros-kinetic-roswtf] +sensor_msgs: + debian: + stretch: [ros-kinetic-sensor-msgs] +smclib: + debian: + stretch: [ros-kinetic-smclib] +std_msgs: + debian: + stretch: [ros-kinetic-std-msgs] +std_srvs: + debian: + stretch: [ros-kinetic-std-srvs] +stereo_msgs: + debian: + stretch: [ros-kinetic-stereo-msgs] +tf2: + debian: + stretch: [ros-kinetic-tf2] +tf2_bullet: + debian: + stretch: [ros-kinetic-tf2-bullet] +tf2_eigen: + debian: + stretch: [ros-kinetic-tf2-eigen] +tf2_geometry_msgs: + debian: + stretch: [ros-kinetic-tf2-geometry-msgs] +tf2_kdl: + debian: + stretch: [ros-kinetic-tf2-kdl] +tf2_msgs: + debian: + stretch: [ros-kinetic-tf2-msgs] +tf2_py: + debian: + stretch: [ros-kinetic-tf2-py] +tf2_ros: + debian: + stretch: [ros-kinetic-tf2-ros] +tf2_sensor_msgs: + debian: + stretch: [ros-kinetic-tf2-sensor-msgs] +tf2_tools: + debian: + stretch: [ros-kinetic-tf2-tools] +tf: + debian: + stretch: [ros-kinetic-tf] +topic_tools: + debian: + stretch: [ros-kinetic-topic-tools] +trajectory_msgs: + debian: + stretch: [ros-kinetic-trajectory-msgs] +urdf: + debian: + stretch: [ros-kinetic-urdf] +urdf_parser_plugin: + debian: + stretch: [ros-kinetic-urdf-parser-plugin] +uuid_msgs: + debian: + stretch: [ros-kinetic-uuid-msgs] +visualization_msgs: + debian: + stretch: [ros-kinetic-visualization-msgs] +xmlrpcpp: + debian: + stretch: [ros-kinetic-xmlrpcpp] +boost: + debian: + stretch: [libboost-all-dev] +bullet: + debian: + stretch: [libbullet-dev] +bzip2: + debian: + stretch: [libbz2-dev] +cmake: + debian: + stretch: [cmake] +cppunit: + debian: + stretch: [libcppunit-dev] +eigen: + debian: + stretch: [libeigen3-dev] +geographiclib-tools: + debian: + stretch: [geographiclib-tools] +geographiclib: + debian: + stretch: [libgeographic-dev] +google-mock: + debian: + stretch: [google-mock] +graphviz: + debian: + stretch: [graphviz] +gtest: + debian: + stretch: [libgtest-dev] +libconsole-bridge-dev: + debian: + stretch: [libconsole-bridge-dev] +libjpeg: + debian: + stretch: [libjpeg-dev] +libpng-dev: + debian: + stretch: [libpng-dev] +libpoco-dev: + debian: + stretch: [libpoco-dev] +libssl-dev: + debian: + stretch: [libssl-dev] +libtiff-dev: + debian: + stretch: [libtiff5-dev] +liburdfdom-dev: + debian: + stretch: [liburdfdom-dev] +liburdfdom-headers-dev: + debian: + stretch: [liburdfdom-headers-dev] +libv4l-dev: + debian: + stretch: [libv4l-dev] +libvtk-qt: + debian: + stretch: [libvtk6-qt-dev] +libwebp-dev: + debian: + stretch: [libwebp-dev] +log4cxx: + debian: + stretch: [liblog4cxx-dev] +lz4: + debian: + stretch: [liblz4-dev] +pkg-config: + debian: + stretch: [pkg-config] +protobuf: + debian: + stretch: [libprotobuf10] +python-bson: + debian: + stretch: [python-bson] +python-catkin-pkg: + debian: + stretch: [python-catkin-pkg] +python-coverage: + debian: + stretch: [python-coverage] +python-defusedxml: + debian: + stretch: [python-defusedxml] +python-empy: + debian: + stretch: [python-empy] +python-future: + debian: + stretch: [python-future] +python-imaging: + debian: + stretch: [python-imaging] +python-lxml: + debian: + stretch: [python-lxml] +python-mock: + debian: + stretch: [python-mock] +python-netifaces: + debian: + stretch: [python-netifaces] +python-nose: + debian: + stretch: [python-nose] +python-numpy: + debian: + stretch: [python-numpy] +python-paramiko: + debian: + stretch: [python-paramiko] +python-rosdep: + debian: + stretch: [python-rosdep] +python-rospkg: + debian: + stretch: [python-rospkg] +python-serial: + debian: + stretch: [python-serial] +python-setuptools: + debian: + stretch: [python-setuptools] +python-sip: + debian: + stretch: [python-sip-dev] +python-tornado: + debian: + stretch: [python-tornado] +python-twisted-core: + debian: + stretch: [python-twisted-core] +python-websocket: + debian: + stretch: [python-websocket] +python-wxtools: + debian: + stretch: [python-wxtools] +python-yaml: + debian: + stretch: [python-yaml] +python: + debian: + stretch: [python-dev] +sbcl: + debian: + stretch: [sbcl] +tinyxml2: + debian: + stretch: [libtinyxml2-dev] +tinyxml: + debian: + stretch: [libtinyxml-dev] +uuid: + debian: + stretch: [uuid-dev] +web_video_server: + debian: + stretch: [ros-kinetic-web-video-server] +v4l-utils: + debian: + stretch: [v4l-utils] +yaml-cpp: + debian: + stretch: [libyaml-cpp-dev] +zlib: + debian: + stretch: [zlib1g-dev] +compressed_depth_image_transport: + debian: + stretch: [ros-kinetic-compressed-depth-image-transport] +compressed_image_transport: + debian: + stretch: [ros-kinetic-compressed-image-transport] +dynamic_reconfigure: + debian: + stretch: [ros-kinetic-dynamic-reconfigure] +theora_image_transport: + debian: + stretch: [ros-kinetic-theora-image-transport] +libogg: + debian: + stretch: [libtheora0=1.1.1+dfsg.1-14] diff --git a/builder/assets/monkey-clever b/builder/assets/monkey-clever new file mode 100644 index 00000000..112d990f --- /dev/null +++ b/builder/assets/monkey-clever @@ -0,0 +1,57 @@ +# Default Host - Configuration +# ============================ +# Here the variable principals of the program are defined in respect +# to the configuration of the different types of directives. + +[HOST] + # ServerName: + # ----------- + # Allow you to set a host and domain name (e.g monkey.linuxchile.cl). If + # you are working in a local network just set your IP address or if you + # are working like localhost set your loopback address (127.0.0.1). + + ServerName 0.0.0.0 + + # DocumentRoot: + # ------------- + # This variable corresponds to the location of the main server directory + # of the web pages, where the files of your site are located. + # + # Example: + # DocumentRoot /home/krypton/htdocs + + DocumentRoot /usr/share/monkey-static + + # Redirect: + # --------- + # Under specific conditions, you may want the server performs a HTTP + # redirect when this Virtual Host is reach. If that is the case, append + # to the Redirect key the value of the address where to redirect the + # HTTP client. + # + # Redirect http://monkey-project.com + +[LOGGER] + # AccessLog: + # ---------- + # Registration file of correct request. + + AccessLog /var/log/monkey-clever/access.log + + # ErrorLog: + # --------- + # Registration file of incorrect request. + + ErrorLog /var/log/monkey-clever/error.log + +[ERROR_PAGES] + 404 404.html + +[HANDLERS] + # FastCGI + # ======= + # Match /.*\.php fastcgi + + # CGI + # === + # Match /cgi-bin/.*\.cgi cgi diff --git a/builder/assets/monkey.service b/builder/assets/monkey.service new file mode 100644 index 00000000..4e2d4451 --- /dev/null +++ b/builder/assets/monkey.service @@ -0,0 +1,9 @@ +[Unit] +Description=Monkey web-server + +[Service] +ExecStart=/usr/sbin/monkey --port 80 --workers 1 +Restart=on-abort + +[Install] +WantedBy=multi-user.target diff --git a/deploy/roscore.env b/builder/assets/roscore.env similarity index 100% rename from deploy/roscore.env rename to builder/assets/roscore.env diff --git a/deploy/roscore.service b/builder/assets/roscore.service similarity index 76% rename from deploy/roscore.service rename to builder/assets/roscore.service index 56f949ac..5e3a5a7e 100644 --- a/deploy/roscore.service +++ b/builder/assets/roscore.service @@ -3,7 +3,7 @@ Description=Launcher for the ROS master, parameter server and rosout logging nod After=network.target [Service] -EnvironmentFile=/home/pi/catkin_ws/src/clever/deploy/roscore.env +EnvironmentFile=/lib/systemd/system/roscore.env ExecStart=/opt/ros/kinetic/bin/roscore Restart=on-abort diff --git a/builder/image-build.sh b/builder/image-build.sh new file mode 100755 index 00000000..27656508 --- /dev/null +++ b/builder/image-build.sh @@ -0,0 +1,106 @@ +#! /usr/bin/env bash + +# +# Script for build the image. Used builder script of the target repo +# For build: docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/builder/repo smirart/builder +# +# Copyright (C) 2018 Copter Express Technologies +# +# Author: Artem Smirnov +# + +set -e # Exit immidiately on non-zero result + +SOURCE_IMAGE="http://repo.coex.space/2018-06-27-raspbian-stretch-lite.zip" + +export DEBIAN_FRONTEND=${DEBIAN_FRONTEND:='noninteractive'} +export LANG=${LANG:='C.UTF-8'} +export LC_ALL=${LC_ALL:='C.UTF-8'} + +echo_stamp() { + # TEMPLATE: echo_stamp + # TYPE: SUCCESS, ERROR, INFO + + # More info there https://www.shellhacks.com/ru/bash-colors/ + + TEXT="$(date '+[%Y-%m-%d %H:%M:%S]') $1" + TEXT="\e[1m$TEXT\e[0m" # BOLD + + case "$2" in + SUCCESS) + TEXT="\e[32m${TEXT}\e[0m";; # GREEN + ERROR) + TEXT="\e[31m${TEXT}\e[0m";; # RED + *) + TEXT="\e[34m${TEXT}\e[0m";; # BLUE + esac + echo -e ${TEXT} +} + +BUILDER_DIR="/builder" +REPO_DIR="${BUILDER_DIR}/repo" +SCRIPTS_DIR="${REPO_DIR}/builder" +IMAGES_DIR="${REPO_DIR}/images" + +[[ ! -d ${SCRIPTS_DIR} ]] && (echo_stamp "Directory ${SCRIPTS_DIR} doesn't exist" "ERROR"; exit 1) +[[ ! -d ${IMAGES_DIR} ]] && mkdir ${IMAGES_DIR} && echo_stamp "Directory ${IMAGES_DIR} was created successful" "SUCCESS" + +if [[ -z ${TRAVIS_TAG} ]]; then IMAGE_VERSION="$(cd ${REPO_DIR}; git log --format=%h -1)"; else IMAGE_VERSION="${TRAVIS_TAG}"; fi +# IMAGE_VERSION="${TRAVIS_TAG:=$(cd ${REPO_DIR}; git log --format=%h -1)}" +REPO_URL="$(cd ${REPO_DIR}; git remote --verbose | grep origin | grep fetch | cut -f2 | cut -d' ' -f1 | sed 's/git@github\.com\:/https\:\/\/github.com\//')" +REPO_NAME="$(basename -s '.git' ${REPO_URL})" +IMAGE_NAME="${REPO_NAME}_${IMAGE_VERSION}.img" +IMAGE_PATH="${IMAGES_DIR}/${IMAGE_NAME}" + +get_image() { + # TEMPLATE: get_image + local BUILD_DIR=$(dirname $1) + local RPI_ZIP_NAME=$(basename $2) + local RPI_IMAGE_NAME=$(echo ${RPI_ZIP_NAME} | sed 's/zip/img/') + + if [ ! -e "${BUILD_DIR}/${RPI_ZIP_NAME}" ]; then + echo_stamp "Downloading original Linux distribution" \ + && wget -nv -O ${BUILD_DIR}/${RPI_ZIP_NAME} $2 \ + && echo_stamp "Downloading complete" "SUCCESS" \ + || (echo_stamp "Downloading was failed!" "ERROR"; exit 1) + else echo_stamp "Linux distribution already donwloaded"; fi + + echo_stamp "Unzipping Linux distribution image" \ + && unzip -p ${BUILD_DIR}/${RPI_ZIP_NAME} ${RPI_IMAGE_NAME} > $1 \ + && echo_stamp "Unzipping complete" "SUCCESS" \ + || (echo_stamp "Unzipping was failed!" "ERROR"; exit 1) +} + +get_image ${IMAGE_PATH} ${SOURCE_IMAGE} + +# Make free space +${BUILDER_DIR}/image-resize.sh ${IMAGE_PATH} max '7G' + +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/init_rpi.sh' '/root/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/hardware_setup.sh' '/root/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-init.sh' ${IMAGE_VERSION} ${SOURCE_IMAGE} + +# Monkey +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/monkey-clever' '/root/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/index.html' '/usr/share/monkey-static/' + +# Butterfly +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/butterfly.service' '/lib/systemd/system/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/butterfly.socket' '/lib/systemd/system/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/monkey.service' '/lib/systemd/system/' +# software install +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-software.sh' +# network setup +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-network.sh' + +# If RPi then use a one thread to build a ROS package on RPi, else use all +[[ $(arch) == 'armv7l' ]] && NUMBER_THREADS=1 || NUMBER_THREADS=$(nproc --all) +# Clever +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/clever.service' '/lib/systemd/system/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/roscore.env' '/lib/systemd/system/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/roscore.service' '/lib/systemd/system/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/kinetic-rosdep-clever.yaml' '/etc/ros/rosdep/' +# ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/kinetic-ros-clever.rosinstall' '/home/pi/ros_catkin_ws/' +${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-ros.sh' ${REPO_URL} ${IMAGE_VERSION} false false ${NUMBER_THREADS} + +${BUILDER_DIR}/image-resize.sh ${IMAGE_PATH} diff --git a/builder/image-init.sh b/builder/image-init.sh new file mode 100755 index 00000000..9448bc7f --- /dev/null +++ b/builder/image-init.sh @@ -0,0 +1,54 @@ +#! /usr/bin/env bash + +# +# Script for initialisation image +# +# Copyright (C) 2018 Copter Express Technologies +# +# Author: Artem Smirnov +# + +set -e # Exit immidiately on non-zero result + +echo_stamp() { + # TEMPLATE: echo_stamp + # TYPE: SUCCESS, ERROR, INFO + + # More info there https://www.shellhacks.com/ru/bash-colors/ + + TEXT="$(date '+[%Y-%m-%d %H:%M:%S]') $1" + TEXT="\e[1m$TEXT\e[0m" # BOLD + + case "$2" in + SUCCESS) + TEXT="\e[32m${TEXT}\e[0m";; # GREEN + ERROR) + TEXT="\e[31m${TEXT}\e[0m";; # RED + *) + TEXT="\e[34m${TEXT}\e[0m";; # BLUE + esac + echo -e ${TEXT} +} + +echo_stamp "Write CLEVER information" + +# Clever image version +echo "$1" >> /etc/clever_version +# Origin image file name +echo "${2%.*}" >> /etc/clever_origin + +echo_stamp "Write magic script to /etc/rc.local" +MAGIC_SCRIPT="sudo /root/init_rpi.sh; sudo sed -i '/sudo \\\/root\\\/init_rpi.sh/d' /etc/rc.local && sudo reboot" +sed -i "19a${MAGIC_SCRIPT}" /etc/rc.local + +# It needs for autosizer.sh & maybe that is correct +echo_stamp "Change boot partition" +sed -i 's/root=[^ ]*/root=\/dev\/mmcblk0p2/' /boot/cmdline.txt +sed -i 's/.* \/boot vfat defaults 0 2$/\/dev\/mmcblk0p1 \/boot vfat defaults 0 2/' /etc/fstab +sed -i 's/.* \/ ext4 defaults,noatime 0 1$/\/dev\/mmcblk0p2 \/ ext4 defaults,noatime 0 1/' /etc/fstab + +echo_stamp "Set max space for syslogs" +# https://unix.stackexchange.com/questions/139513/how-to-clear-journalctl +sed -i 's/#SystemMaxUse=/SystemMaxUse=200M/' /etc/systemd/journald.conf + +echo_stamp "End of init image" diff --git a/builder/image-network.sh b/builder/image-network.sh new file mode 100755 index 00000000..e085a322 --- /dev/null +++ b/builder/image-network.sh @@ -0,0 +1,73 @@ +#! /usr/bin/env bash + +# +# Script for network configure +# +# Copyright (C) 2018 Copter Express Technologies +# +# Author: Artem Smirnov +# + +set -e # Exit immidiately on non-zero result + +echo_stamp() { + # TEMPLATE: echo_stamp + # TYPE: SUCCESS, ERROR, INFO + + # More info there https://www.shellhacks.com/ru/bash-colors/ + + TEXT="$(date '+[%Y-%m-%d %H:%M:%S]') $1" + TEXT="\e[1m$TEXT\e[0m" # BOLD + + case "$2" in + SUCCESS) + TEXT="\e[32m${TEXT}\e[0m";; # GREEN + ERROR) + TEXT="\e[31m${TEXT}\e[0m";; # RED + *) + TEXT="\e[34m${TEXT}\e[0m";; # BLUE + esac + echo -e ${TEXT} +} + +echo_stamp "#1 Write to /etc/wpa_supplicant/wpa_supplicant.conf" + +# TODO: Use wpa_cli insted direct file edit +cat << EOF >> /etc/wpa_supplicant/wpa_supplicant.conf +network={ + ssid="CLEVER" + psk="cleverwifi" + mode=2 + proto=RSN + key_mgmt=WPA-PSK + pairwise=CCMP + group=CCMP + auth_alg=OPEN +} +EOF + +echo_stamp "#2 Write STATIC to /etc/dhcpcd.conf" + +cat << EOF >> /etc/dhcpcd.conf +interface wlan0 +static ip_address=192.168.11.1/24 +EOF + +echo_stamp "#3 Write dhcp-config to /etc/dnsmasq.conf" + +cat << EOF >> /etc/dnsmasq.conf +interface=wlan0 +address=/clever/coex/192.168.11.1 +dhcp-range=192.168.11.100,192.168.11.200,12h +no-hosts +filterwin2k +bogus-priv +domain-needed +quiet-dhcp6 +EOF + +#echo_stamp "#4 Write magic script for rename SSID to /etc/rc.local" +#RENAME_SSID="sudo sed -i.OLD \"s/CLEVER/CLEVER-\$(head -c 100 /dev/urandom | xxd -ps -c 100 | sed -e 's/[^0-9]//g' | cut -c 1-4)/g\" /etc/wpa_supplicant/wpa_supplicant.conf && sudo sed -i '/sudo sed/d' /etc/rc.local && sudo reboot" +#sed -i "19a$RENAME_SSID" /etc/rc.local + +echo_stamp "#5 End of network installation" diff --git a/builder/image-ros.sh b/builder/image-ros.sh new file mode 100755 index 00000000..81f74956 --- /dev/null +++ b/builder/image-ros.sh @@ -0,0 +1,176 @@ +#! /usr/bin/env bash + +# +# Script for build the image. Used builder script of the target repo +# For build: docker run --privileged -it --rm -v /dev:/dev -v $(pwd):/builder/repo smirart/builder +# +# Copyright (C) 2018 Copter Express Technologies +# +# Author: Artem Smirnov +# + +set -e # Exit immidiately on non-zero result + +REPO=$1 +REF=$2 +INSTALL_ROS_PACK_SOURCES=$3 +DISCOVER_ROS_PACK=$4 +NUMBER_THREADS=$5 + +echo_stamp() { + # TEMPLATE: echo_stamp + # TYPE: SUCCESS, ERROR, INFO + + # More info there https://www.shellhacks.com/ru/bash-colors/ + + TEXT="$(date '+[%Y-%m-%d %H:%M:%S]') $1" + TEXT="\e[1m$TEXT\e[0m" # BOLD + + case "$2" in + SUCCESS) + TEXT="\e[32m${TEXT}\e[0m";; # GREEN + ERROR) + TEXT="\e[31m${TEXT}\e[0m";; # RED + *) + TEXT="\e[34m${TEXT}\e[0m";; # BLUE + esac + echo -e ${TEXT} +} + +# https://gist.github.com/letmaik/caa0f6cc4375cbfcc1ff26bd4530c2a3 +# https://github.com/travis-ci/travis-build/blob/master/lib/travis/build/templates/header.sh +my_travis_retry() { + local result=0 + local count=1 + while [ $count -le 3 ]; do + [ $result -ne 0 ] && { + echo -e "\n${ANSI_RED}The command \"$@\" failed. Retrying, $count of 3.${ANSI_RESET}\n" >&2 + } + # ! { } ignores set -e, see https://stackoverflow.com/a/4073372 + ! { "$@"; result=$?; } + [ $result -eq 0 ] && break + count=$(($count + 1)) + sleep 1 + done + + [ $count -gt 3 ] && { + echo -e "\n${ANSI_RED}The command \"$@\" failed 3 times.${ANSI_RESET}\n" >&2 + } + + return $result +} + +# TODO: 'kinetic-rosdep-clever.yaml' should add only if we use our repo? +echo_stamp "Init rosdep" \ +&& rosdep init \ +&& echo "yaml file:///etc/ros/rosdep/kinetic-rosdep-clever.yaml" >> /etc/ros/rosdep/sources.list.d/20-default.list \ +&& rosdep update + +resolve_rosdep() { + # TEMPLATE: resolve_rosdep + CATKIN_PATH=$1 + ROS_DISTRO='kinetic' + OS_DISTRO='debian' + OS_VERSION='stretch' + + echo_stamp "Installing dependencies apps with rosdep in ${CATKIN_PATH}" + cd ${CATKIN_PATH} + my_travis_retry rosdep install -y --from-paths src --ignore-src --rosdistro ${ROS_DISTRO} -r --os=${OS_DISTRO}:${OS_VERSION} +} + +INSTALL_ROS_PACK_SOURCES=${INSTALL_ROS_PACK_SOURCES:='false'} +if [ "${INSTALL_ROS_PACK_SOURCES}" = "true" ]; then + DISCOVER_ROS_PACK=${DISCOVER_ROS_PACK:='true'} + if [ "${DISCOVER_ROS_PACK}" = "false" ]; then + echo_stamp "Preparing ros_comm packages to kinetic-ros_comm-wet.rosinstall" \ + && mkdir -p /home/pi/ros_catkin_ws && cd /home/pi/ros_catkin_ws \ + && rosinstall_generator ros_comm --rosdistro kinetic --deps --wet-only --tar > kinetic-ros_comm-wet.rosinstall \ + && wstool init -j${NUMBER_THREADS} src kinetic-ros_comm-wet.rosinstall \ + && echo_stamp "All roscomm sources was installed!" "SUCCESS" \ + || (echo_stamp "Some roscomm sources installation was failed!" "ERROR"; exit 1) + + echo_stamp "Preparing other ROS-packages to kinetic-custom_ros.rosinstall" \ + && cd /home/pi/ros_catkin_ws \ + && rosinstall_generator \ + actionlib actionlib_msgs angles async_web_server_cpp bond bond_core bondcpp bondpy camera_calibration_parsers camera_info_manager catkin class_loader cmake_modules cpp_common cv_bridge cv_camera diagnostic_msgs diagnostic_updater dynamic_reconfigure eigen_conversions gencpp geneus genlisp genmsg gennodejs genpy geographic_msgs geometry_msgs geometry2 image_transport compressed_image_transport libmavconn mavlink mavros_msgs message_filters message_generation message_runtime mk nav_msgs nodelet orocos_kdl pluginlib python_orocos_kdl ros ros_comm rosapi rosauth rosbag rosbag_migration_rule rosbag_storage rosbash rosboost_cfg rosbridge_library rosbridge_server rosbridge_suite rosbuild rosclean rosconsole rosconsole_bridge roscpp roscpp_serialization roscpp_traits roscreate rosgraph rosgraph_msgs roslang roslaunch roslib roslint roslisp roslz4 rosmake rosmaster rosmsg rosnode rosout rospack rosparam rospy rospy_tutorials rosserial rosserial_client rosserial_msgs rosserial_python rosservice rostest rostime rostopic rosunit roswtf sensor_msgs smclib std_msgs std_srvs stereo_msgs tf tf2 tf2_bullet tf2_eigen tf2_geometry_msgs tf2_kdl tf2_msgs tf2_py tf2_ros tf2_sensor_msgs tf2_tools topic_tools trajectory_msgs urdf urdf_parser_plugin usb_cam uuid_msgs visualization_msgs web_video_server xmlrpcpp mavros opencv3 mavros_extras interactive_markers tf2_web_republisher interactive_marker_proxy \ + --rosdistro kinetic --deps --wet-only --tar > kinetic-custom_ros.rosinstall \ + && wstool merge -j${NUMBER_THREADS} -t src kinetic-custom_ros.rosinstall \ + && wstool update -j${NUMBER_THREADS} -t src \ + && echo_stamp "All custom sources was installed!" "SUCCESS" \ + || (echo_stamp "Some custom sources installation was failed!" "ERROR"; exit 1) + else + echo_stamp "Creating ros_catkin_ws & getting all sources using wstool" \ + && mkdir -p /home/pi/ros_catkin_ws && cd /home/pi/ros_catkin_ws \ + && wstool init -j${NUMBER_THREADS} src kinetic-ros-clever.rosinstall \ + > /dev/null \ + && echo_stamp "All CLEVER sources was installed!" "SUCCESS" \ + || (echo_stamp "Some CLEVER sources installation was failed!" "ERROR"; exit 1) + fi + + resolve_rosdep '/home/pi/ros_catkin_ws' + + # TODO: Add refactor to origin repo + #echo_stamp "Refactoring usb_cam in SRC" + #sed -i '/#define __STDC_CONSTANT_MACROS/a\#define PIX_FMT_RGB24 AV_PIX_FMT_RGB24\n#define PIX_FMT_YUV422P AV_PIX_FMT_YUV422P' /home/pi/ros_catkin_ws/src/usb_cam/src/usb_cam.cpp + + echo_stamp "Building ros_catkin_ws packages" + cd /home/pi/ros_catkin_ws && ./src/catkin/bin/catkin_make_isolated --install -j${NUMBER_THREADS} -DCMAKE_BUILD_TYPE=Release --install-space /opt/ros/kinetic + + #echo_stamp "#11 Building light packages on 2 threads" + #cd /home/pi/ros_catkin_ws && ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release -j2 --install-space /opt/ros/kinetic --pkg actionlib actionlib_msgs angles async_web_server_cpp bond bond_core bondcpp bondpy camera_calibration_parsers camera_info_manager catkin class_loader cmake_modules cpp_common diagnostic_msgs diagnostic_updater dynamic_reconfigure eigen_conversions gencpp geneus genlisp genmsg gennodejs genpy geographic_msgs geometry_msgs geometry2 image_transport libmavconn mavlink mavros_msgs message_filters message_generation message_runtime mk nav_msgs nodelet orocos_kdl pluginlib python_orocos_kdl ros ros_comm rosapi rosauth rosbag rosbag_migration_rule rosbag_storage rosbash rosboost_cfg rosbridge_library rosbridge_server rosbridge_suite rosbuild rosclean rosconsole rosconsole_bridge roscpp roscpp_serialization roscpp_traits roscreate rosgraph rosgraph_msgs roslang roslaunch roslib roslint roslisp roslz4 rosmake rosmaster rosmsg rosnode rosout rospack rosparam rospy rospy_tutorials rosserial rosserial_client rosserial_msgs rosserial_python rosservice rostest rostime rostopic rosunit roswtf sensor_msgs smclib std_msgs std_srvs stereo_msgs tf tf2 tf2_bullet tf2_eigen tf2_geometry_msgs tf2_kdl tf2_msgs tf2_py tf2_ros tf2_sensor_msgs tf2_tools topic_tools trajectory_msgs urdf urdf_parser_plugin usb_cam uuid_msgs visualization_msgs xmlrpcpp + + #echo_stamp "#12 Building heavy packages" + # This command uses less threads to avoid Raspberry Pi freeze + #cd /home/pi/ros_catkin_ws && ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release -j1 --install-space /opt/ros/kinetic --pkg mavros opencv3 cv_bridge cv_camera mavros_extras web_video_server + + # Install builded packages + # WARNING: A major bug was found when using --pkg option (catkin_make_isolated doesn't install environment files) + # TODO: Can we increase threads number with HDD swap? + + echo_stamp "Remove build_isolated & devel_isolated from ros_catkin_ws" + rm -rf /home/pi/ros_catkin_ws/build_isolated /home/pi/ros_catkin_ws/devel_isolated + chown -Rf pi:pi /home/pi/ros_catkin_ws +fi + +echo_stamp "Installing CLEVER" \ +&& git clone ${REPO} /home/pi/catkin_ws/src/clever \ +&& cd /home/pi/catkin_ws/src/clever \ +&& echo "REF: ${REF}" \ +&& git checkout ${REF} \ +&& cd /home/pi/catkin_ws \ +&& resolve_rosdep $(pwd) \ +&& my_travis_retry pip install wheel \ +&& my_travis_retry pip install -r /home/pi/catkin_ws/src/clever/clever/requirements.txt \ +&& source /opt/ros/kinetic/setup.bash \ +&& catkin_make -j${NUMBER_THREADS} -DCMAKE_BUILD_TYPE=Release \ +&& systemctl enable roscore \ +&& systemctl enable clever \ +&& echo_stamp "All CLEVER was installed!" "SUCCESS" \ +|| (echo_stamp "CLEVER installation was failed!" "ERROR"; exit 1) + +# TODO move GeographicLib datasets to Mavros debian package +echo_stamp "Install GeographicLib datasets (needs for mavros)" \ +&& wget -qO- https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh | bash + +echo_stamp "Change permissions for catkin_ws" +chown -Rf pi:pi /home/pi/catkin_ws + +echo_stamp "Setup ROS environment" +cat << EOF >> /home/pi/.bashrc +LANG='C.UTF-8' +LC_ALL='C.UTF-8' +ROS_DISTRO='kinetic' +export ROS_IP='192.168.11.1' +source /opt/ros/kinetic/setup.bash +source /home/pi/catkin_ws/devel/setup.bash +EOF + +#echo_stamp "Removing local apt mirror" +# Restore original sources.list +#mv /var/sources.list.bak /etc/apt/sources.list +# Clean apt cache +apt-get clean -qq > /dev/null +# Remove local mirror repository key +#apt-key del COEX-MIRROR + +echo_stamp "END of ROS INSTALLATION" diff --git a/builder/image-software.sh b/builder/image-software.sh new file mode 100755 index 00000000..0e33ebd9 --- /dev/null +++ b/builder/image-software.sh @@ -0,0 +1,136 @@ +#! /usr/bin/env bash + +# +# Script for install software to the image. +# +# Copyright (C) 2018 Copter Express Technologies +# +# Author: Artem Smirnov +# + +set -e # Exit immidiately on non-zero result + +echo_stamp() { + # TEMPLATE: echo_stamp + # TYPE: SUCCESS, ERROR, INFO + + # More info there https://www.shellhacks.com/ru/bash-colors/ + + TEXT="$(date '+[%Y-%m-%d %H:%M:%S]') $1" + TEXT="\e[1m${TEXT}\e[0m" # BOLD + + case "$2" in + SUCCESS) + TEXT="\e[32m${TEXT}\e[0m";; # GREEN + ERROR) + TEXT="\e[31m${TEXT}\e[0m";; # RED + *) + TEXT="\e[34m${TEXT}\e[0m";; # BLUE + esac + echo -e ${TEXT} +} + +# https://gist.github.com/letmaik/caa0f6cc4375cbfcc1ff26bd4530c2a3 +# https://github.com/travis-ci/travis-build/blob/master/lib/travis/build/templates/header.sh +my_travis_retry() { + local result=0 + local count=1 + while [ $count -le 3 ]; do + [ $result -ne 0 ] && { + echo -e "\n${ANSI_RED}The command \"$@\" failed. Retrying, $count of 3.${ANSI_RESET}\n" >&2 + } + # ! { } ignores set -e, see https://stackoverflow.com/a/4073372 + ! { "$@"; result=$?; } + [ $result -eq 0 ] && break + count=$(($count + 1)) + sleep 1 + done + + [ $count -gt 3 ] && { + echo -e "\n${ANSI_RED}The command \"$@\" failed 3 times.${ANSI_RESET}\n" >&2 + } + + return $result +} + +echo_stamp "Install apt keys & repos" + +# TODO: This STDOUT consist 'OK' +curl http://repo.coex.space/aptly_repo_signing.key 2> /dev/null | apt-key add - +apt-get update \ +&& apt-get install --no-install-recommends -y -qq dirmngr=2.1.18-8~deb9u2 > /dev/null \ +&& apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116 + +echo "deb http://packages.ros.org/ros/ubuntu stretch main" > /etc/apt/sources.list.d/ros-latest.list +echo "deb http://repo.coex.space/rpi-ros-kinetic stretch main" > /etc/apt/sources.list.d/rpi-ros-kinetic.list +echo "deb http://repo.coex.space/clever stretch main" > /etc/apt/sources.list.d/clever.list + +echo_stamp "Update apt cache" + +# TODO: FIX ERROR: /usr/bin/apt-key: 596: /usr/bin/apt-key: cannot create /dev/null: Permission denied +apt-get update -qq +# && apt upgrade -y + +echo_stamp "Software installing" +apt-get install --no-install-recommends -y \ +unzip=6.0-21 \ +zip=3.0-11 \ +ipython=5.1.0-3 \ +ipython3=5.1.0-3 \ +screen=4.5.0-6 \ +byobu=5.112-1 \ +nmap=7.40-1 \ +lsof=4.89+dfsg-0.1 \ +git \ +dnsmasq=2.76-5+rpt1+deb9u1 \ +tmux=2.3-4 \ +vim=2:8.0.0197-4+deb9u1 \ +cmake=3.7.2-1 \ +python-pip=9.0.1-2+rpt2 \ +python3-pip=9.0.1-2+rpt2 \ +libjpeg8-dev=8d1-2 \ +tcpdump \ +ltrace \ +libpoco-dev=1.7.6+dfsg1-5+deb9u1 \ +python-rosdep=0.12.2-1 \ +python-rosinstall-generator=0.1.14-1 \ +python-wstool=0.1.17-1 \ +python-rosinstall=0.7.8-1 \ +build-essential=12.3 \ +libffi-dev \ +monkey=1.6.9-1 \ +&& echo_stamp "Everything was installed!" "SUCCESS" \ +|| (echo_stamp "Some packages wasn't installed!" "ERROR"; exit 1) + +# Deny byobu to check available updates +sed -i "s/updates_available//" /usr/share/byobu/status/status +# sed -i "s/updates_available//" /home/pi/.byobu/status + +#echo_stamp "Upgrade pip" +#my_travis_retry pip install --upgrade pip +#my_travis_retry pip3 install --upgrade pip + +echo_stamp "Not upgrading system pip due to https://github.com/pypa/pip/issues/5599" + +echo_stamp "Make sure both pip and pip3 are installed" +pip --version +pip3 --version + +echo_stamp "Install and enable Butterfly (web terminal)" +my_travis_retry pip3 install butterfly +my_travis_retry pip3 install butterfly[systemd] +systemctl enable butterfly.socket + +echo_stamp "Setup Monkey" +mv /etc/monkey/sites/default /etc/monkey/sites/default.orig +mv /root/monkey-clever /etc/monkey/sites/default +systemctl enable monkey.service + +echo_stamp "Add .vimrc" +cat << EOF > /home/pi/.vimrc +set mouse-=a +syntax on +autocmd BufNewFile,BufRead *.launch set syntax=xml +EOF + +echo_stamp "End of software installation" 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..8610bcb4 100644 --- a/clever/launch/clever.launch +++ b/clever/launch/clever.launch @@ -2,34 +2,35 @@ - - + - - - + + - + - - - + + + + + + @@ -37,11 +38,14 @@ - - + + + + + @@ -49,14 +53,15 @@ + + + + + + - - - - - 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 old mode 100644 new mode 100755 index 480ba38f..8c0aba46 --- a/clever/launch/main_camera.launch +++ b/clever/launch/main_camera.launch @@ -1,11 +1,19 @@ - - + + - - + - + + + + + + + + + + @@ -16,8 +24,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..b53cec3e 100644 --- a/clever/launch/sitl.launch +++ b/clever/launch/sitl.launch @@ -1,17 +1,19 @@ - + + + - - + + 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/package.xml b/clever/package.xml index 5759150f..4a018903 100644 --- a/clever/package.xml +++ b/clever/package.xml @@ -2,55 +2,40 @@ clever 0.0.1 - The clever package + The CLEVER package - - - Oleg Kalachev + MIT + + Oleg Kalachev + Artem Smirnov - - - - TODO - - - - - - - - - - - - - - - - - - - - - - - - - catkin - nodelet roscpp - - nodelet + visualization_msgs + tf2_geometry_msgs + + catkin + + catkin roscpp + nodelet + mavros + mavros_extras + lxml + cv_camera + mjpg-streamer + rosbridge_server + web_video_server + ros_commr + + - + - 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/fpv_camera b/clever/src/fpv_camera index 7ca4981d..052d22d8 100755 --- a/clever/src/fpv_camera +++ b/clever/src/fpv_camera @@ -4,5 +4,4 @@ # fpv_camera echo "Starting FPV camera $1 on :$2" -cd /home/pi/mjpg-streamer/mjpg-streamer-experimental -./mjpg_streamer -i "./input_uvc.so -d $1 -r 320x240 -f 30" -o "./output_http.so -w ./www -p $2" +mjpg_streamer -i "/usr/lib/input_uvc.so -d $1 -r 320x240 -f 30" -o "/usr/lib/output_http.so -w /usr/share/mjpg_streamer/www -p $2" 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/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..314cc095 100755 --- a/clever/src/selfcheck.py +++ b/clever/src/selfcheck.py @@ -1,93 +1,228 @@ #!/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 sensor_msgs.msg import Image, CameraInfo, NavSatFix, Imu, Range +from mavros_msgs.msg import State, OpticalFlowRad +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('Visual position estimate') +def check_vpe(): + try: + rospy.wait_for_message('mavros/vision_pose/pose', PoseStamped, timeout=1) + except rospy.ROSException: + try: + rospy.wait_for_message('mavros/mocap/pose', PoseStamped, timeout=1) + except rospy.ROSException: + failure('No VPE or MoCap 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=1) + except rospy.ROSException: + failure('No global position') -def check(name, fn): +@check('Optical flow') +def check_optical_flow(): + # TODO:check FPS! try: - fn() - rospy.loginfo('%s: OK', name) - except Exception as e: - rospy.logwarn('%s: %s', name, str(e)) + rospy.wait_for_message('mavros/px4flow/raw/send', OpticalFlowRad, timeout=0.5) + except rospy.ROSException: + failure('No optical flow data (from Raspberry)') + + +@check('Rangefinder') +def check_rangefinder(): + # TODO: check FPS! + try: + rospy.wait_for_message('mavros/distance_sensor/rangefinder_3_sub', Range, timeout=0.5) + except rospy.ROSException: + failure('No randefinder data from Raspberry') + try: + rospy.wait_for_message('mavros/distance_sensor/rangefinder_0', Range, timeout=0.5) + except rospy.ROSException: + failure('No rangefinder data from PX4') + + +@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_optical_flow() + check_vpe() + check_rangefinder() + 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..887bca41 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) @@ -128,7 +131,10 @@ BRAKE_TIME = rospy.Duration(0) def get_navigate_setpoint(stamp, start, finish, start_stamp, speed): distance = math.sqrt((finish.z - start.z)**2 + (finish.x - start.x)**2 + (finish.y - start.y)**2) time = rospy.Duration(distance / speed) - k = (stamp - start_stamp) / time + if time == rospy.Duration(0): + k = 0 + else: + k = (stamp - start_stamp) / time time_left = start_stamp + time - stamp if BRAKE_TIME and time_left < BRAKE_TIME: @@ -158,14 +164,17 @@ def get_publisher_and_message(req, stamp, continued=True, update_frame=True): ps.header.stamp = stamp vs.header.stamp = stamp + # don't block on setpoints publishing + transform_timeout = rospy.Duration(0.1) if continued else TRANSFORM_TIMEOUT + if isinstance(req, (srv.NavigateRequest, srv.NavigateGlobalRequest)): global current_nav_start, current_nav_start_stamp, current_nav_finish if update_frame: ps.header.frame_id = req.frame_id or LOCAL_FRAME ps.pose.position = Point(getattr(req, 'x', 0), getattr(req, 'y', 0), req.z) - ps.pose.orientation = orientation_from_euler(0, 0, req.yaw) - current_nav_finish = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT) + 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): # Recalculate x and y from lat and lon @@ -183,32 +192,34 @@ 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)): ps.header.frame_id = req.frame_id or LOCAL_FRAME ps.pose.position = Point(getattr(req, 'x', 0), getattr(req, 'y', 0), req.z) ps.pose.orientation = orientation_from_euler(0, 0, req.yaw) - pose_local = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT) + pose_local = tf_buffer.transform(ps, LOCAL_FRAME, transform_timeout) if isinstance(req, srv.SetPositionGlobalRequest): pose_local.pose.position.x, pose_local.pose.position.y = global_to_local(req.lat, req.lon) yaw_rate_flag = math.isnan(req.yaw) - msg = PositionTarget(coordinate_frame=PT.FRAME_LOCAL_NED, - type_mask=PT.IGNORE_VX + PT.IGNORE_VY + PT.IGNORE_VZ + - PT.IGNORE_AFX + PT.IGNORE_AFY + PT.IGNORE_AFZ + - (PT.IGNORE_YAW if yaw_rate_flag else PT.IGNORE_YAW_RATE), - position=pose_local.pose.position, - yaw=euler_from_orientation(pose_local.pose.orientation, '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): @@ -216,32 +227,37 @@ def get_publisher_and_message(req, stamp, continued=True, update_frame=True): vs.header.frame_id = req.frame_id or LOCAL_FRAME ps.header.frame_id = req.frame_id or LOCAL_FRAME ps.pose.orientation = orientation_from_euler(0, 0, req.yaw) - pose_local = tf_buffer.transform(ps, LOCAL_FRAME, TRANSFORM_TIMEOUT) - vector_local = tf_buffer.transform(vs, LOCAL_FRAME, TRANSFORM_TIMEOUT) + pose_local = tf_buffer.transform(ps, LOCAL_FRAME, transform_timeout) + 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) + pose_local = tf_buffer.transform(ps, LOCAL_FRAME, transform_timeout) + 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 +277,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): @@ -279,14 +298,19 @@ def handle(req): return {'message': 'Both yaw and yaw_rate cannot be NaN'} 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) + # check frame_id existance + # (for non-blocking setpoint's publishing in get_publisher_and_message) + stamp = rospy.get_rostime() + if hasattr(req, 'frame_id'): + tf_buffer.lookup_transform(req.frame_id or LOCAL_FRAME, LOCAL_FRAME, stamp, TRANSFORM_TIMEOUT) - current_msg.header.stamp = stamp - current_pub.publish(current_msg) + with handle_lock: + 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) if req.auto_arm: offboard_and_arm() @@ -364,24 +388,31 @@ def get_telemetry(req): frame_id = req.frame_id or LOCAL_FRAME stamp = rospy.get_rostime() - if pose: - p = tf_buffer.transform(pose, frame_id, TRANSFORM_TIMEOUT) - res['x'] = p.pose.position.x - res['y'] = p.pose.position.y - res['z'] = p.pose.position.z + transform_timeout = rospy.Duration(0.4) + try: + if pose: + p = tf_buffer.transform(pose, frame_id, transform_timeout) + res['x'] = p.pose.position.x + res['y'] = p.pose.position.y + res['z'] = p.pose.position.z - # Calculate roll pitch and yaw as Tait-Bryan angles, order z-y-x - res['yaw'], res['pitch'], res['roll'] = euler_from_orientation(p.pose.orientation, axes='rzyx') + # Calculate roll pitch and yaw as Tait-Bryan angles, order z-y-x + res['yaw'], res['pitch'], res['roll'] = euler_from_orientation(p.pose.orientation, axes='rzyx') + except: + pass if velocity: - v = Vector3Stamped() - v.header.stamp = velocity.header.stamp - v.header.frame_id = velocity.header.frame_id - v.vector = velocity.twist.linear - linear = tf_buffer.transform(v, frame_id, TRANSFORM_TIMEOUT) - res['vx'] = linear.vector.x - res['vy'] = linear.vector.y - res['vz'] = linear.vector.z + try: + v = Vector3Stamped() + v.header.stamp = velocity.header.stamp + v.header.frame_id = velocity.header.frame_id + v.vector = velocity.twist.linear + linear = tf_buffer.transform(v, frame_id, transform_timeout) + res['vx'] = linear.vector.x + res['vy'] = linear.vector.y + res['vz'] = linear.vector.z + except: + pass res['yaw_rate'] = velocity.twist.angular.z res['pitch_rate'] = velocity.twist.angular.y @@ -428,21 +459,21 @@ def start_loop(): current_pub, current_msg = get_publisher_and_message(current_req, stamp, True, getattr(current_req, 'update_frame', False)) - current_msg.header.stamp = stamp - current_pub.publish(current_msg) - - # For monitoring - if isinstance(current_msg, PositionTarget): - p = PoseStamped() - p.header.frame_id = LOCAL_FRAME - p.header.stamp = stamp - p.pose.position = current_msg.position - p.pose.orientation = orientation_from_euler(0, 0, current_msg.yaw + math.pi / 2) - target_pub.publish(p) - except Exception as e: rospy.logwarn_throttle(10, str(e)) + current_msg.header.stamp = stamp + current_pub.publish(current_msg) + + # For monitoring + if isinstance(current_msg, PositionTarget): + p = PoseStamped() + p.header.frame_id = LOCAL_FRAME + p.header.stamp = stamp + p.pose.position = current_msg.position + p.pose.orientation = orientation_from_euler(0, 0, current_msg.yaw) + target_pub.publish(p) + r.sleep() diff --git a/clever/src/vl53l1x.py b/clever/src/vl53l1x.py new file mode 100755 index 00000000..346c382b --- /dev/null +++ b/clever/src/vl53l1x.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# TODO: rewrite, as Python version eats 20% CPU + +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) +z_shift = rospy.get_param("z_shift", 0) # TODO: move to mavros (use frame) + +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 + z_shift + 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/deploy/clever_arudino.tar.gz b/deploy/clever_arudino.tar.gz deleted file mode 100644 index df92e77a..00000000 Binary files a/deploy/clever_arudino.tar.gz and /dev/null differ diff --git a/deploy/generate_ros_lib b/deploy/generate_ros_lib deleted file mode 100644 index b72c5602..00000000 --- a/deploy/generate_ros_lib +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -# This script generates ros_lib library for Arduino for using with rosseial_arduino: -# http://wiki.ros.org/rosserial_arduino/Tutorials -# https://copterexpress.gitbooks.io/clever/content/docs/arduino.html - -rm -rf ros_lib -rosrun rosserial_arduino make_libraries.py . -tar czf clever_arudino.tar.gz ros_lib 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 67eecade..b47fb264 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -4,16 +4,19 @@ * [Глоссарий](glossary.md) * [Сборка Клевер 2](assemble.md) * [Сборка Клевер 3](assemble_clever3_4in1.md) +* [Установка FPV](fpv.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) +* [Параметры PX4](px4_parameters.md) * [Пилотирование со смартфона](rc.md) * [SSH-доступ](ssh.md) +* [Устройство UART](uart.md) * [Неисправности радиоаппаратуры](radioerrors.md) * [Безопасность](safety.md) * [Техника безопасности по пайке](tb.md) @@ -43,8 +46,11 @@ * [Учебно-методическое пособие](metod.md) * [Контрольные и проверочные материалы](tests.md) * [Другое](drugoe.md) + * [CopterHack-2018](copterhack2018.md) * [CopterHack-2017](copterhack2017.md) * [Прошивка 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/arduino.md b/docs/arduino.md index 0b99aae7..bd73755f 100644 --- a/docs/arduino.md +++ b/docs/arduino.md @@ -1,5 +1,4 @@ -Управление коптером с Arduino -=== +# Управление коптером с Arduino Для взаимодействия с ROS-топиками и сервисами на Raspberry Pi можно использовать библиотеку [rosserial_arduino](http://wiki.ros.org/rosserial_arduino). @@ -7,17 +6,23 @@ Arudino необходимо установить на Клевер и подключить по USB-порту. -Настройка Arduino IDE ---- +## Настройка Arduino IDE -Необходимо скачать и скопировать [библиотеку ROS-сообщений Клевера](https://github.com/CopterExpress/clever_bundle/blob/master/deploy/clever_arudino.tar.gz?raw=true) (`ros_lib`) в `<папку скетчей>/libraries`. +Для работы с ROS, Arduino необходимо понимать формат сообщений. Для этого на Clever необходимо собрать библиотеку ROS-сообщений (`ros_lib`) и скопировать в папку `<папку скетчей>/libraries`. -Настройка Raspberry Pi ---- +Для сборки библиотеки на коптере необходимо выполнить следующий скрипт: + +```bash +rosrun rosserial_arduino make_libraries.py . +tar czf clever_arudino.tar.gz ros_lib +rm -rf ros_lib +``` + +## Настройка Raspberry Pi Чтобы единоразово запустить программу на Arduino, можно воспользоваться командой: -``` +```bash roslaunch clever arduino.launch ``` @@ -33,8 +38,7 @@ roslaunch clever arduino.launch sudo systemctl restart clever ``` -Задержки ---- +## Задержки При использовании `rosserial_arduino` микроконтроллер Arduino не должен быть заблокирован больше чем на несколько секунд (например, с использованием функции `delay`); иначе связь между Raspberry Pi и Arduino будет разорвана. @@ -52,13 +56,12 @@ while(/* условие */) { ```cpp // Задержка на 8 секунд for(int i=0; i<8; i++) { - delay(1000); - nh.spinOnce(); + delay(1000); + nh.spinOnce(); } ``` -Работа с Клевером ---- +## Работа с Клевером Набор сервисов и топиков аналогичен обычному набору в [simple_offboard](simple_offboard.md) и [mavros](mavros.md). @@ -165,8 +168,7 @@ void loop() } ``` -Получение телеметрии ---- +## Получение телеметрии С Arduino можно использовать [сервис](simple_offboard.md) `get_telemetry`. Для этого надо объявить его по аналогии с сервисами `navigate` и `set_mode`: @@ -201,8 +203,7 @@ getTelemetry.call(gt_req, gt_res); // gt_res.z - положение коптера по z ``` -Проблемы ---- +## Проблемы При использовании Arudino Nano может не хватать оперативной памяти (RAM). В таком случае в Aruino IDE будут появляться сообщения, типа: diff --git a/docs/aruco.md b/docs/aruco.md index cfc28ea8..5548c31c 100644 --- a/docs/aruco.md +++ b/docs/aruco.md @@ -39,7 +39,7 @@ sudo systemctl restart clever В качестве карты меток можно использовать автоматически сгенерированный [ArUco-board](https://docs.opencv.org/trunk/db/da9/tutorial_aruco_board_detection.html). -Настройка карты меток производится с помощью файла `~/catkin_ws/src/clever/clever/aruco.launch`. Для использования AruCo-board введите его параметры: +Настройка карты меток производится с помощью файла `~/catkin_ws/src/clever/clever/launch/aruco.launch`. Для использования AruCo-board введите его параметры: ```xml @@ -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 d6a0c58d..1eef8b72 100644 --- a/docs/assemble.md +++ b/docs/assemble.md @@ -3,8 +3,7 @@ ![Clever](assets/Clevermain.png) -Состав конструктора -------------------- +## Состав конструктора ![Explosion](assets/explosion.png) @@ -27,7 +26,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 +36,8 @@ * Батарейка АА х4 * Джампер, Bind-разъем -#### Крепежные элементы +### Крепежные элементы + * Пластиковые стойки 6 мм x28. * Пластиковые стойки 30 мм x32. * Винты М3x8 x48. @@ -54,10 +54,8 @@ * Ножницы канцелярские х1 * Ремешок для батареи 250 мм х1 +## Функционал радиопульта Flysky i6 - -Функционал радиопульта Flysky i6 ---------------------------- 1. Переключатель A (SwA). 2. Переключатель B (SwB). 3. Переключатель С (SwC). @@ -78,10 +76,9 @@ ![radio Transmitter](assets/radioTransmitter.png) +## Дополнительное оборудование -Дополнительное оборудование ---------------------------- -#### Данное оборудование не входит в состав конструктора Клевер 2, но оно необходимо для реализации сборочного процесса +### Данное оборудование не входит в состав конструктора Клевер 2, но оно необходимо для реализации сборочного процесса 1. Паяльник 2. Канифоль/ Флюс (нейтральный) @@ -94,11 +91,9 @@ ![Дополнительное оборудование](assets/addEqipment.jpg) - [Техника безопасности при пайке](tb.md) -Порядок сборки --------------- +## Порядок сборки ### Установка моторов @@ -107,11 +102,13 @@ ![Мотор brrc2205](assets/brrc2205.png) Зачистить + * снять 2мм термоизоляции с конца провода не повредив медные жилы. Скрутить провода. Залудить + * Нанести флюс на оголенную часть провода. * Покрыть припоем, используя пинцет. @@ -128,17 +125,19 @@ ![Вращение моторов](assets/brrc2205ondeck.png) +### Залудить три контактные площадки регулятора -#### Залудить три контактные площадки регулятора * Нанести флюс * Нанести припой Чтобы припой аккуратно заполнил всю площадку, необходимо прогреть площадку регулятора. Для этого нужно удерживать жало паяльника на контактной плащадке в течение 2 сек (или больше, если потребуется) ![Лужение контактных площадок регуляторов](assets/escDYSzap.png) + * Повторить данную операцию для оставшихся трех регуляторов -#### Припаять провода моторов к регуляторам +### Припаять провода моторов к регуляторам + Припаять ранее приготовленные провода моторов к контактным площадкам регуляторов. ![Припаять провода моторов к регуляторам](assets/solderingBrrc2205ondeckTOescDYSzap.png) @@ -146,6 +145,7 @@ * Повторить данную операцию для оставшихся трех регуляторов ### Монтаж разъемов питания + [Статья про силовые и управляющие цепи](powerConnection.md) #### Подготовка проводов для силовых разъемов XT60 @@ -169,10 +169,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 +190,18 @@ ![Предпаячная проверка](assets/startPDBtest.jpg) Прозвонить следующие цепи на НЕЗАМКНУТОСТЬ (отсутствие звукового сигнала мультиметра): + * “BAT+” и “BAT-” * “12V” и “GND” * “5V” и “GND” Прозвонить следующие цепи на ЗАМКНУТОСТЬ (появление звукового сигнала мультиметра): + * “BAT-” c каждым контактом, обозначенным “-” и “GND” * “BAT+”, с каждым контактом, обозначенным “+” #### Залудить контактные площадки платы питания + 1. [Залудить*](zap.md) контактные площадки платы питания. 2. С помощью мультиметра проверить отсутствие контактного замыкания на плате (прозвонить) @@ -210,15 +210,18 @@ Чтобы припой аккуратно заполнил всю площадку, необходимо её прогреть. Для этого нужно удерживать жало паяльника на контактной плащадке в течение 2 сек (или больше, если потребуется) #### Пайка силового разъема питания XT60 + Припаять разъем для АКБ, соблюдая полярность на контактных площадках. ![Пайка XT60 на PDB](assets/solderingxt60socketTOpdb.png) ВАЖНО о полярности + * красный провод - это “+” * черный провод - это “-” #### Пайка разъема питания управляющей цепи 5В + Припаять разъем 5В, соблюдая полярность на контактных площадках. (на изображении: красный провод - это питание “+”) @@ -227,6 +230,7 @@ ### Монтаж отсека АКБ #### Подготовка перемычек (3 шт.) + ![Перемычка](assets/jumper.png) * Отрезать силовой провод длиной 2 см. @@ -237,60 +241,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 +295,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 +340,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 +373,11 @@ Коптер готов к настройке! - ## Безопасность при сборке и настройке 1. Снять пропеллеры.“Все наземные операции производить со снятыми пропеллерами. Устанавливать пропеллеры на моторы только перед полётом.” - -2. Отключить аккумулятор. Держать питание выключенным. -“Сборку, настройку и ремонт производить с отключенным питанием. Подключать питание только для тестирования электронных компонентов коптера. После тестирования перед другими работами питание сразу отключить.” - -3. Позвать на помощь -“Если при выполнении работ возникли какие-либо проблемы, необходимо обратиться к преподавателю или учителю, а не пытаться решить проблему самостоятельно.” +2. Отключить аккумулятор. Держать питание выключенным. “Сборку, настройку и ремонт производить с отключенным питанием. Подключать питание только для тестирования электронных компонентов коптера. После тестирования перед другими работами питание сразу отключить.” +3. Позвать на помощь. “Если при выполнении работ возникли какие-либо проблемы, необходимо обратиться к преподавателю или учителю, а не пытаться решить проблему самостоятельно.” ![Безопасность при сборке](assets/safetybyassem.png) @@ -436,4 +387,4 @@ 2. При подключении (отключении) аккумуляторов держаться только за разъёмы, тянуть или дергать за провода запрещается. 3. В случае обрыва разъемов, обнаружения нарушений целостности изоляции или корпуса аккумулятора, не трогая его, немедленно сообщить преподавателю. -## [ТЕХНИКА БЕЗОПАСНОСТИ ПРИ ПАЙКЕ И ЛЁТНОЙ ЭКСПЛУАТАЦИИ КОПТЕРОВ](safety.md) +[ТЕХНИКА БЕЗОПАСНОСТИ ПРИ ПАЙКЕ И ЛЁТНОЙ ЭКСПЛУАТАЦИИ КОПТЕРОВ](safety.md) diff --git a/docs/assemble_clever3_4in1.md b/docs/assemble_clever3_4in1.md index ec407847..baa0e3f6 100644 --- a/docs/assemble_clever3_4in1.md +++ b/docs/assemble_clever3_4in1.md @@ -6,6 +6,8 @@ Состав конструктора ------------------- +TODO + Дополнительное оборудование ------------------- ![Дополнительное оборудование](assets/additonal_eqipment.jpg) @@ -121,7 +123,6 @@ ![Проверка направления вращения моторов](assets/cl3_testMotorsFlysky.JPG) - Монтаж и подключение полетного контроллера Pixracer ---------------------------- 1. Установить Полетный контроллер Pixracer на двухстороний скотч 3М (2-3 слоя) @@ -186,4 +187,4 @@ USB-разъемы направлены к хвостовой части коп -------------------- 1. Соедините Pixracer и Raspberry, используя micro USB - USB кабель 2. Соедините Arduino и Raspberry, используя micro USB - USB кабель -![Монтаж USB соединителей](assets/cl3_mountUSBconnectors.JPG) +![Монтаж USB соединителей](assets/cl3_mountUSBconnectors.JPG) \ No newline at end of file diff --git a/docs/assets/alcopter.jpg b/docs/assets/alcopter.jpg new file mode 100644 index 00000000..47737992 Binary files /dev/null and b/docs/assets/alcopter.jpg differ diff --git a/docs/assets/camera_option_1.png b/docs/assets/camera_option_1.png new file mode 100755 index 00000000..5e6f2b85 Binary files /dev/null and b/docs/assets/camera_option_1.png differ diff --git a/docs/assets/camera_option_2.png b/docs/assets/camera_option_2.png new file mode 100755 index 00000000..2bc923d5 Binary files /dev/null and b/docs/assets/camera_option_2.png differ diff --git a/docs/assets/camera_option_3.png b/docs/assets/camera_option_3.png new file mode 100755 index 00000000..dcd2209b Binary files /dev/null and b/docs/assets/camera_option_3.png differ diff --git a/docs/assets/camera_option_4.png b/docs/assets/camera_option_4.png new file mode 100755 index 00000000..a88f40c9 Binary files /dev/null and b/docs/assets/camera_option_4.png 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_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_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/copter_visualization.png b/docs/assets/copter_visualization.png new file mode 100755 index 00000000..4bd00bd0 Binary files /dev/null and b/docs/assets/copter_visualization.png differ diff --git a/docs/assets/copterhack18.jpg b/docs/assets/copterhack18.jpg new file mode 100644 index 00000000..61d863c1 Binary files /dev/null and b/docs/assets/copterhack18.jpg differ diff --git a/docs/assets/etcher.gif b/docs/assets/etcher.gif new file mode 100644 index 00000000..e06ce0cb Binary files /dev/null and b/docs/assets/etcher.gif differ diff --git a/docs/assets/fpv_1.png b/docs/assets/fpv_1.png new file mode 100644 index 00000000..9ff8096e Binary files /dev/null and b/docs/assets/fpv_1.png differ diff --git a/docs/assets/fpv_2.png b/docs/assets/fpv_2.png new file mode 100644 index 00000000..a00c0516 Binary files /dev/null and b/docs/assets/fpv_2.png differ diff --git a/docs/assets/fpv_3.png b/docs/assets/fpv_3.png new file mode 100644 index 00000000..ef6557f4 Binary files /dev/null and b/docs/assets/fpv_3.png differ diff --git a/docs/assets/fpv_4.png b/docs/assets/fpv_4.png new file mode 100644 index 00000000..ca8dce61 Binary files /dev/null and b/docs/assets/fpv_4.png differ diff --git a/docs/assets/fpv_5.png b/docs/assets/fpv_5.png new file mode 100644 index 00000000..1ac6f7d7 Binary files /dev/null and b/docs/assets/fpv_5.png 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/assets/rqt.png b/docs/assets/rqt.png new file mode 100644 index 00000000..1ebdf93c Binary files /dev/null and b/docs/assets/rqt.png differ diff --git a/docs/assets/Снимок экрана 2017-11-28 в 23.50.36.png b/docs/assets/rviz.png similarity index 100% rename from docs/assets/Снимок экрана 2017-11-28 в 23.50.36.png rename to docs/assets/rviz.png 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/camera_frame.md b/docs/camera_frame.md index f1e4cdf5..20796854 100644 --- a/docs/camera_frame.md +++ b/docs/camera_frame.md @@ -22,20 +22,34 @@ ## Настройки для Клевера -### Клевер 3, камера вниз +### 1. Камера направлена вниз, шлейф назад + +```xml + +``` + +![](assets/camera_option_1.png) + +### 2. Камера направлена вниз, шлейф вперёд ```xml ``` -### Клевер 3, камера вверх +![](assets/camera_option_2.png) + +### 3. Камера направлена вверх, шлейф назад + +```xml + +``` + +![](assets/camera_option_3.png) + +### 4. Камера направлена вверх, шлейф вперёд ```xml ``` -### Клевер 2, камера вниз - -```xml - -``` +![](assets/camera_option_4.png) 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/copterhack2018.md b/docs/copterhack2018.md new file mode 100644 index 00000000..f78af988 --- /dev/null +++ b/docs/copterhack2018.md @@ -0,0 +1,31 @@ +# Copter Hack 2018 + + + +Чат хакатона: https://t.me/CopterHack. + +Стрим хакатона: https://www.youtube.com/watch?v=nIo5HSqlt6I. + +Фотографии с хакатона: https://drive.google.com/open?id=1ozdXol4rhKwhHbsrnfxrp3CqazBRm-3W. + +## Лекции + +Лекция 1: сборка – https://www.youtube.com/watch?v=gEs-w7BRPM8. + +Лекция 2: настройка – https://www.youtube.com/watch?v=sPqSCCmgdG0. + +Лекция 3: прошивка PX4 – https://www.youtube.com/watch?v=WFnZAIypgMQ. + +Лекция 4: автономные полеты – https://www.youtube.com/watch?v=gD6a7aSEf9M. + +## Результаты + +Команды-победители: + +1. Starshine (Москва) — управление дроном с помощью "умной" перчатки. +2. Alcopter (Москва) — управление дроном с помощью жестов и смены поз. +3. Весёлый коптер (Самара) — бот Vkontakte для управления коптером, совместный полет "Жужи" и "Клевера 3". +4. International Post (Новосибирск) — автоматический разброс листовок с дрона. +5. ЛАМАР (Екатеринбург) — станция автоматической смены аккумулятора квадрокоптера. + + 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/fpv.md b/docs/fpv.md new file mode 100644 index 00000000..a77c81a6 --- /dev/null +++ b/docs/fpv.md @@ -0,0 +1,49 @@ +# Установка FPV + +## Подготовка курсовой камеры + +1. Взять провод-коннектор от камеры и откусить ЧЁРНУЮ сторону 3-х пинового разъема. +1. Подготовить провода провода к подключению: + 1. Укоротить провода до нужной длины *. + 1. Зачистить (снять 2мм термоизоляции с конца провода, не повредив жилы). + 1. Скрутить провода. + 1. Залудить, используя пинцет. + +\* Длину нужно определить заранее, между платой распределения питания и предположительным место установки камеры! + +![FPV1](assets/fpv_1.png) + +## Подготовка передатчика + +Аналогичную процедуру проводим и здесь: + +1. Взять провод-коннектор от передатчика и откусить ЧЁРНУЮ сторону 5-ти пинового разъема. +2. Подготовить провода провода к подключению: + 1. Укоротить провода до нужной длины *. + 2. Зачистить (снять 2мм термоизоляции с конца провода, не повредив жилы). + 3. Скрутить провода. + 4. Залудить, используя пинцет. + +* Длину нужно определить заранее, между платой распределения питания и предположительным место установки передатчика! + +![FPV2](assets/fpv_2.png) + +## Подключение FPV + +Готовые коннекторы вставить в соответствующие разъёмы и запаять провода питания на плату распределения питания согласно схеме: + +![FPV3](assets/fpv_3.png) + +> **Warning** В данной схеме питание камеры идёт на 12V (Однако возможно использовать 5V). +> Питание передатчика идёт на питание регулятора (однако возможно использовать 12V). + +## Установка компонентов FPV + +![FPV4](assets/fpv_4.png) + +В качестве крепежных материалов можно использовать: + +1. Термоклей; +1. изоленту; +1. стяжки (хомуты); +1. двусторонний скотч. 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/leds.md b/docs/leds.md index c1a999a8..74a3026e 100644 --- a/docs/leds.md +++ b/docs/leds.md @@ -101,10 +101,14 @@ sudo python strandtest.py При запуске программы с помощью sudo пользовательское окружение изменяется и появляются ошибки импорта библиотек, т.к. в окружении отсутствуют необходимые пути. Чтобы добавить в окружение пути к библиотекам python и пакетам ROS, необходимо добавить в файл /etc/sudoers следующие строки: ```(bash) -Defaults env_keep += "PYTHONPATH" -Defaults env_keep += "PATH" -Defaults env_keep += "ROS_ROOT" -Defaults env_keep += "ROS_MASTER_URI" +Defaults env_keep += "PYTHONPATH" +Defaults env_keep += "PATH" +Defaults env_keep += "ROS_ROOT" +Defaults env_keep += "ROS_MASTER_URI" +Defaults env_keep += "ROS_PACKAGE_PATH" +Defaults env_keep += "ROS_LOCATIONS" +Defaults env_keep += "ROS_HOME" +Defaults env_keep += "ROS_LOG_DIR" ``` ## Функции для работы со светодиодной лентой 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 5ba18e4e..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). @@ -36,3 +36,144 @@ MAVLink-сообщение это отдельная "порция" данных Каждое устройство (дрон, базовая станция и т. д.) имеет ID в сети MAVLink. В PX4 MAVLink ID менятся с помощью параметра `MAV_SYS_ID`. Каждое MAVLink сообщение содержит поле с ID системы-отправителя. Кроме того, некоторые сообщения (например, `COMMAND_LONG`) содержат также ID системы-получателя. Помимо ID систем, сообщения могут содержать ID компонента-отправителя и компонента-получателя. Примеры компонентов системы: полетный контроллер, внешняя камера, управляющий бортовой компьютер (Raspberry Pi в случае Клевера) и т. д. + +### Пример пакета + +Пример структуры MAVLink-пакета с сообщением `COMMAND_LONG`: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ПолеДлинаИмяКомментарий
Заголовок
magic1 байтМетка начала0xFD для MAVLink 2.0
len1 байтРазмер данных
incompat_flags1 байтОбратно несовместимые флагиНа данный момент не используется
compat_flags1 байтОбратно совместимые флагиНа данный момент не используется
seq1 байтПорядковый номер сообщения
sysid1 байтID системы-отправителя
compid1 байтID компонента-отправителя
msgid3 байтаID сообщения
Данные (пример)
target_system1 байтID системы-получателя
target_component1 байтID компонента–получателя
command2 байтаID команды
confirmation1 байтНомер для подтверждения
param14 байтаПараметр 1Число с плавающей точкой одинарной точности
param24 байтаПараметр 2
param34 байтаПараметр 3
param44 байтаПараметр 4
param54 байтаПараметр 5
param64 байтаПараметр 6
param74 байтаПараметр 7
checksum2 байтаКонтрольная сумма
signature13 байтСигнатура (опционально)Позволяет убедиться, что пакет не был скомпроментирован. +Обычно не используется.
+ +Желтым цветом выделены поля данных (полезной нагрузки). Для каждого типа сообщения существует свой набор таких полей. 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/microsd_images.md b/docs/microsd_images.md index 286bbad3..65233df5 100644 --- a/docs/microsd_images.md +++ b/docs/microsd_images.md @@ -12,7 +12,7 @@ Для установки образа воспользуйтесь утилитой [Etcher](https://etcher.io). -[![Etcher](https://etcher.io/static/screenshot.gif)](https://etcher.io) +[![Etcher](assets/etcher.gif)](https://etcher.io) ## Версия образа diff --git a/docs/modes.md b/docs/modes.md index ddef9c47..0b968d5b 100644 --- a/docs/modes.md +++ b/docs/modes.md @@ -41,8 +41,8 @@ PX4 Основные используемые пакеты MAVLink: -* MAV_CMD_COMPONENT_ARM_DISARM -* [SET_POSITION_TARGET_LOCAL_NED](https://pixhawk.ethz.ch/mavlink/#SET_POSITION_TARGET_LOCAL_NED) -* [SET_ATTITUDE_TARGET](https://pixhawk.ethz.ch/mavlink/#SET_ATTITUDE_TARGET) +* [MAV_CMD_COMPONENT_ARM_DISARM](https://mavlink.io/en/messages/common.html#MAV_CMD_COMPONENT_ARM_DISARM) +* [SET_POSITION_TARGET_LOCAL_NED](https://mavlink.io/en/messages/common.html#SET_POSITION_TARGET_LOCAL_NED) +* [SET_ATTITUDE_TARGET](https://mavlink.io/en/messages/common.html#SET_ATTITUDE_TARGET) См.: [автономные полеты коптера в режиме OFFBOARD](simple_offboard.md). diff --git a/docs/network.md b/docs/network.md index b5c4d316..4a565dae 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). ## Инструкция для переключения адаптера в режим клиента @@ -272,7 +272,7 @@ EOF ## Ссылки 1. [habr.com: Linux WiFi из командной строки с wpa_supplicant](https://habr.com/post/315960/) -2. [wiki.archlinux.org: WPA supplicant (Русский)](https://wiki.archlinux.org/index.php/WPA_supplicant_(Русский)) +2. [wiki.archlinux.org: WPA supplicant (Русский)](https://wiki.archlinux.org/index.php/WPA_supplicant_\(Русский\)) 3. [blog.hoxnox.com: WiFi access point with wpa_supplicant](http://blog.hoxnox.com/gentoo/wifi-hotspot.html) 4. [dmitrysnotes.ru: Raspberry Pi 3. Присвоение статического IP-адреса](http://dmitrysnotes.ru/raspberry-pi-3-prisvoenie-staticheskogo-ip-adresa) 5. [thegeekdiary.com: Linux OS Service ‘network’](https://www.thegeekdiary.com/linux-os-service-network/) diff --git a/docs/optical_flow.md b/docs/optical_flow.md new file mode 100644 index 00000000..01c37318 --- /dev/null +++ b/docs/optical_flow.md @@ -0,0 +1,63 @@ +# Использование Optical Flow + +> **Warning** Данная функция является **экспериментальной** и включена в образ с версии v0.11.4. + +При использовании технологии Optical Flow возможен полет в режиме POSCTL и автономные полеты по камере, направленной вниз, засчет измерения сдвигов текстуры поверхности пола. + +## Включение + +А данный момент для использования Optical Flow необходима [кастомная прошивка PX4](https://yadi.sk/d/KaxaIhohu4V8XA). + +Необходимо использования дальномера. При использовании дальномера STM vl53l1x, необходимо подключить его к Raspberry Pi по I2C и включить его в `~/catkin_ws/src/clever/clever/launch/clever.launch`: + +```xml + +``` + +Проверить работу лазерного дальномера можно с помощью команды: + +```bash +rostopic echo mavros/distance_sensor/rangefinder_3_sub +``` + +Необходимо включить Optical Flow: + +```xml + +``` + +В `main_camera.launch` должен быть выставлен корректный фрейм камеры. + +Рекомендуемые параметры PX4: + +* `SYS_MC_EST_GROUP` – 2 (EKF2). +* `EKF2_AID_MASK` – use optical flow. +* `EKF2_OF_DELAY` – 0. +* `EKF2_OF_QMIN` – 20. +* `EKF2_HGT_MODE` – range sensor (ремменд.). + +## Полет в POSCTL + +Настройте POSCTL как один из полетных режимов PX4. Переведите в режим POSCTL. + +## Автономный полет + +Автономный полет возможен с использованием модуля [simple_offboard](simple_offboard.md). + +## Troubleshooting + +При появлении в QGC ошибок типа `EKF INTERNAL CHECKS` попробуйте перезагрузить ekf2. Для этого наберите в MAVLink-консоли: + +```nsh +ekf2 stop +ekf2 start +``` + +Если коптер будет сильно уплывать по рысканью, попробуйте следующее: + +* Перекалибровать гироскопы +* Перекалибровать магнитометр +* Попробовать разные значения параметра `EKF2_MAG_TYPE`, который определяет, каким образом данные с магнитометра используются в EKF2. +* Изменять значения параметров `EKF2_MAG_NOISE`, `EKF2_GYR_NOISE`, `EKF2_GYR_B_NOISE`. + +Если коптер уплывает по высоте, попробуйте также выставить `MPC_ALT_MODE` = 2 (Terrain following). diff --git a/docs/px4_parameters.md b/docs/px4_parameters.md new file mode 100644 index 00000000..9936ed82 --- /dev/null +++ b/docs/px4_parameters.md @@ -0,0 +1,70 @@ +# Параметры PX4 + +Основная статья: https://dev.px4.io/en/advanced/parameter_reference.html + +> **Note** Это описание некоторых, наиболее важных параметров PX4 по состоянию на версию 1.8.0. Полный список см. по ссылке выше. + +Для изменения параметров PX4 можно воспользоваться программой QGroundControl, [подключившись к Клеверу по Wi-Fi](gcs_bridge.md). + +## Основные параметры + +Наиболее важные параметры вынесены в этот параграф. + +`SYS_MC_EST_GROUP` – выбор модуля estimator'а. + +Это группа модулей, которая вычисляет текущее состояние (state) коптера, используя показания с датчиков. В состояние коптера входит: + +* угловая скорость коптера – pitch_rate, roll_rate, yaw_rate; +* ориентация коптера (в локальной системе координат) – pitch (тангаж), roll (крен), yaw (рысканье) (одно из представлений); +* позиция коптера (в локальной системе координат) – x, y, z; +* скорость коптера (в локальной системе координат) – vx, vy, vz; +* глобальные координаты коптера – lattitude, longitude, altitude; +* высота над поверхностью; +* другие параметры (дрейф гироскопов, скорость ветра и пр.). + +`SYS_AUTOCONFIG` – сброс всех параметров (при установке в значение 1). + +## EKF2 + +`EKF2_AID_MASK` – выбор датчиков, которые используются EKF2 для вычисления состояния коптера. + +`EKF2_HGT_MODE` – основной источник данных о высоте (z в локальной системе координт): + +* 0 – давление с барометра. +* 1 – GPS. +* 2 – дальномер (например, vl53l1x). +* 3 – данные с VPE. + +Вариант 2 является наиболее точным, но его корректно использовать, только если поверхность, над которой летает котер – плоская. В противном случае начало координат по Z будет двигаться вверх и вниз с изменением высоты поверхности. + +## Multicopter Position Control (полет по позиции) + +Данные параметры настраивают полет коптера по позиции (режимы POSCTL, OFFBOARD, AUTO). + +`MPC_THR_HOVER` – газ висения. Данный параметр наобходимо установить на примерный процент газа, необходимый для того, чтобы коптер удерживал высоту. Если коптер имеет тенденцию набирать или терять высоту в режиме удержания высоты – можно уменьшить или увеличить это значение. + +`MPC_XY_P` – коэффициент *P* регулятора по позиции. Этот параметр влияет на то, насколько резко коптер будет выполнять заданные команды по позиции. Слишком большое значение может вызвать перестрелы. + +`MPC_XY_VEL_P` – коэффициент *P* регулятора по скорости. Данный параметр также влияет на точность и резкость выполнения коптером заданной позиции. При слишком большом значении возможны перестрелы. + +`MPC_XY_VEL_MAX` – максимальная горизонтальная скорость в режимах POSCTL, OFFBOARD, AUTO. + +`MPC_Z_P`, `MPC_Z_VEL_P` – коэффициенты *P* регуляторов по вертикальной позиции и скорости. Влияют на удерживание коптером необходимой высоты. + +`MPC_LAND_SPEED` – вертикальная скорость посадки в режиме LAND. + +## LPE + Q attitude estimator + +Данные параметры настраивают поведение модулей `lpe` и `q`, которые вычисляют состояние (ориентацию, позицию) коптера. Эти параметры применяются **только** если параметр `SYS_MC_EST_GROUP` установлен в значение `1` (local_position_estimator, attitude_estimator_q) + +TODO + +## Commander + +Преарм-чеки, переключение режимов и состояний коптера. + +## Sensors + +Включение, выключение и настройка различных датчков. + +TODO 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..0b0cca3c 100644 --- a/docs/rviz.md +++ b/docs/rviz.md @@ -1,11 +1,13 @@ -Использование rviz +Использование rviz и rqt === -![](assets/Снимок экрана 2017-11-28 в 23.50.36.png) +![](assets/rviz.png) Инструмент [rviz](http://wiki.ros.org/rviz) позволяет в реальном времени визуализировать на 3D-сцене все компоненты роботехнической системы — системы координат, движущиеся части, показания датчиков, изображения с камер. -Для использования rviz необходим компьютер с ОС Ubuntu Linux (либо виртуальная машина, например [Parallels Desktop Lite](https://itunes.apple.com/ru/app/parallels-desktop-lite/id1085114709?mt=12) или [VirtualBox](https://www.virtualbox.org)). +[rqt](http://wiki.ros.org/rqt) – это набор GUI для анализа и контроля ROS-систем. Например, `rqt_image_view` позволяет просматривать топики с изображениями, `rqt_multiplot` – строить графики по значениям в топиках и т. д. + +Для использования rviz и rqt необходим компьютер с ОС Ubuntu Linux (либо виртуальная машина, например [Parallels Desktop Lite](https://itunes.apple.com/ru/app/parallels-desktop-lite/id1085114709?mt=12) или [VirtualBox](https://www.virtualbox.org)). На него необходимо установить пакет `ros-kinetic-desktop-full` или `ros-kinetic-desktop`, используя [документацию по установке](http://wiki.ros.org/kinetic/Installation/Ubuntu). @@ -24,9 +26,46 @@ ROS_MASTER_URI=http://192.168.11.1:11311 rviz export ROS_IP=192.168.11.1 ``` -Использование +Использование rviz --- -В качестве reference frame рекомендуется установить фрейм `local_origin`. Для визуализации коптера можно добавить визуализационные маркеры из топика `/vehicle_markers`. Можно просмотреть картинку с дополненной реальностью из топика основной камеры `/main_camera/image_raw`. +### Визуализация положения коптера + +В качестве reference frame рекомендуется установить фрейм `local_origin`. Для визуализации коптера добавьте визуализационные маркеры из топика `/vehicle_markers`. Для визуализации камеры коптера добавьте визуализационные маркеры из топика `/main_camera/camera_markers`. + +Результат визуализации коптера и камеры представлен ниже: + +![](assets/copter_visualization.png) + + +### Визуализация окружения + +Можно просмотреть картинку с дополненной реальностью из топика основной камеры `/main_camera/image_raw`. Axis или Grid настроенный на фрейм `aruco_map` будут визуализировать расположение [карты ArUco-меток](aruco.md). + +Запуск инструментов rqt +--- + +![](assets/rqt.png) + +Для запуска rqt для мониторинга состояния Клевера используйте команду: + +```bash +ROS_MASTER_URI=http://192.168.11.1:11311 rqt +``` + +Пример запуск конкретного плагина (`rqt_image_view`): + +```bash +ROS_MASTER_URI=http://192.168.11.1:11311 rqt_image_view +``` + +jsk_rviz_plugins +--- + +Рекомендуется также установка набора дополнительных полезных плагинов для rviz [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..9b53c420 100644 --- a/docs/snippets.md +++ b/docs/snippets.md @@ -9,7 +9,7 @@ Python > # -*- coding: utf-8 -*- > ``` ---- +

#

Функция определения расстяния между двумя точками (**важно**: точки должны быть в одной [системе координат](frames.md)): @@ -18,7 +18,7 @@ def get_distance(x1, y1, z1, x2, y2, z2): return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2) ``` ---- +

#

Функция для приблизительного определения расстояния (в метрах) между двумя глобальными координатами (широта/долгота): @@ -27,7 +27,7 @@ def get_distance_global(lat1, lon1, lat2, lon2): return math.hypot(lat1 - lat2, lon1 - lon2) * 1.113195e5 ``` ---- +

#

Взлет и ожидание окончания взлета: @@ -50,7 +50,7 @@ while True: rospy.sleep(0.2) ``` ---- +

#

Лететь в точку и ждать пока коптер долетит в нее: @@ -71,19 +71,75 @@ while True: rospy.sleep(0.2) ``` ---- +

#

+ +Дизарм коптера (выключение винтов, **коптер упадет**): + +```python +# Объявление прокси: +from mavros_msgs.srv import CommandBool +arming = rospy.ServiceProxy('mavros/cmd/arming', CommandBool) + +# ... + +arming(False) # дизарм +``` + +

#

+ +Трансформировать позицию (`PoseStamped`) из одной системы координат ([фрейма](frames.md)) в другую, используя [tf2](http://wiki.ros.org/tf2): + +```python +import tf2_ros +import tf2_geometry_msgs + +tf_buffer = tf2_ros.Buffer() +tf_listener = tf2_ros.TransformListener(tf_buffer) + +# ... + +# Создаем объект PoseStamped (либо получаем из топика): +pose = PoseStamped() +pose.header.frame_id = 'local_origin' # фрейм, в котором задана позиция +pose.header.stamp = rospy.get_rostime() # момент времени, для которого задана позиция (текущее время) +pose.pose.position.x = 1 +pose.pose.position.y = 2 +pose.pose.position.z = 3 +pose.pose.orientation.w = 1 + +frame_id = 'fcu' # целевой фрейм +transform_timeout = rospy.Duration(0.2) # таймаут ожидания транформации + +# Преобразовываем позицию из старого фрейма в новый: +new_pose = tf_buffer.transform(pose, frame_id, transform_timeout) +``` + +

#

+ +Определение, перевернут ли коптер: + +```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 ``` ---- +

#

Полет по круговой траектории: @@ -105,7 +161,18 @@ while not rospy.is_shutdown(): r.sleep() ``` ---- +

#

+ +Повторять действие с частотой 10 Гц: + +```python +r = rospy.Rate(10) +while not rospy.is_shutdown(): + # Do anything + r.sleep() +``` + +

#

Пример подписки на топики из MAVROS: @@ -132,7 +199,7 @@ rospy.Subscriber('mavros/rc/in', RCIn, rc_callback) Информацию по топикам MAVROS см. по [ссылке](mavros.md). ---- + Пример отправки произвольного [MAVLink-сообщения](mavlink.md) коптеру: @@ -156,7 +223,7 @@ ros_msg = mavlink.convert_to_rosmsg(msg) mavlink_pub.publish(ros_msg) ``` ---- +

#

Реакция на переключение режима на пульте радиоуправления (может быть использовано для запуска автономного полета, см. [пример](https://gist.github.com/okalachev/b709f04522d2f9af97e835baedeb806b)): @@ -165,16 +232,16 @@ from mavros_msgs.msg import RCIn # Вызывается при получении новых данных с пульта def rc_callback(data): - # Произвольная реакция на переключение тумблера на пульте - if data.channels[5] < 1100: - # ... - pass - elif data.channels[5] > 1900: - # ... - pass - else: - # ... - pass + # Произвольная реакция на переключение тумблера на пульте + if data.channels[5] < 1100: + # ... + pass + elif data.channels[5] > 1900: + # ... + pass + else: + # ... + pass # Создаем подписчик на топик с данными с пульта rospy.Subscriber('mavros/rc/in', RCIn, rc_callback) @@ -182,7 +249,7 @@ rospy.Subscriber('mavros/rc/in', RCIn, rc_callback) rospy.spin() ``` ---- +

#

Флип: 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 +``` diff --git a/image_builder/Jenkinsfile b/image_builder/Jenkinsfile deleted file mode 100644 index e3b28530..00000000 --- a/image_builder/Jenkinsfile +++ /dev/null @@ -1,35 +0,0 @@ -pipeline { - agent any - parameters { - string(name: 'GWBT_REF', defaultValue: "master") - string(name: 'GWBT_URL', defaultValue: "https://github.com/CopterExpress/clever.git") - string(name: 'GWBT_FILE', defaultValue: "") - string(name: 'IMAGE_NAME', defaultValue: "\$(cat ${GWBT_FILE} | jq '.repository.name' -r)-${params.GWBT_REF}.img") - string(name: 'GWBT_EVENT', defaultValue: 'release') - booleanParam(name: 'ONLY_PUBLISH', defaultValue: false, description: 'ONLY PUBLISH') - string(name: 'BUILD_DIR', defaultValue: '/mnt/hdd_builder/workspace', description: 'Build workspace') - } - environment { - DEBIAN_FRONTEND = 'noninteractive' - LANG = 'C.UTF-8' - LC_ALL = 'C.UTF-8' - } - stages { - stage('Build image') { - when { not { expression { return params.ONLY_PUBLISH } } } - steps { - build job: 'CopterExpress-clever-build', parameters: [[$class: 'StringParameterValue', name: 'IMAGE_NAME', value: "${params.IMAGE_NAME}"], [$class: 'StringParameterValue', name: 'IMAGE_VERSION', value: "${params.GWBT_REF}"], [$class: 'StringParameterValue', name: 'GWBT_REF', value: "${params.GWBT_REF}"], [$class: 'StringParameterValue', name: 'GWBT_URL', value: "${params.GWBT_URL}"]] - } - } - stage('Publish image') { - when { environment name: 'GWBT_EVENT', value: 'release' } - environment { - CONFIG_FILE = "${params.BUILD_DIR}/coex-ci.json" - YA_SCRIPT = "$WORKSPACE/image_builder/yadisk.py" - } - steps { - sh "$WORKSPACE/image_builder/image_config.sh publish_image ${params.BUILD_DIR} ${params.IMAGE_NAME} ${YA_SCRIPT} ${CONFIG_FILE} \$(cat ${params.GWBT_FILE} | jq '.release.id' -r) \"\$(cat ${params.GWBT_FILE} | jq '.release.body' | sed 's/\"//' | rev | sed 's/\"//' | rev)\"" - } - } - } -} diff --git a/image_builder/README.md b/image_builder/README.md deleted file mode 100644 index d4b0242e..00000000 --- a/image_builder/README.md +++ /dev/null @@ -1,89 +0,0 @@ -## Setup your builder - -1. Install requirements -```(bash) -sudo apt-get install unzip zip git python-pip jq curl -sudo pip install YaDiskClient -``` -2. Mount HDD -```bash -nano /etc/fstab -``` -``` -proc /proc proc defaults 0 0 -PARTUUID=37665771-01 /boot vfat defaults 0 2 -PARTUUID=37665771-02 / ext4 defaults,noatime 0 1 -# a swapfile is not a swap partition, no line here -# use dphys-swapfile swap[on|off] for that -/dev/sdb1 none swap sw 0 0 -/dev/sdb2 /mnt/hdd_system ext4 defaults,acl 0 0 -/dev/sdb3 /mnt/hdd_builder ext4 defaults,acl 0 0 -``` - -3. Enable swap on HDD -> TODO: - -And disable `dphys-swapfile` -```(bash) -sudo systemctl stop dphys-swapfile -sudo systemctl disable dphys-swapfile -``` - -3. Create /mnt/hdd_builder/workspace/coex-ci.json -```(json) -{ - "yadisk": - { - "login":"LOGIN", - "password":"PASS", - "server_dir":"/clever_images" - }, - "github": - { - "login":"LOGIN", - "password":"PASS", - "url":"https://api.github.com/repos/CopterExpress/clever/releases/" - } -} -``` -6. Add webhook to release on your github project -> TODO - -9. Install Jenkins -> Manual https://www.digitalocean.com/community/tutorials/how-to-install-jenkins-on-ubuntu-16-04 - -10. Change user & group invoked Jenkins -```(bash) -sudo sed -i 's/JENKINS_USER=$NAME/JENKINS_USER=root/' /etc/default/jenkins -sudo sed -i 's/JENKINS_GROUP=$NAME/JENKINS_GROUP=root/' /etc/default/jenkins -``` -11. Install Jenikins plugins -> Pipeline, Git SCM - -12. Create Jenkins pipeline job -> TODO - -13. Configure Jenkins -> TODO: Matrix autorization, GIT Token - -13. Add Jenkins service to autostart -```(bash) -sudo systemctl enable jenkins -``` - -14. Start service -```(bash) -sudo systemctl start jenkins -``` - -## Requirements - -* Jenkins (BlueOcean plugin, optional) - -## Troubleshooting - -If JDK not installed: - -```bash -sudo apt-get install default-jdk -``` diff --git a/image_builder/autosizer.sh b/image_builder/autosizer.sh deleted file mode 100755 index 191de1dc..00000000 --- a/image_builder/autosizer.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/bash - -set -e - -if [ $(whoami) != "root" ]; then - echo \ - && echo "********************************************************************" \ - && echo "******************** This should be run as root ********************" \ - && echo "********************************************************************" \ - && echo \ - && exit 1 -fi - -if [[ -z $1 ]]; then - echo "================================================================================" - echo -e "\033[0;31m\033[1mAutomatic Image file resizer\033[0m\033[0m" - echo -e "\033[0;31m\033[1mDescription:\033[0m\033[0m This script shrink your image to 10MiB free space" - echo -e "if you didn't set FREE_SPACE in MiB (see usage below)." - echo -e "\033[0;31m\033[1mAuthors:\033[0m\033[0m Artem Smirnov @urpylka, SirLagz" - echo - echo -e "\033[0;31m\033[1mUsage:\033[0m\033[0m ./autosizer.sh PATH_TO_IMAGE FREE_SPACE" - echo - echo -e "\033[0;31m\033[1mRequirements:\033[0m\033[0m parted, losetup, e2fsck, resize2fs, bc, truncate" - echo "================================================================================" - exit 0 -fi - -echo "================================================================================" -strImgFile=$1 -echo -e "\033[0;31m\033[1mPath to image: $strImgFile\033[0m\033[0m" -echo "================================================================================" - -if [[ ! -e $strImgFile ]]; then - echo -e "\033[0;31m\033[1mError: File doesn't exist\033[0m\033[0m" - echo - exit 1 -fi - -echo "================================================================================" -partinfo=`parted -m $strImgFile unit B print` -echo -e "\033[0;31m\033[1mPartition information:\033[0m\033[0m\n$partinfo" -echo "================================================================================" - -partnumber=`echo "$partinfo" | grep ext4 | awk -F: '{ print $1 }'` -echo -e "\033[0;31m\033[1mPartition number: $partnumber\033[0m\033[0m" -echo "================================================================================" - -partstart=`echo "$partinfo" | grep ext4 | awk -F: '{ print substr($2,0,length($2)-1) }'` -echo -e "\033[0;31m\033[1mPartition start: $partstart (bytes)\033[0m\033[0m" -echo "================================================================================" - -loopback=`losetup -f --show -o $partstart $strImgFile` -echo -e "\033[0;31m\033[1mLoopback device: $loopback\033[0m\033[0m" -echo "================================================================================" - -set +e -e2fsck -fvy $loopback -set -e - -echo "================================================================================" -minsize=`resize2fs -P $loopback | awk -F': ' '{ print $2 }'` -#minsize=`resize2fs -P $loopback 2> /dev/null | awk -F': ' '{ print $2 }'` -echo -e "\033[0;31m\033[1mMinsize: $minsize (4KiB)\033[0m\033[0m" -echo "================================================================================" - -# Default add 10MiB free space to image, if $2 doesn't set -FREE_SPACE=${2:-10} - -FREE_SPACE=$(($FREE_SPACE*1024*1024/4096)) - -minsize=`echo "$minsize+$FREE_SPACE" | bc` -echo -e "\033[0;31m\033[1mMinsize + $FREE_SPACE (4KiB): $minsize (4KiB)\033[0m\033[0m" -echo "================================================================================" - -resize2fs -p $loopback $minsize -sleep 1 -losetup -d $loopback - -echo "================================================================================" -partnewsize=`echo "$minsize * 4096" | bc` -echo -e "\033[0;31m\033[1mNew size of part: $minsize (4KiB) = $partnewsize (bytes)\033[0m\033[0m" -echo "================================================================================" - -newpartend=`echo "$partstart + $partnewsize" | bc` -echo -e "\033[0;31m\033[1mNew end of part (Part start + part new size):\033[0m\033[0m" -echo -e "\033[0;31m\033[1m$partstart (bytes) + $partnewsize (bytes) = $newpartend (bytes)\033[0m\033[0m" -echo "================================================================================" - -part1=`parted $strImgFile rm 2` -echo "================================================================================" -part2=`parted $strImgFile unit B mkpart primary $partstart $newpartend` - -echo "================================================================================" -endresult=`parted -m $strImgFile unit B print free | tail -1 | awk -F: '{ print substr($2,0,length($2)-1) }'` -echo -e "\033[0;31m\033[1mSize of result image: $endresult (bytes)\033[0m\033[0m" -echo "================================================================================" - -truncate -s $endresult $strImgFile - -echo "================================================================================" -partinfo=`parted -m $strImgFile unit B print` -echo -e "\033[0;31m\033[1mPartition information:\033[0m\033[0m\n$partinfo" -echo "================================================================================" diff --git a/image_builder/build.Jenkinsfile b/image_builder/build.Jenkinsfile deleted file mode 100644 index 1426248b..00000000 --- a/image_builder/build.Jenkinsfile +++ /dev/null @@ -1,94 +0,0 @@ -pipeline { - agent any - parameters { - string(name: 'IMAGE_NAME', defaultValue: 'clever_noname.img', description: 'Output image file name') - string(name: 'GWBT_REF', defaultValue: 'master', description: 'Checkout ref-param') - string(name: 'IMAGE_VERSION', defaultValue: 'no_version', description: 'Image version') - - string(name: 'BUILD_DIR', defaultValue: '/mnt/hdd_builder/workspace', description: 'Build workspace') - - string(name: 'RPI_DONWLOAD_URL', defaultValue: 'https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2017-12-01/2017-11-29-raspbian-stretch-lite.zip') - // TODO: Add mirrorparameters - - string(name: 'GWBT_URL', defaultValue: 'https://github.com/CopterExpress/clever.git') - - // Experimental function - booleanParam(name: 'SHRINK', defaultValue: true, description: 'SHRINK IMAGE') - booleanParam(name: 'DISCOVER_ROS_PACKAGES', defaultValue: false, description: 'DISCOVER ROS PACKAGES') - } - environment { - DEBIAN_FRONTEND = 'noninteractive' - LANG = 'C.UTF-8' - LC_ALL = 'C.UTF-8' - } - stages { - stage('Get image') { - steps { - sh "$WORKSPACE/image_builder/image_config.sh get_image ${params.BUILD_DIR} ${params.RPI_DONWLOAD_URL} ${params.IMAGE_NAME}" - } - } - stage('Resize FS') { - environment { - SIZE = '7G' - } - steps { - sh "$WORKSPACE/image_builder/image_config.sh resize_fs ${params.BUILD_DIR}/${params.IMAGE_NAME} $SIZE" - } - } - stage('Initialize image') { - environment { - EXECUTE_FILE = 'image_builder/scripts/init_image.sh' - } - // TODO: Transfer apps.sh initialisation code here - steps { - sh "$WORKSPACE/image_builder/image_config.sh execute ${params.BUILD_DIR}/${params.IMAGE_NAME} $WORKSPACE/$EXECUTE_FILE ${params.IMAGE_VERSION} \$(basename ${params.RPI_DONWLOAD_URL})" - } - } - stage('Hardware setup') { - environment { - EXECUTE_FILE = 'image_builder/scripts/hardware_setup.sh' - } - steps { - sh "$WORKSPACE/image_builder/image_config.sh execute ${params.BUILD_DIR}/${params.IMAGE_NAME} $WORKSPACE/$EXECUTE_FILE" - } - } - stage('Software install') { - environment { - EXECUTE_FILE = 'image_builder/scripts/software_install.sh' - } - steps { - sh "$WORKSPACE/image_builder/image_config.sh execute ${params.BUILD_DIR}/${params.IMAGE_NAME} $WORKSPACE/$EXECUTE_FILE" - } - } - stage('Network setup') { - environment { - EXECUTE_FILE = 'image_builder/scripts/network_setup.sh' - } - steps { - sh "$WORKSPACE/image_builder/image_config.sh execute ${params.BUILD_DIR}/${params.IMAGE_NAME} $WORKSPACE/$EXECUTE_FILE" - } - } - stage('Install ROS') { - environment { - EXECUTE_FILE = 'image_builder/scripts/ros_install.sh' - MOVE_FILE = 'image_builder/kinetic-ros-coex.rosinstall' - MOVE_TO = '/home/pi/ros_catkin_ws' - } - steps { - sh "if ! ${params.DISCOVER_ROS_PACKAGES}; then $WORKSPACE/image_builder/image_config.sh copy_to_chroot ${params.BUILD_DIR}/${params.IMAGE_NAME} $WORKSPACE/$MOVE_FILE $MOVE_TO; fi" - sh "$WORKSPACE/image_builder/image_config.sh execute ${params.BUILD_DIR}/${params.IMAGE_NAME} $WORKSPACE/$EXECUTE_FILE ${params.GWBT_URL} ${params.GWBT_REF} ${params.DISCOVER_ROS_PACKAGES}" - } - } - // TODO: Add finalising step, transfer mirror removal from ros.sh - stage('Shrink image') { - environment { - EXECUTE_FILE = 'image_builder/scripts/change_boot_part.sh' - } - when { expression { return params.SHRINK } } - steps { - sh "$WORKSPACE/image_builder/autosizer.sh ${params.BUILD_DIR}/${params.IMAGE_NAME}" - sh "$WORKSPACE/image_builder/image_config.sh execute ${params.BUILD_DIR}/${params.IMAGE_NAME} $WORKSPACE/$EXECUTE_FILE" - } - } - } -} diff --git a/image_builder/image_config.sh b/image_builder/image_config.sh deleted file mode 100755 index d8d86c92..00000000 --- a/image_builder/image_config.sh +++ /dev/null @@ -1,385 +0,0 @@ -#!/bin/bash - -# Exit immidiately on non-zero result -set -e - -# -# Script for image configure -# @urpylka Artem Smirnov -# @dvornikov-aa Andrey Dvornikov -# - -get_image() { - -# STATIC FUNCTION -# TEMPLATE: get_image $BUILD_DIR $RPI_DONWLOAD_URL $IMAGE_NAME - - local RPI_ZIP_NAME=$(basename $2) - if [ ! -e "$1/${RPI_ZIP_NAME}" ]; - then - echo "$(date) | 1. Downloading original Linux distribution" - wget -nv -O $1/${RPI_ZIP_NAME} $2 - echo "$(date) | Downloading complete" - else - echo "$(date) | 1. Linux distribution already donwloaded" - fi - echo "$(date) | 2. Unzipping Linux distribution image" - local RPI_IMAGE_NAME=$(echo ${RPI_ZIP_NAME} | sed 's/zip/img/') - unzip -p $1/${RPI_ZIP_NAME} ${RPI_IMAGE_NAME} > $1/$3 - echo "$(date) | Unzipping complete" -} - -resize_fs() { - - # STATIC FUNCTION - # TEMPLATE: resize_fs $IMAGE_PATH $SIZE - - # Partitions numbers - local BOOT_PARTITION=1 - local ROOT_PARTITION=2 - - set +e - - # https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D1%91%D0%BD%D0%BD%D1%8B%D0%B9_%D1%84%D0%B0%D0%B9%D0%BB - - # https://raspberrypi.stackexchange.com/questions/13137/how-can-i-mount-a-raspberry-pi-linux-distro-image - # fdisk -l 2017-11-29-raspbian-stretch-lite.img - # https://www.stableit.ru/2011/05/losetup.html - # -f : losetup сам выбрал loop (минуя занятые) - # -P : losetup монтирует разделы в образе как отдельные подразделы, - # например /dev/loop0p1 и /dev/loop0p2 - # --show : печатает имя устройства, например /dev/loop4 - - # http://karelzak.blogspot.ru/2015/05/resize-by-sfdisk.html - # ", +" : expand partition for volume size - # -N 2 : select second partition for work - - # There is a risk that sfdisk will ask for a disk remount to update partition table - # TODO: Check sfdisk exit code - - echo -e "\033[0;31m\033[1mTruncate image\033[0m\033[0m" \ - && truncate -s$2 $1 \ - && echo "Mount loop-image: $1" \ - && local DEV_IMAGE=$(losetup -Pf $1 --show) \ - && sleep 0.5 \ - && echo -e "\033[0;31m\033[1mMount loop-image: $1\033[0m\033[0m" \ - && echo ", +" | sfdisk -N ${ROOT_PARTITION} ${DEV_IMAGE} \ - && sleep 0.5 \ - && losetup -d ${DEV_IMAGE} \ - && sleep 0.5 \ - && local DEV_IMAGE=$(losetup -Pf $1 --show) \ - && sleep 0.5 \ - && echo -e "\033[0;31m\033[1mCheck & repair filesystem after expand partition\033[0m\033[0m" \ - && e2fsck -fvy "${DEV_IMAGE}p${ROOT_PARTITION}" \ - && echo -e "\033[0;31m\033[1mExpand filesystem\033[0m\033[0m" \ - && resize2fs "${DEV_IMAGE}p${ROOT_PARTITION}" \ - && echo -e "\033[0;31m\033[1mUmount loop-image\033[0m\033[0m" \ - && losetup -d ${DEV_IMAGE} - - set -e -} - -mount_system() { - - # STATIC FUNCTION - # TEMPLATE: mount_system $IMAGE - - # Partitions numbers - local BOOT_PARTITION=1 - local ROOT_PARTITION=2 - - # https://www.stableit.ru/2011/05/losetup.html - # -f : losetup выбирает незанятое имя устройства, например /dev/loop2 - # -P : losetup монтирует разделы в образе как отдельные подразделы, - # например /dev/loop0p1 и /dev/loop0p2 - # --show : печатает имя устройства, например /dev/loop4 - - echo -e "\033[0;31m\033[1mMount loop-image: $1\033[0m\033[0m" - local DEV_IMAGE=$(losetup -Pf $1 --show) - sleep 0.5 - - # Get temp directory to mount image - local MOUNT_POINT=$(mktemp -d) - - echo -e "\033[0;31m\033[1mMount dirs ${MOUNT_POINT} & ${MOUNT_POINT}/boot\033[0m\033[0m" - mount "${DEV_IMAGE}p${ROOT_PARTITION}" ${MOUNT_POINT} - mount "${DEV_IMAGE}p${BOOT_PARTITION}" ${MOUNT_POINT}/boot - - echo -e "\033[0;31m\033[1mBind system dirs\033[0m\033[0m" - # https://github.com/debian-pi/raspbian-ua-netinst/issues/314 - echo "Mounting /proc in chroot... " - if [ ! -d ${MOUNT_POINT}/proc ] ; then - mkdir -p ${MOUNT_POINT}/proc \ - && echo "Created ${MOUNT_POINT}/proc" - fi - mount -t proc -o nosuid,noexec,nodev proc ${MOUNT_POINT}/proc \ - && echo "OK" - - echo "Mounting /sys in chroot... " - if [ ! -d ${MOUNT_POINT}/sys ] ; then - mkdir -p ${MOUNT_POINT}/sys \ - && echo "Created ${MOUNT_POINT}/sys" - fi - mount -t sysfs -o nosuid,noexec,nodev sysfs ${MOUNT_POINT}/sys \ - && echo "OK" - - echo "Mounting /dev/ and /dev/pts in chroot... " \ - && mkdir -p -m 755 ${MOUNT_POINT}/dev/pts \ - && mount -t devtmpfs -o mode=0755,nosuid devtmpfs ${MOUNT_POINT}/dev \ - && mount -t devpts -o gid=5,mode=620 devpts ${MOUNT_POINT}/dev/pts \ - && echo "OK" - # mount -t devpts none "${MOUNT_POINT}/dev/pts" -o ptmxmode=0666,newinstance - # ln -fs "pts/ptmx" "${MOUNT_POINT}/dev/ptmx" - - # mount -o bind /dev ${MOUNT_POINT}/dev - # mount -t proc proc ${MOUNT_POINT}/proc - # mount -t devpts devpts ${MOUNT_POINT}/dev/pts - - # mount -t proc proc ${MOUNT_POINT}/proc - # mount -t sysfs sys ${MOUNT_POINT}/sys - # mount --bind /dev ${MOUNT_POINT}/dev - - echo -e "\033[0;31m\033[1mCopy DNS records\033[0m\033[0m" \ - && cp -L /etc/resolv.conf ${MOUNT_POINT}/etc/resolv.conf - - # https://wiki.archlinux.org/index.php/Change_root_(%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9) - # http://www.unix-lab.org/posts/chroot/ - # https://habrahabr.ru/post/141012/ - # https://losst.ru/vosstanovlenie-grub2 - # http://unixteam.ru/content/virtualizaciya-ili-zapuskaem-prilozhenie-v-chroot-okruzhenii-razmyshleniya - # http://help.ubuntu.ru/wiki/%D0%B2%D0%BE%D1%81%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_grub - echo -e "\033[0;31m\033[1mEnter chroot\033[0m\033[0m" \ - && chroot ${MOUNT_POINT} /bin/bash - - umount_system ${MOUNT_POINT} ${DEV_IMAGE} -} - -execute() { - - # STATIC FUNCTION - # TEMPLATE: execute $IMAGE $EXECUTE_FILE ... - - # Partitions numbers - local BOOT_PARTITION=1 - local ROOT_PARTITION=2 - - echo -e "\033[0;31m\033[1mMount loop-image: $1\033[0m\033[0m" - local DEV_IMAGE=$(losetup -Pf $1 --show) - sleep 0.5 - - # Get temp directory to mount image - local MOUNT_POINT=$(mktemp -d) - - echo -e "\033[0;31m\033[1mMount dirs ${MOUNT_POINT} & ${MOUNT_POINT}/boot\033[0m\033[0m" - mount "${DEV_IMAGE}p${ROOT_PARTITION}" ${MOUNT_POINT} - mount "${DEV_IMAGE}p${BOOT_PARTITION}" ${MOUNT_POINT}/boot - - echo -e "\033[0;31m\033[1mBind system dirs\033[0m\033[0m" - echo "Mounting /proc in chroot... " - if [ ! -d ${MOUNT_POINT}/proc ] ; then - mkdir -p ${MOUNT_POINT}/proc - echo "Created ${MOUNT_POINT}/proc" - fi - mount -t proc -o nosuid,noexec,nodev proc ${MOUNT_POINT}/proc \ - && echo "OK" - - echo "Mounting /sys in chroot... " - if [ ! -d ${MOUNT_POINT}/sys ] ; then - mkdir -p ${MOUNT_POINT}/sys - echo "Created ${MOUNT_POINT}/sys" - fi - mount -t sysfs -o nosuid,noexec,nodev sysfs ${MOUNT_POINT}/sys \ - && echo "OK" - - echo "Mounting /dev/ and /dev/pts in chroot... " \ - && mkdir -p -m 755 ${MOUNT_POINT}/dev/pts \ - && mount -t devtmpfs -o mode=0755,nosuid devtmpfs ${MOUNT_POINT}/dev \ - && mount -t devpts -o gid=5,mode=620 devpts ${MOUNT_POINT}/dev/pts \ - && echo "OK" - - echo -e "\033[0;31m\033[1mCopy DNS records\033[0m\033[0m" \ - && cp -L /etc/resolv.conf ${MOUNT_POINT}/etc/resolv.conf - - echo -e "\033[0;31m\033[1m$(date) | Enter chroot\033[0m\033[0m" - local script_name=$(basename $2) - local script_path_root="${MOUNT_POINT}/root/${script_name}" - # Copy script into chroot fs - # TODO: Find more suitable location for temporary script storage - cp "$2" "${script_path_root}" - # Its important to save arguments (direct ${@:4} causes problems) - script_args="${@:3}" - # Run script in chroot with additional arguments - chroot ${MOUNT_POINT} /bin/sh -c "/root/${script_name} ${script_args}" - # Removing script from chroot fs - rm "${script_path_root}" - - umount_system ${MOUNT_POINT} ${DEV_IMAGE} -} - -copy_to_chroot() { - - # STATIC FUNCTION - # TEMPLATE: copy_to_chroot $IMAGE $MOVE_FILE $MOVE_TO - - # Partitions numbers - local BOOT_PARTITION=1 - local ROOT_PARTITION=2 - - echo -e "\033[0;31m\033[1mMount loop-image: $1\033[0m\033[0m" - local DEV_IMAGE=$(losetup -Pf $1 --show) - sleep 0.5 - - # Get temp directory to mount image - local MOUNT_POINT=$(mktemp -d) - - echo -e "\033[0;31m\033[1mMount dirs ${MOUNT_POINT} & ${MOUNT_POINT}/boot\033[0m\033[0m" - mount "${DEV_IMAGE}p${ROOT_PARTITION}" ${MOUNT_POINT} - mount "${DEV_IMAGE}p${BOOT_PARTITION}" ${MOUNT_POINT}/boot - - echo -e "\033[0;31m\033[1m$(date) | Enter chroot\033[0m\033[0m" - file_name=$(basename $2) - file_path_root="${MOUNT_POINT}$3/${file_name}" - # Copy script into chroot fs - # TODO: Find more suitable location for temporary script storage - if [ ! -d ${file_path_root} ] ; then - mkdir -p ${file_path_root} \ - && echo "Created ${file_path_root}" - fi - cp "$2" "${file_path_root}" - - umount_system ${MOUNT_POINT} ${DEV_IMAGE} -} - -umount_system() { - - # STATIC FUNCTION - # TEMPLATE: umount_system $MOUNT_POINT $DEV_IMAGE - - echo -e "\033[0;31m\033[1m$(date) | Umount recursive dirs: $1\033[0m\033[0m" - # There is a risk that umount will fail - set +e - # Successfull unmount flag (false at thismoment) - umount_ok=false - # Repeat 5 times - for i in {1..5} - do - # Unmount chroot rootfs and boot partition - umount -fR $1 - # If no problems detected - if [[ $? == 0 ]] - then - echo -e "\033[0;31m\033[1m$(date) | Successfull unmount\033[0m\033[0m" - # Set flag - umount_ok=true - # Exit loop - break - fi - # Unmount has failed - echo -e "\033[0;31m\033[1m$(date) | Unmount failed\033[0m\033[0m" - # Wait for some time - sleep 2 - done - set -e - # Jenkins job will fail if this condition is not true - [[ "$umount_ok" == true ]] - echo -e "\033[0;31m\033[1m$(date) | Umount loop-image\033[0m\033[0m" - #losetup -d $DEV_IMAGE - losetup -d $2 -} - -publish_image() { - -# STATIC FUNCTION -# TEMPLATE: publish_image_bash $BUILD_DIR $IMAGE_NAME $YA_SCRIPT $CONFIG_FILE $RELEASE_ID $RELEASE_BODY - -# https://developer.github.com/v3/repos/releases/ -#RELEASE_BODY="### Changelog\n* Add /boot/cmdline.txt net.ifnames=0 https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/\n* Updated cophelper\n* Installed copstat" - - echo -e "\033[0;31m\033[1m$(date) | Zip image\033[0m\033[0m" - if [ ! -e "$1/$2.zip" ]; - then - cd $1 && zip $2.zip $2 - echo -e "\033[0;31m\033[1m$(date) | Zipping complete!\033[0m\033[0m" - else - echo -e "\033[0;31m\033[1m$(date) | Zip-archive already created\033[0m\033[0m" - cd $1 && rm $2.zip && zip $2.zip $2 - echo -e "\033[0;31m\033[1m$(date) | Old archive was deleted & create new\033[0m\033[0m" - fi - - echo -e "\033[0;31m\033[1m$(date) | Upload image\033[0m\033[0m" - local IMAGE_LINK=$($3 $4 $1/$2.zip) - echo -e "\033[0;31m\033[1m$(date) | Upload copmlete!\033[0m\033[0m" - - echo -e "\033[0;31m\033[1m$(date) | Meashure size of zip-image\033[0m\033[0m" - local IMAGE_SIZE=$(du -sh $1/$2.zip | awk '{ print $1 }') - echo -e "\033[0;31m\033[1m$(date) | Meashuring copmlete!\033[0m\033[0m" - - echo -e "\033[0;31m\033[1m$(date) | Meashure hash-sum of zip-image\033[0m\033[0m" - local IMAGE_HASH=$(sha256sum $1/$2.zip | awk '{ print $1 }') - echo -e "\033[0;31m\033[1m$(date) | Meashuring copmlete!\033[0m\033[0m" - - echo "" - echo "\$6: $6" - echo "" - - echo -e "\033[0;31m\033[1m$(date) | Post message to GH\033[0m\033[0m" - local NEW_RELEASE_BODY="### Download\n* [$2.zip]($IMAGE_LINK) ($IMAGE_SIZE)\nsha256: $IMAGE_HASH\n\n$6" - local DATA="{ \"body\":\"$NEW_RELEASE_BODY\" }" - - echo "" - echo "\$DATA: $DATA" - echo "" - - local GH_LOGIN=$(cat $4 | jq '.github.login' -r) - local GH_PASS=$(cat $4 | jq '.github.password' -r) - local GH_URL=$(cat $4 | jq '.github.url' -r) - curl -d "$DATA" -u "$GH_LOGIN:$GH_PASS" --request PATCH $GH_URL$5 - echo -e "\033[0;31m\033[1m$(date) | Post message to GH copmlete!\033[0m\033[0m" -} - -if [ $(whoami) != "root" ]; -then echo "" \ - && echo "********************************************************************" \ - && echo "******************** This should be run as root ********************" \ - && echo "********************************************************************" \ - && echo "" \ - && exit 1 -fi - -echo "\$#: $#" -echo "\$1: $1" -echo "\$2: $2" -echo "\$3: $3" -echo "\$4: $4" -echo "\$5: $5" -echo "\$6: $6" -echo "\$7: $7" - -case "$1" in - mount_system) - # mount_system $IMAGE - mount_system $2;; - - get_image) - # get_image $BUILD_DIR $RPI_DONWLOAD_URL $IMAGE_NAME - get_image $2 $3 $4;; - - resize_fs) - # resize_fs $IMAGE_PATH $SIZE - resize_fs $2 $3;; - - publish_image) - # publish_image $BUILD_DIR $IMAGE_NAME $YA_SCRIPT $CONFIG_FILE $RELEASE_ID $RELEASE_BODY - publish_image $2 $3 $4 $5 $6 "$7";; - - execute) - # execute $IMAGE $EXECUTE_FILE ... - execute $2 $3 ${@:4};; - - copy_to_chroot) - # copy_to_chroot $IMAGE $MOVE_FILE $MOVE_TO - copy_to_chroot $2 $3 $4;; - - *) - echo "Enter one of: mount_system, get_image, resize_fs, publish_image, execute";; -esac diff --git a/image_builder/scripts/change_boot_part.sh b/image_builder/scripts/change_boot_part.sh deleted file mode 100755 index bca48d7a..00000000 --- a/image_builder/scripts/change_boot_part.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -e - -echo -e "\033[0;31m\033[1m$(date) | #1 Change boot partition\033[0m\033[0m" - -sed -i 's/root=[^ ]*/root=\/dev\/mmcblk0p2/' /boot/cmdline.txt -sed -i 's/.* \/boot vfat defaults 0 2$/\/dev\/mmcblk0p1 \/boot vfat defaults 0 2/' /etc/fstab -sed -i 's/.* \/ ext4 defaults,noatime 0 1$/\/dev\/mmcblk0p2 \/ ext4 defaults,noatime 0 1/' /etc/fstab - -echo -e "\033[0;31m\033[1m$(date) | End of change boot partition\033[0m\033[0m" diff --git a/image_builder/scripts/hardware_setup.sh b/image_builder/scripts/hardware_setup.sh deleted file mode 100755 index c748688e..00000000 --- a/image_builder/scripts/hardware_setup.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash - -# Exit immidiately on non-zero result -set -e - -# -# Script for image configure -# @urpylka Artem Smirnov -# - -################################################## -# Configure hardware interfaces -################################################## - -# 1. Enable sshd -echo -e "\033[0;31m\033[1m$(date) | #1 Turn on sshd\033[0m\033[0m" -touch /boot/ssh -# /usr/bin/raspi-config nonint do_ssh 0 - -# 2. Enable GPIO -echo -e "\033[0;31m\033[1m$(date) | #2 GPIO enabled by default\033[0m\033[0m" - -# 3. Enable I2C -echo -e "\033[0;31m\033[1m$(date) | #3 Turn on I2C\033[0m\033[0m" -/usr/bin/raspi-config nonint do_i2c 0 - -# 4. Enable SPI -echo -e "\033[0;31m\033[1m$(date) | #4 Turn on SPI\033[0m\033[0m" -/usr/bin/raspi-config nonint do_spi 0 - -# 5. Enable raspicam -echo -e "\033[0;31m\033[1m$(date) | #5 Turn on raspicam\033[0m\033[0m" -/usr/bin/raspi-config nonint do_camera 0 - -# 6. Enable hardware UART -echo -e "\033[0;31m\033[1m$(date) | #6 Turn on UART\033[0m\033[0m" -# Temporary solution -# https://github.com/RPi-Distro/raspi-config/pull/75 -/usr/bin/raspi-config nonint do_serial 1 -/usr/bin/raspi-config nonint set_config_var enable_uart 1 /boot/config.txt -/usr/bin/raspi-config nonint set_config_var dtoverlay pi3-miniuart-bt /boot/config.txt - -# After adding to Raspbian OS -# https://github.com/RPi-Distro/raspi-config/commit/d6d9ecc0d9cbe4aaa9744ae733b9cb239e79c116 -#/usr/bin/raspi-config nonint do_serial 2 - -# 7. Enable V4L driver http://robocraft.ru/blog/electronics/3158.html -#echo "bcm2835-v4l2" >> /etc/modules -echo -e "\033[0;31m\033[1m$(date) | #7 Turn on v4l2 driver\033[0m\033[0m" -if ! grep -q "^bcm2835-v4l2" /etc/modules; -then printf "bcm2835-v4l2\n" >> /etc/modules -fi - -echo -e "\033[0;31m\033[1m$(date) | End of configure hardware interfaces\033[0m\033[0m" diff --git a/image_builder/scripts/init_image.sh b/image_builder/scripts/init_image.sh deleted file mode 100755 index f8588345..00000000 --- a/image_builder/scripts/init_image.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -set -e - -################################################################################################################################## -# Image initialisation -################################################################################################################################## - -# Add apt key to allow local mirror usage during image build -#wget -O - ftp://192.168.0.10/coex-mirror.gpg | apt-key add - -# Generate a backup of the original source.list -#cp /etc/apt/sources.list /var/sources.list.bak -# Add the local mirror as the first priority repository -#wget -O - ftp://192.168.0.10/coex-mirror.list 2>/dev/null | cat - /etc/apt/sources.list > /var/sources.list && mv /var/sources.list /etc/apt/sources.list - -echo -e "\033[0;31m\033[1m$(date) | #1 apt cache update\033[0m\033[0m" - -# Clean repostory cache -apt-get clean -# Update repository cache -apt-get update -# && apt upgrade -y - -echo -e "\033[0;31m\033[1m$(date) | #2 Write clever information\033[0m\033[0m" - -# Clever image version -echo "$1" >> /etc/clever_version -# Origin image file name -echo "${2%.*}" >> /etc/clever_origin - -echo -e "\033[0;31m\033[1m$(date) | #3 End initialisation of image\033[0m\033[0m" diff --git a/image_builder/scripts/network_setup.sh b/image_builder/scripts/network_setup.sh deleted file mode 100755 index 420be48e..00000000 --- a/image_builder/scripts/network_setup.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -set -e - -echo -e "\033[0;31m\033[1m$(date) | #1 Write to /etc/wpa_supplicant/wpa_supplicant.conf\033[0m\033[0m" - -# TODO: Use wpa_cli insted direct file edit -echo " -network={ - ssid=\"CLEVER\" - psk=\"cleverwifi\" - mode=2 - proto=RSN - key_mgmt=WPA-PSK - pairwise=CCMP - group=CCMP - auth_alg=OPEN -}" >> /etc/wpa_supplicant/wpa_supplicant.conf - -echo -e "\033[0;31m\033[1m$(date) | #2 Write STATIC to /etc/dhcpcd.conf\033[0m\033[0m" - -echo " -interface wlan0 -static ip_address=192.168.11.1/24" >> /etc/dhcpcd.conf - -echo -e "\033[0;31m\033[1m$(date) | #3 Write dhcp-config to /etc/dnsmasq.conf\033[0m\033[0m" - -echo " -interface=wlan0 -address=/clever/coex/192.168.11.1 -dhcp-range=192.168.11.100,192.168.11.200,12h -no-hosts -filterwin2k -bogus-priv -domain-needed -quiet-dhcp6 -" >> /etc/dnsmasq.conf - -echo -e "\033[0;31m\033[1m$(date) | #4 Write magic script for rename SSID to /etc/rc.local\033[0m\033[0m" - -RENAME_SSID="sudo sed -i.OLD \"s/CLEVER/CLEVER-\$(head -c 100 /dev/urandom | xxd -ps -c 100 | sed -e 's/[^0-9]//g' | cut -c 1-4)/g\" /etc/wpa_supplicant/wpa_supplicant.conf && sudo sed -i '/sudo sed/d' /etc/rc.local && sudo reboot" - -sed -i "19a$RENAME_SSID" /etc/rc.local - -echo -e "\033[0;31m\033[1m$(date) | #5 End of network installation\033[0m\033[0m" diff --git a/image_builder/scripts/ros_install.sh b/image_builder/scripts/ros_install.sh deleted file mode 100755 index e161af0a..00000000 --- a/image_builder/scripts/ros_install.sh +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/bash - -set -e - -################################################################################################################################## -# ROS for user pi -################################################################################################################################## - -# ros http://wiki.ros.org/action/fullsearch/ROSberryPi/Installing%20ROS%20Kinetic%20on%20the%20Raspberry%20Pi - -echo -e "\033[0;31m\033[1m$(date) | Installing ROS\033[0m\033[0m" - -echo -e "\033[0;31m\033[1m$(date) | #1 Installing dirmngr & add key to apt-key\033[0m\033[0m" - -# Install a tool that apt-key uses to add ROS repository key -# http://wpblogger.su/tags/apt/ -apt-get install --no-install-recommends -y dirmngr=2.1.18-8~deb9u2 -# setup keys -apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116 - -# setup sources.list -echo "deb http://packages.ros.org/ros/ubuntu stretch main" > /etc/apt/sources.list.d/ros-latest.list - -echo -e "\033[0;31m\033[1m$(date) | #2 apt update && apt upgrade\033[0m\033[0m" - -# install bootstrap tools -apt-get update -# && apt upgrade -y - -echo -e "\033[0;31m\033[1m$(date) | #3 Installing wget, unzip, python-rosdep, python-rosinstall-generator, python-wstool, python-rosinstall, build-essential, cmake\033[0m\033[0m" - -apt-get install --no-install-recommends -y \ - python-rosdep=0.12.2-1 \ - python-rosinstall-generator=0.1.14-1 \ - python-wstool=0.1.17-1 \ - python-rosinstall=0.7.8-1 \ - build-essential=12.3 - -echo -e "\033[0;31m\033[1m$(date) | #4 rosdep init && rosdep update\033[0m\033[0m" - -# bootstrap rosdep -rosdep init && rosdep update - -# If $3 = false, then discover packages -if [ "$3" = "false" ]; -then - echo -e "\033[0;31m\033[1m$(date) | #5 Preparing ros_comm packages to kinetic-ros_comm-wet.rosinstall\033[0m\033[0m" - - # create ros catkin workspace - mkdir -p /home/pi/ros_catkin_ws && cd /home/pi/ros_catkin_ws \ - && rosinstall_generator ros_comm --rosdistro kinetic --deps --wet-only --tar > kinetic-ros_comm-wet.rosinstall \ - && wstool init src kinetic-ros_comm-wet.rosinstall - - echo -e "\033[0;31m\033[1m$(date) | #6 Preparing other ROS-packages to kinetic-custom_ros.rosinstall\033[0m\033[0m" - - cd /home/pi/ros_catkin_ws \ - && rosinstall_generator \ - actionlib actionlib_msgs angles async_web_server_cpp bond bond_core bondcpp bondpy camera_calibration_parsers camera_info_manager catkin class_loader cmake_modules cpp_common cv_bridge cv_camera diagnostic_msgs diagnostic_updater dynamic_reconfigure eigen_conversions gencpp geneus genlisp genmsg gennodejs genpy geographic_msgs geometry_msgs geometry2 image_transport libmavconn mavlink mavros_msgs message_filters message_generation message_runtime mk nav_msgs nodelet orocos_kdl pluginlib python_orocos_kdl ros ros_comm rosapi rosauth rosbag rosbag_migration_rule rosbag_storage rosbash rosboost_cfg rosbridge_library rosbridge_server rosbridge_suite rosbuild rosclean rosconsole rosconsole_bridge roscpp roscpp_serialization roscpp_traits roscreate rosgraph rosgraph_msgs roslang roslaunch roslib roslint roslisp roslz4 rosmake rosmaster rosmsg rosnode rosout rospack rosparam rospy rospy_tutorials rosserial rosserial_client rosserial_msgs rosserial_python rosservice rostest rostime rostopic rosunit roswtf sensor_msgs smclib std_msgs std_srvs stereo_msgs tf tf2 tf2_bullet tf2_eigen tf2_geometry_msgs tf2_kdl tf2_msgs tf2_py tf2_ros tf2_sensor_msgs tf2_tools topic_tools trajectory_msgs urdf urdf_parser_plugin usb_cam uuid_msgs visualization_msgs web_video_server xmlrpcpp mavros opencv3 mavros_extras \ - --rosdistro kinetic --deps --wet-only --tar > kinetic-custom_ros.rosinstall \ - && wstool merge -t src kinetic-custom_ros.rosinstall \ - && wstool update -t src -else - echo -e "\033[0;31m\033[1m$(date) | #5 Creating manual ros_catkin_ws\033[0m\033[0m" - - mkdir -p /home/pi/ros_catkin_ws && cd /home/pi/ros_catkin_ws \ - && wstool init src kinetic-ros-coex.rosinstall -fi - -echo -e "\033[0;31m\033[1m$(date) | #7 Installing dependencies apps with rosdep\033[0m\033[0m" -cd /home/pi/ros_catkin_ws -# There is a risk that umount will fail -set +e -# Successfull unmount flag (false at thismoment) -install_ok=false -# Repeat 5 times -for i in {1..5} -do - # Resolving Dependencies with rosdep - rosdep install -y --from-paths src --ignore-src --rosdistro kinetic -r --os=debian:stretch - # If no problems detected - if [[ $? == 0 ]] - then - echo -e "\033[0;31m\033[1m$(date) | Successfull rosdep install\033[0m\033[0m" - # Set flag - install_ok=true - # Exit loop - break - fi - # Unmount has failed - echo -e "\033[0;31m\033[1m$(date) | Rosdep installation failed\033[0m\033[0m" - # Wait for some time - sleep 2 -done -set -e -# Jenkins job will fail if this condition is not true -[[ "$install_ok" == true ]] -echo -e "\033[0;31m\033[1m$(date) | End of rosdep install\033[0m\033[0m" - -echo -e "\033[0;31m\033[1m$(date) | #8 Refactoring usb_cam in SRC\033[0m\033[0m" - -sed -i '/#define __STDC_CONSTANT_MACROS/a\#define PIX_FMT_RGB24 AV_PIX_FMT_RGB24\n#define PIX_FMT_YUV422P AV_PIX_FMT_YUV422P' /home/pi/ros_catkin_ws/src/usb_cam/src/usb_cam.cpp - -echo -e "\033[0;31m\033[1m$(date) | #9 Installing GeographicLib datasets\033[0m\033[0m" - -/home/pi/ros_catkin_ws/src/mavros/mavros/scripts/install_geographiclib_datasets.sh - -#echo -e "\033[0;31m\033[1m$(date) | #11 Building light packages on 2 threads\033[0m\033[0m" - -# Build the catkin Workspace -#cd /home/pi/ros_catkin_ws && ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release -j2 --install-space /opt/ros/kinetic --pkg actionlib actionlib_msgs angles async_web_server_cpp bond bond_core bondcpp bondpy camera_calibration_parsers camera_info_manager catkin class_loader cmake_modules cpp_common diagnostic_msgs diagnostic_updater dynamic_reconfigure eigen_conversions gencpp geneus genlisp genmsg gennodejs genpy geographic_msgs geometry_msgs geometry2 image_transport libmavconn mavlink mavros_msgs message_filters message_generation message_runtime mk nav_msgs nodelet orocos_kdl pluginlib python_orocos_kdl ros ros_comm rosapi rosauth rosbag rosbag_migration_rule rosbag_storage rosbash rosboost_cfg rosbridge_library rosbridge_server rosbridge_suite rosbuild rosclean rosconsole rosconsole_bridge roscpp roscpp_serialization roscpp_traits roscreate rosgraph rosgraph_msgs roslang roslaunch roslib roslint roslisp roslz4 rosmake rosmaster rosmsg rosnode rosout rospack rosparam rospy rospy_tutorials rosserial rosserial_client rosserial_msgs rosserial_python rosservice rostest rostime rostopic rosunit roswtf sensor_msgs smclib std_msgs std_srvs stereo_msgs tf tf2 tf2_bullet tf2_eigen tf2_geometry_msgs tf2_kdl tf2_msgs tf2_py tf2_ros tf2_sensor_msgs tf2_tools topic_tools trajectory_msgs urdf urdf_parser_plugin usb_cam uuid_msgs visualization_msgs xmlrpcpp - -#echo -e "\033[0;31m\033[1m$(date) | #12 Building heavy packages\033[0m\033[0m" - -# This command uses less threads to avoid Raspberry Pi freeze -# Build the catkin Workspace -#cd /home/pi/ros_catkin_ws && ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release -j1 --install-space /opt/ros/kinetic --pkg mavros opencv3 cv_bridge cv_camera mavros_extras web_video_server - -echo -e "\033[0;31m\033[1m$(date) | #10 Building packages on 1 thread\033[0m\033[0m" - -# Install builded packages -# WARNING: A major bug was found when using --pkg option (catkin_make_isolated doesn't install environment files) -# TODO: Can we increase threads number with HDD swap? -cd /home/pi/ros_catkin_ws && ./src/catkin/bin/catkin_make_isolated --install -j1 -DCMAKE_BUILD_TYPE=Release --install-space /opt/ros/kinetic - -echo -e "\033[0;31m\033[1m$(date) | #11 Remove build_isolated & devel_isolated from ros_catkin_ws\033[0m\033[0m" - -rm -rf /home/pi/ros_catkin_ws/build_isolated /home/pi/ros_catkin_ws/devel_isolated -chown -Rf pi:pi /home/pi/ros_catkin_ws - -echo -e "\033[0;31m\033[1m$(date) | #12 Creating catkin_ws & Installing CLEVER-BUNDLE\033[0m\033[0m" - -git clone $1 /home/pi/catkin_ws/src/clever \ - && cd /home/pi/catkin_ws/src/clever \ - && git checkout $2 \ - && pip install wheel \ - && pip install -r /home/pi/catkin_ws/src/clever/clever/requirements.txt \ - && cd /home/pi/catkin_ws \ - && . /opt/ros/kinetic/setup.sh \ - && catkin_make -j1 -DCMAKE_BUILD_TYPE=Release \ - && ln -s /home/pi/catkin_ws/src/clever/deploy/roscore.service /lib/systemd/system/roscore.service \ - && ln -s /home/pi/catkin_ws/src/clever/deploy/clever.service /lib/systemd/system/clever.service \ - && systemctl enable roscore \ - && systemctl enable clever - -echo -e "\033[0;31m\033[1m$(date) | #13 Change permissions for catkin_ws\033[0m\033[0m" - -chown -Rf pi:pi /home/pi/catkin_ws - -echo -e "\033[0;31m\033[1m$(date) | #14 Setup ROS environment\033[0m\033[0m" - -cat < /dev/null -LANG=C.UTF-8 -LC_ALL=C.UTF-8 -ROS_DISTRO=kinetic -export ROS_IP=192.168.11.1 -source /opt/ros/kinetic/setup.bash -source /home/pi/catkin_ws/devel/setup.bash -EOF - -#echo -e "\033[0;31m\033[1m$(date) | #14 Removing local apt mirror\033[0m\033[0m" -# Restore original sources.list -#mv /var/sources.list.bak /etc/apt/sources.list -# Clean apt cache -apt-get clean -# Remove local mirror repository key -#apt-key del COEX-MIRROR - -echo -e "\033[0;31m\033[1m$(date) | END of ROS INSTALLATION\033[0m\033[0m" diff --git a/image_builder/scripts/software_install.sh b/image_builder/scripts/software_install.sh deleted file mode 100755 index 3a4bb793..00000000 --- a/image_builder/scripts/software_install.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -set -e - -################################################################################################################################## -# Image software installation -################################################################################################################################## - -echo -e "\033[0;31m\033[1m$(date) | #1 Software installing\033[0m\033[0m" - -# TODO: Use dnsmasq instead of isc-dhcp-server -apt-get install --no-install-recommends -y \ - unzip=6.0-21 \ - zip=3.0-11 \ - ipython=5.1.0-3 \ - ipython3=5.1.0-3 \ - screen=4.5.0-6 \ - byobu=5.112-1 \ - nmap=7.40-1 \ - lsof=4.89+dfsg-0.1 \ - git=1:2.11.0-3+deb9u3 \ - dnsmasq=2.76-5+rpt1+deb9u1 \ - tmux=2.3-4 \ - vim=2:8.0.0197-4+deb9u1 \ - cmake=3.7.2-1 \ - python-pip=9.0.1-2+rpt2 \ - python3-pip=9.0.1-2+rpt2 \ - libjpeg8-dev=8d1-2 \ - tcpdump \ - libpoco-dev=1.7.6+dfsg1-5+deb9u1 - -echo -e "\033[0;31m\033[1m$(date) | #2 Adding mjpg-streamer at /home/pi\033[0m\033[0m" -# https://github.com/jacksonliam/mjpg-streamer - -git clone https://github.com/jacksonliam/mjpg-streamer.git /home/pi/mjpg-streamer \ - && cd /home/pi/mjpg-streamer/mjpg-streamer-experimental \ - && make \ - && make install \ - && chown -Rf pi:pi /home/pi/mjpg-streamer - -echo -e "\033[0;31m\033[1m$(date) | Add .vimrc\033[0m\033[0m" - -# vim settings -echo "set mouse-=a -syntax on -" > /home/pi/.vimrc - -echo -e "\033[0;31m\033[1m$(date) | End of network installation\033[0m\033[0m" diff --git a/image_builder/yadisk.py b/image_builder/yadisk.py deleted file mode 100755 index cacd1517..00000000 --- a/image_builder/yadisk.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python - -# -# Simple python uploader to YaDisk -# Smirnov Artem @urpylka -# -# Use: -# python yadisk.py login password file server_dir -# - -from YaDiskClient.YaDiskClient import YaDisk -import os.path, sys, json - -def upload(_login, _password, _server_dir, _file): - if os.path.isfile(_file): - disk = YaDisk(_login, _password) - disk.upload(_file, _server_dir + '/' + os.path.basename(_file)) - link = disk.publish_doc(_server_dir + '/' + os.path.basename(_file)) - print link - else: - print "Error: file-path is bad" - return 1 - -def main(): - if (len(sys.argv) == 5): - print "login: " + sys.argv[1] - print "password: " + sys.argv[2] - print "server_dir: " + sys.argv[3] - print "file: " + sys.argv[4] - - upload(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]) - - elif (len(sys.argv) == 3): - # print "config: " + sys.argv[1] - # print "file: " + sys.argv[2] - - if os.path.isfile(sys.argv[1]) and os.path.isfile(sys.argv[2]): - - with open(sys.argv[1]) as json_data: - d = json.load(json_data) - upload(d['yadisk']['login'], d['yadisk']['password'], d['yadisk']['server_dir'], sys.argv[2]) - - else: - print "Error: file-path or config-path is bad" - return 1 - else: - print "Error: amount of args is incorrect" - return 1 - -if __name__ == '__main__': - main()