diff --git a/Common/Ubuntu/create_swap_file.sh b/Common/Ubuntu/create_swap_file.sh new file mode 100755 index 00000000..8f74c388 --- /dev/null +++ b/Common/Ubuntu/create_swap_file.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# Copyright 2017-2019 JetsonHacks +# MIT License +# Create a swap file and set up permissions +# If a parameter is passed, it should be the place to create the swapfile +set -e +SWAPDIRECTORY="/mnt" +# Ubuntu recommends 6GB for 4GB of memory when using suspend +# You can use 1 or 2 if need be +SWAPSIZE=6 +AUTOMOUNT="Y" +function usage +{ + echo "usage: installSwapFile [[[-d directory ] [-s size] -a] | [-h]]" + echo " -d | --dir Directory to place swapfile ( default: /mnt)" + echo " -s | --size (default: 6)" + echo " -a | --auto Enable swap on boot in /etc/fstab (default: Y)" + echo " -h | --help This message" +} + +while [ "$1" != "" ]; do + case $1 in + -d | --dir ) shift + SWAPDIRECTORY=$1 + ;; + -s | --size ) shift + SWAPSIZE=$1 + ;; + -a | --auto ) shift + AUTOMOUNT=$1 + ;; + -h | --help ) usage + exit + ;; + * ) usage + exit 1 + esac + shift +done + +echo "Creating Swapfile at: " $SWAPDIRECTORY +echo "Swapfile Size: " $SWAPSIZE"G" +echo "Automount: " $AUTOMOUNT + +#Create a swapfile for Ubuntu at the current directory location +sudo fallocate -l $SWAPSIZE"G" $SWAPDIRECTORY"/swapfile" +cd $SWAPDIRECTORY +#List out the file +ls -lh swapfile +# Change permissions so that only root can use it +sudo chmod 600 swapfile +#List out the file +ls -lh swapfile +#Set up the Linux swap area +sudo mkswap swapfile +#Now start using the swapfile +sudo swapon swapfile +#Show that it's now being used +swapon -s + +if [ "$AUTOMOUNT" = "Y" ]; then + echo "Modifying /etc/fstab to enable on boot" + SWAPLOCATION=$SWAPDIRECTORY"/swapfile" + echo $SWAPLOCATION + sudo sh -c 'echo "'$SWAPLOCATION' swap swap defaults 0 0" >> /etc/fstab' +fi + +echo "Swap file has been created" +echo "Reboot to make sure changes are in effect" diff --git a/Common/Ubuntu/install_packages.sh b/Common/Ubuntu/install_packages.sh index 1c95b449..027060be 100755 --- a/Common/Ubuntu/install_packages.sh +++ b/Common/Ubuntu/install_packages.sh @@ -21,8 +21,8 @@ apt-get dist-upgrade -y apt-get -y install python-dev python-numpy python3-numpy python-pip python-opencv # pymavlink deps: -apt-get install -y libxml2-dev libxslt1.1 libxslt1-dev libz-dev -time pip install future lxml +apt-get install -y libxml2-dev libxslt1.1 libxslt1-dev libz-dev python-lxml +time pip install future # install dronekit pip install dronekit dronekit-sitl # also installs pymavlink diff --git a/Common/Ubuntu/librealsense/buildLibrealsense.sh b/Common/Ubuntu/librealsense/buildLibrealsense.sh new file mode 100755 index 00000000..51cf03e9 --- /dev/null +++ b/Common/Ubuntu/librealsense/buildLibrealsense.sh @@ -0,0 +1,146 @@ +#!/bin/bash +# Builds the Intel Realsense library librealsense on a Jetson Nano Development Kit +# Copyright (c) 2016-19 Jetsonhacks +# MIT License + +# Jetson Nano; L4T 32.2.3 + +LIBREALSENSE_DIRECTORY=${HOME}/GitHub/librealsense +LIBREALSENSE_VERSION=v2.33.1 +INSTALL_DIR=$PWD +NVCC_PATH=/usr/local/cuda-10.0/bin/nvcc + +USE_CUDA=false +s +function usage +{ + echo "usage: ./buildLibrealsense.sh [[-c ] | [-h]]" + echo "-nc | --build_with_cuda Build no CUDA (Defaults to with CUDA)" + echo "-h | --help This message" +} + +# Iterate through command line inputs +while [ "$1" != "" ]; do + case $1 in + -nc | --build_no_cuda ) USE_CUDA=false + ;; + -h | --help ) usage + exit + ;; + * ) usage + exit 1 + esac + shift +done + +echo "Build with CUDA: "$USE_CUDA + +red=`tput setaf 1` +green=`tput setaf 2` +reset=`tput sgr0` +# e.g. echo "${red}The red tail hawk ${green}loves the green grass${reset}" + + +echo "" +echo "Please make sure that no RealSense cameras are currently attached" +echo "" +read -n 1 -s -r -p "Press any key to continue" +echo "" + +if [ ! -d "$LIBREALSENSE_DIRECTORY" ] ; then + # clone librealsense + cd ${HOME} + echo "${green}Cloning librealsense${reset}" + git clone https://github.com/IntelRealSense/librealsense.git +fi + +# Is the version of librealsense current enough? +cd $LIBREALSENSE_DIRECTORY +VERSION_TAG=$(git tag -l $LIBREALSENSE_VERSION) +if [ ! $VERSION_TAG ] ; then + echo "" + tput setaf 1 + echo "==== librealsense Version Mismatch! =============" + tput sgr0 + echo "" + echo "The installed version of librealsense is not current enough for these scripts." + echo "This script needs librealsense tag version: "$LIBREALSENSE_VERSION "but it is not available." + echo "Please upgrade librealsense or remove the librealsense folder before attempting to install again." + echo "" + exit 1 +fi + +# Checkout version the last tested version of librealsense +git checkout $LIBREALSENSE_VERSION + +# Install the dependencies +cd $INSTALL_DIR +sudo ./scripts/installDependencies.sh + +cd $LIBREALSENSE_DIRECTORY +git checkout $LIBREALSENSE_VERSION + +# Now compile librealsense and install +mkdir build +cd build +# Build examples, including graphical ones +echo "${green}Configuring Make system${reset}" +# Build with CUDA (default), the CUDA flag is USE_CUDA, ie -DUSE_CUDA=true +export CUDACXX=$NVCC_PATH +export PATH=${PATH}:/usr/local/cuda/bin +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/cuda/lib64 + +/usr/bin/cmake ../ -DBUILD_EXAMPLES=true -DFORCE_LIBUVC=true -DBUILD_WITH_CUDA="$USE_CUDA" -DCMAKE_BUILD_TYPE=release -DBUILD_PYTHON_BINDINGS=bool:true -DBUILD_WITH_TM2=ON + +# The library will be installed in /usr/local/lib, header files in /usr/local/include +# The demos, tutorials and tests will located in /usr/local/bin. +echo "${green}Building librealsense, headers, tools and demos${reset}" + +NUM_CPU=$(nproc) +time make -j$(($NUM_CPU - 1)) +if [ $? -eq 0 ] ; then + echo "librealsense make successful" +else + # Try to make again; Sometimes there are issues with the build + # because of lack of resources or concurrency issues + echo "librealsense did not build " >&2 + echo "Retrying ... " + # Single thread this time + time make + if [ $? -eq 0 ] ; then + echo "librealsense make successful" + else + # Try to make again + echo "librealsense did not successfully build" >&2 + echo "Please fix issues and retry build" + exit 1 + fi +fi +echo "${green}Installing librealsense, headers, tools and demos${reset}" +sudo make install + +if grep -Fxq 'export PYTHONPATH=$PYTHONPATH:/usr/local/lib' ~/.bashrc ; then + echo "PYTHONPATH already exists in .bashrc file" +else + echo 'export PYTHONPATH=$PYTHONPATH:/usr/local/lib' >> ~/.bashrc + echo "PYTHONPATH added to ~/.bashrc. Pyhon wrapper is now available for importing pyrealsense2" +fi + +cd $LIBREALSENSE_DIRECTORY +echo "${green}Applying udev rules${reset}" +# Copy over the udev rules so that camera can be run from user space +sudo cp config/99-realsense-libusb.rules /etc/udev/rules.d/ +sudo udevadm control --reload-rules && udevadm trigger + +echo "${green}Library Installed${reset}" +echo " " +echo " -----------------------------------------" +echo "The library is installed in /usr/local/lib" +echo "The header files are in /usr/local/include" +echo "The demos and tools are located in /usr/local/bin" +echo " " +echo " -----------------------------------------" +echo " " + + + diff --git a/Common/Ubuntu/librealsense/install_vision_to_mavros.sh b/Common/Ubuntu/librealsense/install_vision_to_mavros.sh new file mode 100755 index 00000000..7b1c05e3 --- /dev/null +++ b/Common/Ubuntu/librealsense/install_vision_to_mavros.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -e +set -x + +tput setaf 3 +echo "Build latest version of librealsense" +tput sgr0 + +time ./buildLibrealsense.sh + +pushd /home/$NORMAL_USER/GitHub +sudo apt install python3-lxml +sudo -H pip3 install cython +sudo -H pip3 install numpy --upgrade +sudo -H pip3 install transformations +sudo -H pip3 install apscheduler +sudo -H pip3 install dronekit + +git clone https://github.com/thien94/vision_to_mavros.git + +mkdir /home/$NORMAL_USER/start_t265_to_mavlink +pushd vision_to_mavros/scripts +cp t265_to_mavlink.py /home/$NORMAL_USER/start_t265_to_mavlink +popd +popd +cp start_t265.sh /home/$NORMAL_USER/start_t265_to_mavlink +sudo cp t265.service /etc/systemd/system + +tput setaf 2 +echo "Finished installing vision_to_mavros" +tput sgr0 + diff --git a/Common/Ubuntu/librealsense/scripts/installDependencies.sh b/Common/Ubuntu/librealsense/scripts/installDependencies.sh new file mode 100755 index 00000000..69938790 --- /dev/null +++ b/Common/Ubuntu/librealsense/scripts/installDependencies.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# installDependencies.sh +# Install dependencies for the Intel Realsense library librealsense2 on a Jetson Nano Developer Kit +# Copyright (c) 2016-19 Jetsonhacks +# MIT License +red=`tput setaf 1` +green=`tput setaf 2` +reset=`tput sgr0` +# e.g. echo "${red}red text ${green}green text${reset}" +echo "${green}Adding Universe repository and updating${reset}" +apt-add-repository universe +apt update +echo "${green}Adding dependencies, graphics libraries and tools${reset}" +apt install libssl-dev libusb-1.0-0-dev pkg-config -y +# This is for ccmake +apt install build-essential cmake cmake-curses-gui -y + +# Graphics libraries - for SDK's OpenGL-enabled examples +apt install libgtk-3-dev libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev -y + +# QtCreator for development; not required for librealsense core library +apt install qtcreator -y + +# Add Python 3 support +apt install -y python3 python3-dev + diff --git a/Common/Ubuntu/librealsense/start_t265.sh b/Common/Ubuntu/librealsense/start_t265.sh new file mode 100755 index 00000000..c34ca195 --- /dev/null +++ b/Common/Ubuntu/librealsense/start_t265.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# This is /usr/bin/your_config-start.sh +# # do all your commands here... script terminates when all is done. + +# Change the path to t265_to_mavlink.py +/home/apsync/start_t265_to_mavlink/t265_to_mavlink.py --connect udp:127.0.0.1:14560 diff --git a/Common/Ubuntu/librealsense/t265.service b/Common/Ubuntu/librealsense/t265.service new file mode 100644 index 00000000..51adefc5 --- /dev/null +++ b/Common/Ubuntu/librealsense/t265.service @@ -0,0 +1,17 @@ +[Unit] +Description=Realsense T265 Service +After==multi-user.target +StartLimitIntervalSec=0 +Conflicts= + +[Service] +User=apsync +EnvironmentFile= +ExecStartPre= +ExecStart=/home/apsync/start_t265_to_mavlink/start_t265.sh + +Restart=on-failure +RestartSec=1 + +[Install] +WantedBy=multi-user.target diff --git a/Common/Ubuntu/librealsense/t265_to_mavlink.py b/Common/Ubuntu/librealsense/t265_to_mavlink.py new file mode 100755 index 00000000..040176f5 --- /dev/null +++ b/Common/Ubuntu/librealsense/t265_to_mavlink.py @@ -0,0 +1,431 @@ +#!/usr/bin/env python3 + +##################################################### +## librealsense T265 to MAVLink ## +##################################################### +# This script assumes pyrealsense2.[].so file is found under the same directory as this script +# Install required packages: +# pip install pyrealsense2 +# pip install transformations +# pip3 install dronekit +# pip3 install apscheduler + + # Set the path for IDLE +import sys +sys.path.append("/usr/local/lib/") + +# Set MAVLink protocol to 2. +import os +os.environ["MAVLINK20"] = "1" + +# Import the libraries +import pyrealsense2 as rs +import numpy as np +import transformations as tf +import math as m +import time +import argparse +import threading +from apscheduler.schedulers.background import BackgroundScheduler + +from dronekit import connect, VehicleMode +from pymavlink import mavutil + +####################################### +# Parameters +####################################### + +# Default configurations for connection to the FCU +connection_string_default = 'udp:127.0.0.1:14560' +connection_baudrate_default = 921600 +vision_msg_hz_default = 30 +confidence_msg_hz_default = 1 +camera_orientation_default = 0 + +# In NED frame, offset from the IMU or the center of gravity to the camera's origin point +body_offset_enabled = 0 +body_offset_x = 0.05 # In meters (m), so 0.05 = 5cm +body_offset_y = 0 # In meters (m) +body_offset_z = 0 # In meters (m) + +# Global scale factor, position x y z will be scaled up/down by this factor +scale_factor = 1.0 + +# Enable using yaw from compass to align north (zero degree is facing north) +compass_enabled = 0 + +# Default global position of home/ origin +home_lat = 151269321 # Somewhere in Africa +home_lon = 16624301 # Somewhere in Africa +home_alt = 163000 + +vehicle = None +pipe = None + +# pose data confidence: 0x0 - Failed / 0x1 - Low / 0x2 - Medium / 0x3 - High +pose_data_confidence_level = ('Failed', 'Low', 'Medium', 'High') + +####################################### +# Parsing user' inputs +####################################### + +parser = argparse.ArgumentParser(description='Reboots vehicle') +parser.add_argument('--connect', + help="Vehicle connection target string. If not specified, a default string will be used.") +parser.add_argument('--baudrate', type=float, + help="Vehicle connection baudrate. If not specified, a default value will be used.") +parser.add_argument('--vision_msg_hz', type=float, + help="Update frequency for VISION_POSITION_ESTIMATE message. If not specified, a default value will be used.") +parser.add_argument('--confidence_msg_hz', type=float, + help="Update frequency for confidence level. If not specified, a default value will be used.") +parser.add_argument('--scale_calib_enable', type=bool, + help="Scale calibration. Only run while NOT in flight") +parser.add_argument('--camera_orientation', type=int, + help="Configuration for camera orientation. Currently supported: forward, usb port to the right - 0; downward, usb port to the right - 1") +parser.add_argument('--debug_enable',type=int, + help="Enable debug messages on terminal") + + +args = parser.parse_args() + +connection_string = args.connect +connection_baudrate = args.baudrate +vision_msg_hz = args.vision_msg_hz +confidence_msg_hz = args.confidence_msg_hz +scale_calib_enable = args.scale_calib_enable +camera_orientation = args.camera_orientation +debug_enable = args.debug_enable + +# Using default values if no specified inputs +if not connection_string: + connection_string = connection_string_default + print("INFO: Using default connection_string", connection_string) +else: + print("INFO: Using connection_string", connection_string) + +if not connection_baudrate: + connection_baudrate = connection_baudrate_default + print("INFO: Using default connection_baudrate", connection_baudrate) +else: + print("INFO: Using connection_baudrate", connection_baudrate) + +if not vision_msg_hz: + vision_msg_hz = vision_msg_hz_default + print("INFO: Using default vision_msg_hz", vision_msg_hz) +else: + print("INFO: Using vision_msg_hz", vision_msg_hz) + +if not confidence_msg_hz: + confidence_msg_hz = confidence_msg_hz_default + print("INFO: Using default confidence_msg_hz", confidence_msg_hz) +else: + print("INFO: Using confidence_msg_hz", confidence_msg_hz) + +if body_offset_enabled == 1: + print("INFO: Using camera position offset: Enabled, x y z is", body_offset_x, body_offset_y, body_offset_z) +else: + print("INFO: Using camera position offset: Disabled") + +if compass_enabled == 1: + print("INFO: Using compass: Enabled. Heading will be aligned to north.") +else: + print("INFO: Using compass: Disabled") + +if scale_calib_enable == True: + print("\nINFO: SCALE CALIBRATION PROCESS. DO NOT RUN DURING FLIGHT.\nINFO: TYPE IN NEW SCALE IN FLOATING POINT FORMAT\n") +else: + if scale_factor == 1.0: + print("INFO: Using default scale factor", scale_factor) + else: + print("INFO: Using scale factor", scale_factor) + +if not camera_orientation: + camera_orientation = camera_orientation_default + print("INFO: Using default camera orientation", camera_orientation) +else: + print("INFO: Using camera orientation", camera_orientation) + +# Transformation to convert different camera orientations to NED convention. Replace camera_orientation_default for your configuration. +# 0: Forward, USB port to the right +# 1: Downfacing, USB port to the right +# Important note for downfacing camera: you need to tilt the vehicle's nose up a little - not flat - before you run the script, otherwise the initial yaw will be randomized, read here for more details: https://github.com/IntelRealSense/librealsense/issues/4080. Tilt the vehicle to any other sides and the yaw might not be as stable. + +if camera_orientation == 0: + # Forward, USB port to the right + H_aeroRef_T265Ref = np.array([[0,0,-1,0],[1,0,0,0],[0,-1,0,0],[0,0,0,1]]) + H_T265body_aeroBody = np.linalg.inv(H_aeroRef_T265Ref) +elif camera_orientation == 1: + # Downfacing, USB port to the right + H_aeroRef_T265Ref = np.array([[0,0,-1,0],[1,0,0,0],[0,-1,0,0],[0,0,0,1]]) + H_T265body_aeroBody = np.array([[0,1,0,0],[1,0,0,0],[0,0,-1,0],[0,0,0,1]]) +else: + # Default is facing forward, USB port to the right + H_aeroRef_T265Ref = np.array([[0,0,-1,0],[1,0,0,0],[0,-1,0,0],[0,0,0,1]]) + H_T265body_aeroBody = np.linalg.inv(H_aeroRef_T265Ref) + + +if not debug_enable: + debug_enable = 0 +else: + debug_enable = 1 + np.set_printoptions(precision=4, suppress=True) # Format output on terminal + print("INFO: Debug messages enabled.") + +####################################### +# Functions +####################################### + +# https://mavlink.io/en/messages/common.html#VISION_POSITION_ESTIMATE +def send_vision_position_message(): + global current_time, H_aeroRef_aeroBody + + if H_aeroRef_aeroBody is not None: + rpy_rad = np.array( tf.euler_from_matrix(H_aeroRef_aeroBody, 'sxyz')) + + msg = vehicle.message_factory.vision_position_estimate_encode( + current_time, # us Timestamp (UNIX time or time since system boot) + H_aeroRef_aeroBody[0][3], # Global X position + H_aeroRef_aeroBody[1][3], # Global Y position + H_aeroRef_aeroBody[2][3], # Global Z position + rpy_rad[0], # Roll angle + rpy_rad[1], # Pitch angle + rpy_rad[2] # Yaw angle + ) + + vehicle.send_mavlink(msg) + vehicle.flush() + +# For a lack of a dedicated message, we pack the confidence level into a message that will not be used, so we can view it on GCS +# Confidence level value: 0 - 3, remapped to 0 - 100: 0% - Failed / 33.3% - Low / 66.6% - Medium / 100% - High +def send_confidence_level_dummy_message(): + global data, current_confidence + if data is not None: + # Show confidence level on terminal + print("INFO: Tracking confidence: ", pose_data_confidence_level[data.tracker_confidence]) + + # Send MAVLink message to show confidence level numerically + msg = vehicle.message_factory.vision_position_delta_encode( + 0, #us Timestamp (UNIX time or time since system boot) + 0, #Time since last reported camera frame + [0, 0, 0], #angle_delta + [0, 0, 0], #position_delta + float(data.tracker_confidence * 100 / 3) + ) + vehicle.send_mavlink(msg) + vehicle.flush() + + # If confidence level changes, send MAVLink message to show confidence level textually and phonetically + if current_confidence is None or current_confidence != data.tracker_confidence: + current_confidence = data.tracker_confidence + confidence_status_string = 'Tracking confidence: ' + pose_data_confidence_level[data.tracker_confidence] + status_msg = vehicle.message_factory.statustext_encode( + 3, #severity, defined here: https://mavlink.io/en/messages/common.html#MAV_SEVERITY, 3 will let the message be displayed on Mission Planner HUD + confidence_status_string.encode() #text char[50] + ) + vehicle.send_mavlink(status_msg) + vehicle.flush() + + +# Send a mavlink SET_GPS_GLOBAL_ORIGIN message (http://mavlink.org/messages/common#SET_GPS_GLOBAL_ORIGIN), which allows us to use local position information without a GPS. +def set_default_global_origin(): + msg = vehicle.message_factory.set_gps_global_origin_encode( + int(vehicle._master.source_system), + home_lat, + home_lon, + home_alt + ) + + vehicle.send_mavlink(msg) + vehicle.flush() + +# Send a mavlink SET_HOME_POSITION message (http://mavlink.org/messages/common#SET_HOME_POSITION), which allows us to use local position information without a GPS. +def set_default_home_position(): + x = 0 + y = 0 + z = 0 + q = [1, 0, 0, 0] # w x y z + + approach_x = 0 + approach_y = 0 + approach_z = 1 + + msg = vehicle.message_factory.set_home_position_encode( + int(vehicle._master.source_system), + home_lat, + home_lon, + home_alt, + x, + y, + z, + q, + approach_x, + approach_y, + approach_z + ) + + vehicle.send_mavlink(msg) + vehicle.flush() + +# Request a timesync update from the flight controller, for future work. +# TODO: Inspect the usage of timesync_update +def update_timesync(ts=0, tc=0): + if ts == 0: + ts = int(round(time.time() * 1000)) + msg = vehicle.message_factory.timesync_encode( + tc, # tc1 + ts # ts1 + ) + vehicle.send_mavlink(msg) + vehicle.flush() + +# Listen to messages that indicate EKF is ready to set home, then set EKF home automatically. +def statustext_callback(self, attr_name, value): + # These are the status texts that indicates EKF is ready to receive home position + if value.text == "GPS Glitch" or value.text == "GPS Glitch cleared" or value.text == "EKF2 IMU1 ext nav yaw alignment complete": + time.sleep(0.1) + print("INFO: Set EKF home with default GPS location") + set_default_global_origin() + set_default_home_position() + +# Listen to attitude data to acquire heading when compass data is enabled +def att_msg_callback(self, attr_name, value): + global heading_north_yaw + if heading_north_yaw is None: + heading_north_yaw = value.yaw + print("INFO: Received first ATTITUDE message with heading yaw", heading_north_yaw * 180 / m.pi, "degrees") + else: + heading_north_yaw = value.yaw + print("INFO: Received ATTITUDE message with heading yaw", heading_north_yaw * 180 / m.pi, "degrees") + +def vehicle_connect(): + global vehicle + + try: + vehicle = connect(connection_string, wait_ready = True, baud = connection_baudrate, source_system = 1) + except: + print('Connection error! Retrying...') + + if vehicle == None: + return False + else: + return True + +def realsense_connect(): + global pipe + # Declare RealSense pipeline, encapsulating the actual device and sensors + pipe = rs.pipeline() + + # Build config object before requesting data + cfg = rs.config() + + # Enable the stream we are interested in + cfg.enable_stream(rs.stream.pose) # Positional data + + # Start streaming with requested config + pipe.start(cfg) + +# Monitor user input from the terminal and update scale factor accordingly +def scale_update(): + global scale_factor + while True: + scale_factor = float(input("INFO: Type in new scale as float number\n")) + print("INFO: New scale is ", scale_factor) + +####################################### +# Main code starts here +####################################### + +print("INFO: Connecting to Realsense camera.") +realsense_connect() +print("INFO: Realsense connected.") + +print("INFO: Connecting to vehicle.") +while (not vehicle_connect()): + pass +print("INFO: Vehicle connected.") + +# Listen to the mavlink messages that will be used as trigger to set EKF home automatically +vehicle.add_message_listener('STATUSTEXT', statustext_callback) + +if compass_enabled == 1: + # Listen to the attitude data in aeronautical frame + vehicle.add_message_listener('ATTITUDE', att_msg_callback) + +data = None +current_confidence = None +H_aeroRef_aeroBody = None +heading_north_yaw = None + +# Send MAVlink messages in the background +sched = BackgroundScheduler() + +sched.add_job(send_vision_position_message, 'interval', seconds = 1/vision_msg_hz) +sched.add_job(send_confidence_level_dummy_message, 'interval', seconds = 1/confidence_msg_hz) + +# For scale calibration, we will use a thread to monitor user input +if scale_calib_enable == True: + scale_update_thread = threading.Thread(target=scale_update) + scale_update_thread.daemon = True + scale_update_thread.start() + +sched.start() + +if compass_enabled == 1: + # Wait a short while for yaw to be correctly initiated + time.sleep(1) + +print("INFO: Sending VISION_POSITION_ESTIMATE messages to FCU.") + +try: + while True: + # Wait for the next set of frames from the camera + frames = pipe.wait_for_frames() + + # Fetch pose frame + pose = frames.get_pose_frame() + + if pose: + # Store the timestamp for MAVLink messages + current_time = int(round(time.time() * 1000000)) + + # Pose data consists of translation and rotation + data = pose.get_pose_data() + + # In transformations, Quaternions w+ix+jy+kz are represented as [w, x, y, z]! + H_T265Ref_T265body = tf.quaternion_matrix([data.rotation.w, data.rotation.x, data.rotation.y, data.rotation.z]) + H_T265Ref_T265body[0][3] = data.translation.x * scale_factor + H_T265Ref_T265body[1][3] = data.translation.y * scale_factor + H_T265Ref_T265body[2][3] = data.translation.z * scale_factor + + # Transform to aeronautic coordinates (body AND reference frame!) + H_aeroRef_aeroBody = H_aeroRef_T265Ref.dot( H_T265Ref_T265body.dot( H_T265body_aeroBody)) + + # Take offsets from body's center of gravity (or IMU) to camera's origin into account + if body_offset_enabled == 1: + H_body_camera = tf.euler_matrix(0, 0, 0, 'sxyz') + H_body_camera[0][3] = body_offset_x + H_body_camera[1][3] = body_offset_y + H_body_camera[2][3] = body_offset_z + H_camera_body = np.linalg.inv(H_body_camera) + H_aeroRef_aeroBody = H_body_camera.dot(H_aeroRef_aeroBody.dot(H_camera_body)) + + # Realign heading to face north using initial compass data + if compass_enabled == 1: + H_aeroRef_aeroBody = H_aeroRef_aeroBody.dot( tf.euler_matrix(0, 0, heading_north_yaw, 'sxyz')) + + # Show debug messages here + if debug_enable == 1: + os.system('clear') # This helps in displaying the messages to be more readable + print("DEBUG: Raw RPY[deg]: {}".format( np.array( tf.euler_from_matrix( H_T265Ref_T265body, 'sxyz')) * 180 / m.pi)) + print("DEBUG: NED RPY[deg]: {}".format( np.array( tf.euler_from_matrix( H_aeroRef_aeroBody, 'sxyz')) * 180 / m.pi)) + print("DEBUG: Raw pos xyz : {}".format( np.array( [data.translation.x, data.translation.y, data.translation.z]))) + print("DEBUG: NED pos xyz : {}".format( np.array( tf.translation_from_matrix( H_aeroRef_aeroBody)))) + +except KeyboardInterrupt: + print("INFO: KeyboardInterrupt has been caught. Cleaning up...") + +finally: + pipe.stop() + vehicle.close() + print("INFO: Realsense pipeline and vehicle object closed.") + sys.exit() diff --git a/RPI2/Ubuntu/1_create_base_image.md b/RPI2/Ubuntu/1_create_base_image.md new file mode 100644 index 00000000..a1628f09 --- /dev/null +++ b/RPI2/Ubuntu/1_create_base_image.md @@ -0,0 +1,170 @@ +# RPi Ubuntu setup script for use as companion computer. + +These instructions are for the official Ubuntu LTS images. + +Download Ubuntu LTS image at this time 18.04 is the recomended image, for RPi3 and RPi4 use the 64bit Image +Even though the RPi3 has only a marginal difference between using 32bit vs 64bit, using the 64bit image provides +Common ground between our images. + +https://ubuntu.com/download/raspberry-pi + +Flash image onto SD card using Balena Etcher which can be downloaded from +https://www.balena.io/etcher/ + +NOTE: make sure you use at least a 16GB card, preferabbly use a 128GB card to allow enough space to install all software. + +Boot Raspberry Pi and follow the instructions for changing the password for the default user (User: ubuntu, Password: ubuntu) + +Setup is easier if you can ssh into the vehicle from an existing +desktop environment. Use the ethernet connection for this. + +Once you log in for the first time you can find out the ip-address of the RPi by typing this command on the console (look for the number next to inet): +```console +ubuntu@ubuntu:~$ ifconfig +eth0: flags=4163 mtu 1500 + inet 10.0.0.87 netmask 255.255.255.0 broadcast 10.0.0.255 + inet6 2601:af5:8200:caf0::b6c3 prefixlen 128 scopeid 0x0 + inet6 fe80::def6:aeff:fe4d:980f prefixlen 64 scopeid 0x20 + inet6 2601:2ae:8200:ca60:ffa6:aeff:fe4d:980f prefixlen 64 scopeid 0x0 + ether dc:a6:32:4d:98:0f txqueuelen 1000 (Ethernet) + RX packets 384106 bytes 524816389 (524.8 MB) + RX errors 56 dropped 56 overruns 0 frame 0 + TX packets 47745 bytes 5827337 (5.8 MB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + +lo: flags=73 mtu 65536 + inet 127.0.0.1 netmask 255.0.0.0 + inet6 ::1 prefixlen 128 scopeid 0x10 + loop txqueuelen 1000 (Local Loopback) + RX packets 234558 bytes 12730563 (12.7 MB) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 234558 bytes 12730563 (12.7 MB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + +``` + +with that ip-address you can now ssh into the RaspberryPi +From the host machine: +```console +ssh ubuntu@ip-address +``` + +Once you log in, clone this repository +```console +cd +mkdir GitHub +pushd GitHub +git clone https://github.com/ardupilot/companion +pushd companion/RPI2/Ubuntu +``` + +Update the package manager and upgrade everything to the latest versions +```console +sudo apt update +sudo apt upgrade -y +``` + +Install some basic packages and create a user named apsync +```console +sudo apt install nano rsync +sudo useradd -s /bin/bash -m -U -G sudo,netdev,users,dialout,video apsync +echo "apsync:apsync" | chpasswd +``` + +Move all files to the apsync user folder +```console +sudo rsync -aPH --delete /home/ubuntu/ /home/apsync +sudo chown -R apsync.apsync /home/apsync +sudo rm -rf * +``` + +You have finished the first part, now you will need to logout and log back in using the apsync user +If desired at this point you can copy your ssh keys to the RPi so that you dont need to enter the password everytime. + +To copy the SSH keys you need to have generated an RSA id on your host machine. Once you have an rsa_id you can copy the keys to the RPi +on the host machine: +```console +ssh-copy-id apsync@ip-address-of-rpi +``` + +ssh into the RPi with the new user apsync +```console +ssh apsync@ip-address-of-rpi +``` + +Now go back to the companion repo folder and continue installing required software +```console +pushd /home/apsync/GitHub/companion/RPI2/Ubuntu +sudo ./set-hostname #set the hostname to apsync +sudo apt autoremove -y # avoid repeated no-longer-required annoyance +sudo ./remove-unattended-upgrades +sudo ./ensure_rc_local.sh +sudo ./disable_console.sh +sudo reboot #reboot for the changes to take effect +``` + +ssh back into the RPi and continue with the following: +```console +pushd /home/apsync/GitHub/companion/RPI2/Ubuntu +sudo -E ./2_install_packages.sh # 20m +sudo -E ./install_niceties || echo "Failed" # 20s +sudo -E ./3_wifi_access_point.sh # 20s +sudo reboot #reboot for the changes to take effect +``` + +Check to see if you can see a WiFi Network named `ardupilot` + +ssh back into the RPi and continue with these command: +```console +pushd /home/apsync/GitHub/companion/RPI2/Ubuntu +sudo ./apstreamline.sh # 1m This is optional +sudo ./setup_master_mavlink-router.sh +sudo ./7_dflogger.sh # ~210s +sudo apt install -y libxml2-dev libxslt1.1 libxslt1-dev python-lxml +sudo -H pip install future # 4m +sudo ./install_pymavlink # new version required for apweb #1m + +pushd /home/apsync/GitHub/pymavlink +git config --global user.email "devel@ardupilot.org" +git config --global user.name "ArduPilotCompanion" + +git stash +git revert e1532c3fc306d83d03adf82fb559f1bb50860c03 +export MDEF=~/GitHub/mavlink/message_definitions +python setup.py build install --user --force +popd + +sudo ./install_apweb # 2m +``` + +At this point you have finished installing the necesary packages for the basic APSync image + +# Automated Scripts +For convenience we have created 4 scripts that automate all the steps above. In order to use those you can do the following after loging into the cosole for the first time: + +```console +mkdir GitHub +pushd GitHub +git clone https://github.com/ardupilot/companion +pushd companion/RPI2/Ubuntu/automated +sudo ./1_Setup_user_and_update.sh +``` +After the first script logout and log back in using the apsync user, then run the following: +```console +pushd companion/RPI2/Ubuntu/automated +sudo ./2_Clone_Repo_Disable_console_sethost.sh +``` +After this the RPi will automatically reboot, log back in and continue with +```console +pushd companion/RPI2/Ubuntu/automated +sudo ./3_Setup_Network_and_Packages.sh +sudo ./4_setup_apsync_components.sh +``` +After completing step 4, the RPI will reboot to enable the swap file. By default this creates a 6GB swap file so make sure you have enough space on the SD Card, if you dont have enough space you can modify the script to create a smaller file. Once it reboots log back in and run +```console +sudo ./5_setup_realsense.sh +``` +**(Warning, compiling the Intel Realsense Drivers on the RPi3 takes around 20hrs and requires a large swap file)** + +This completes the installation of AP Sync you are now ready to prepare the image for cloning. + diff --git a/RPI2/Ubuntu/2_install_packages.sh b/RPI2/Ubuntu/2_install_packages.sh new file mode 100755 index 00000000..c1c7910a --- /dev/null +++ b/RPI2/Ubuntu/2_install_packages.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +tput setaf 3 +echo "Installing Packages" +tput sgr0 + +apt remove modemmanager + +apt install avahi-daemon -y +# install packages common to all +../../Common/Ubuntu/install_packages.sh diff --git a/RPI2/Ubuntu/3_wifi_access_point.sh b/RPI2/Ubuntu/3_wifi_access_point.sh new file mode 100755 index 00000000..eb12db7b --- /dev/null +++ b/RPI2/Ubuntu/3_wifi_access_point.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +tput setaf 3 +echo "Setting up access point using wifi-ap snap" +tput sgr0 + +# time snap install network-manager +time snap install wifi-ap +sleep 5 +wifi-ap.config set wifi.ssid=ArduPilot +wifi-ap.config set wifi.security-passphrase=ardupilot +wifi-ap.config set wifi.address=10.0.1.128 +wifi-ap.config set dhcp.range-start=10.0.1.129 +wifi-ap.config set dhcp.range-stop=10.0.1.138 + diff --git a/RPI2/Ubuntu/7_dflogger.sh b/RPI2/Ubuntu/7_dflogger.sh new file mode 100755 index 00000000..4d93a936 --- /dev/null +++ b/RPI2/Ubuntu/7_dflogger.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +pushd ../../Common/Ubuntu/dflogger/ + ./install_dflogger +popd diff --git a/RPI2/Ubuntu/apstreamline.sh b/RPI2/Ubuntu/apstreamline.sh new file mode 100755 index 00000000..c42d8c73 --- /dev/null +++ b/RPI2/Ubuntu/apstreamline.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +tput setaf 3 +echo "Installing AP Streamline" +tput sgr0 + +apt install python3 python3-pip meson ninja-build libgstreamer-plugins-base1.0* libgstreamer1.0-dev libgstrtspserver-1.0-dev gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly -y + +sudo -u $NORMAL_USER -H bash </dev/null + +pushd /home/$NORMAL_USER/GitHub +rm -rf APStreamline + +[ -d apstreamline ] || { + git clone https://github.com/shortstheory/adaptive-streaming.git APStreamline +} + +pushd /home/$NORMAL_USER/GitHub/APStreamline + git checkout master + meson build + pushd build + meson configure -Dprefix=$HOME/start_apstreamline/ + ninja install + sudo cp $HOME/start_apstreamline/bin/stream_server /bin/stream_server + popd +popd +EOF + +tput setaf 2 +echo "Succesful install of AP Streamline" +tput sgr0 diff --git a/RPI2/Ubuntu/automated/1_Setup_user_and_update.sh b/RPI2/Ubuntu/automated/1_Setup_user_and_update.sh new file mode 100755 index 00000000..d90f9f73 --- /dev/null +++ b/RPI2/Ubuntu/automated/1_Setup_user_and_update.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +#Update and upgrade all packages to the latest versions +apt update +apt upgrade -y + +apt install nano rsync +# create an apsync user: +useradd -s /bin/bash -m -U -G sudo,netdev,users,dialout,video $NORMAL_USER + +tput setaf 3 +echo "Setting password for AP user" +tput sgr0 + +echo "$NORMAL_USER:$NORMAL_USER" | chpasswd + +pushd /home/$STD_USER +rsync -aPH --delete /home/$STD_USER/ /home/$NORMAL_USER +chown -R $NORMAL_USER.$NORMAL_USER /home/$NORMAL_USER +rm -rf * + +tput setaf 2 +echo >&2 "Finished part 1 of APSync install, please logout and then log back in using apsync user, password apsync" +tput sgr0 diff --git a/RPI2/Ubuntu/automated/2_Clone_Repo_Disable_console_sethost.sh b/RPI2/Ubuntu/automated/2_Clone_Repo_Disable_console_sethost.sh new file mode 100755 index 00000000..3ff37eb9 --- /dev/null +++ b/RPI2/Ubuntu/automated/2_Clone_Repo_Disable_console_sethost.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +tput setaf 3 +echo "Cloning Companion Repo" +tput sgr0 + +pushd /home/$NORMAL_USER + +pushd /home/$NORMAL_USER/GitHub/companion/RPI2/Ubuntu + +tput setaf 3 +echo "Running Scripts" +tput sgr0 + +tput setaf 3 +echo "Setting Hostname to apsync" +tput sgr0 +./set-hostname # reset the machine's hostname + +tput setaf 3 +echo "Removing unused packages" +tput sgr0 +apt autoremove -y # avoid repeated no-longer-required annoyance +./remove-unattended-upgrades + +tput setaf 3 +echo "Setting up rc.local" +tput sgr0 +./ensure_rc_local.sh + +tput setaf 3 +echo "Disabling TTY console on serial port" +tput sgr0 +./disable_console.sh + +tput setaf 2 +echo "Rebooting in 5 sec to Finish changes" +tput sgr0 + +sleep 5 +reboot # ensure hostname correct / console disabling OK / autologin working diff --git a/RPI2/Ubuntu/automated/3_Setup_Network_and_Packages.sh b/RPI2/Ubuntu/automated/3_Setup_Network_and_Packages.sh new file mode 100755 index 00000000..fa07d7b5 --- /dev/null +++ b/RPI2/Ubuntu/automated/3_Setup_Network_and_Packages.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +tput setaf 3 +echo "Part 3 of apsync installation" +tput sgr0 + +pushd /home/$NORMAL_USER/GitHub/companion/RPI2/Ubuntu +time sudo -E ./2_install_packages.sh # 20m +time sudo -E ./install_niceties || echo "Failed" # 20s +time sudo -E ./3_wifi_access_point.sh # 20s + +tput setaf 2 +echo "Success! Finished part 3" +tput sgr0 + diff --git a/RPI2/Ubuntu/automated/4_setup_apsync_components.sh b/RPI2/Ubuntu/automated/4_setup_apsync_components.sh new file mode 100755 index 00000000..7e73a147 --- /dev/null +++ b/RPI2/Ubuntu/automated/4_setup_apsync_components.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +pushd /home/$NORMAL_USER/GitHub/companion/RPI2/Ubuntu +time ./apstreamline.sh # 1m This is optional +#time ./setup_mavlink-router # ~2m Remember to change the mavlink_router.conf file to the right serial port +time ./setup_master_mavlink-router.sh + +time ./7_dflogger.sh # ~210s +#time ./5_setup_mavproxy.sh # instant +#time ./setup-video-streaming # 11s This is optional + +time apt-get install -y libxml2-dev libxslt1.1 libxslt1-dev +time pip install future lxml # 4m +time ./install_pymavlink # new version required for apweb #1m +#Fix pymavlink for apweb install +sudo -u $NORMAL_USER -H bash <&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +pushd /home/$NORMAL_USER/GitHub/companion/RPI2/Ubuntu +time ./install_realsense.sh + +tput setaf 2 +echo "Finished installing Intel Realsense Drivers and Pose Scripts" +tput sgr0 +popd + diff --git a/RPI2/Ubuntu/automated/README.md b/RPI2/Ubuntu/automated/README.md new file mode 100644 index 00000000..0ab85789 --- /dev/null +++ b/RPI2/Ubuntu/automated/README.md @@ -0,0 +1 @@ +# apsync-rpi diff --git a/RPI2/Ubuntu/automated/config.env b/RPI2/Ubuntu/automated/config.env new file mode 100644 index 00000000..fa0c8773 --- /dev/null +++ b/RPI2/Ubuntu/automated/config.env @@ -0,0 +1,4 @@ +export STD_USER=ubuntu +export NORMAL_USER=apsync +export TELEM_SERIAL_PORT=/dev/ttyS0 +export TELEM_SERIAL_BAUD=921600 diff --git a/RPI2/Ubuntu/config.env b/RPI2/Ubuntu/config.env new file mode 100644 index 00000000..a91da932 --- /dev/null +++ b/RPI2/Ubuntu/config.env @@ -0,0 +1,4 @@ +export STD_USER=ubuntu +export NORMAL_USER=apsync +export TELEM_SERIAL_PORT=/dev/ttyS0 +export TELEM_SERIAL_BAUD=921600 \ No newline at end of file diff --git a/RPI2/Ubuntu/create_swap_file.sh b/RPI2/Ubuntu/create_swap_file.sh new file mode 100755 index 00000000..0c18458b --- /dev/null +++ b/RPI2/Ubuntu/create_swap_file.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +pushd ../../Common/Ubuntu +./create_swap_file.sh +popd \ No newline at end of file diff --git a/RPI2/Ubuntu/disable_console.sh b/RPI2/Ubuntu/disable_console.sh new file mode 100755 index 00000000..73e05a2c --- /dev/null +++ b/RPI2/Ubuntu/disable_console.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +tput setaf 3 +echo "Disabling Serial Console to ttyS0" +tput sgr0 + +systemctl mask serial-getty@ttyS0.service + +#copy uboot.env configuration to disable uboot wait for key +cp uboot.env /boot/firmware + +perl -pe 's/console=ttyAMA0,115200//' -i /boot/config-5.3.0-1017-raspi2 +perl -pe 's/console=ttyAMA0,115200//' -i /boot/config-5.3.0-1018-raspi2 diff --git a/RPI2/Ubuntu/ensure_rc_local.sh b/RPI2/Ubuntu/ensure_rc_local.sh new file mode 100755 index 00000000..1707b500 --- /dev/null +++ b/RPI2/Ubuntu/ensure_rc_local.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +tput setaf 3 +echo "Setting up rc.local" +tput sgr0 + +if [ ! -f /etc/rc.local ]; then + cat >/etc/rc.local <&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +pushd ../../Common/Ubuntu/apweb + ./install_apweb +popd diff --git a/RPI2/Ubuntu/install_niceties b/RPI2/Ubuntu/install_niceties new file mode 100755 index 00000000..68d17200 --- /dev/null +++ b/RPI2/Ubuntu/install_niceties @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +pushd ../../Common/Ubuntu + ./install_niceties +popd diff --git a/RPI2/Ubuntu/install_pymavlink b/RPI2/Ubuntu/install_pymavlink new file mode 100755 index 00000000..509a7e58 --- /dev/null +++ b/RPI2/Ubuntu/install_pymavlink @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +. config.env + +pushd ../../Common/Ubuntu/pymavlink + ./install_pymavlink +popd diff --git a/RPI2/Ubuntu/install_realsense.sh b/RPI2/Ubuntu/install_realsense.sh new file mode 100755 index 00000000..ab98a749 --- /dev/null +++ b/RPI2/Ubuntu/install_realsense.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +set -e +set -x + +sudo -u $NORMAL_USER -H bash < or case insensitive, or <0> or <1> +# defining if traffic statistics should be reported. +# Default: false +# +# MavlinkDialect +# One of , or . Defines which MAVLink +# dialect is being used by flight stack, so mavlink-router can log +# appropiately. If , mavlink-router will try to decide based +# on heartbeat received from flight stack. +# Default: auto +# +# Log +# Path to directory where to store flightstack log. +# No default value. If absent, no flightstack log will be stored. +# +# DebugLogLevel +# One of , , or . Which debug log +# level is being used by mavlink-router, with being the +# most verbose. +# Default: +# +# Section [UartEndpoint]: This section must have a name +# +# Keys: +# Device +# Path to UART device, like `/dev/ttyS0` +# No default value. Must be defined. +# +# Baud +# Numeric value stating baudrate of UART device +# Default: 115200 +# +# FlowControl +# Boolean value or case insensitive, or <0> or <1> +# defining if flow control should be enabled +# Default: false +# +# +# Section [UdpEndpoint]: This section must have a name +# +# Keys: +# Address +# If on `Normal` mode, IP to which mavlink-router will +# route messages to (and from). If on `Eavesdropping` mode, +# IP of interface to which mavlink-router will listen for +# incoming packets. In this case, `0.0.0.0` means that +# mavlink-router will listen on all interfaces. +# No dafault value. Must be defined. +# +# Mode +# One of or . See `Address` for more +# information. +# No default value. Must be defined +# +# Port +# Numeric value defining in which port mavlink-router will send +# packets (or listen for them). +# Default value: Increasing value, starting from 14550, when +# mode is `Normal`. Must be defined if on `Eavesdropping` mode. +# +# Section [TcpEndpoint]: This section must have a name +# +# Keys: +# Address: +# IP to which mavlink-router will connect to. +# No default value. Must be defined. +# +# Port: +# Numeric value with port to which mavlink-router will connect to. +# No dafault value. Must be defined. +# +# RetryTimeout: +# Numeric value defining how many seconds mavlink-router should wait +# to reconnect to IP in case of disconnection. A value of 0 disables +# reconnection. +# Default value: 5 +# +# Following, an example of configuration file: +[General] +#ReportStats=true +MavlinkDialect=ardupilotmega +TcpServerPort=0 +#Log=flightstack.log +DebugLogLevel=info +StatsFilePath=/tmp/cmavnode-links.txt + +################################### +# AutoPilot Endpoint # +################################### +[UartEndpoint to_fc] +Device = /dev/ttyS0 +Baud = 921600 + +#[TcpEndpoint to_fc] +#Address = 127.0.0.1 +#Port = 5760 + +################################### +# Local Endpoints # +################################### +[UdpEndpoint to_mavproxy] +Mode = Normal +Address = 127.0.0.1 +Port = 14655 +PortLock = 1 + +[UdpEndpoint to_mavros] +Mode = Normal +Address = 127.0.0.1 +Port = 14551 +PortLock = 1 + +[UdpEndpoint to_dflogger] +Mode = Eavesdropping +Address = 127.0.0.1 +Port = 14556 + +[UdpEndpoint to_t265] +Mode = Normal +Address = 127.0.0.1 +Port = 14560 + +[UdpEndpoint to_apweb] +Mode = Normal +Address = 127.0.0.1 +Port = 14755 + +################################### +# Subnet 10.0.1.xxx # +################################### +[UdpEndpoint to_10_0_1_14550] +Mode = Normal +Address = 10.0.1.255 +Port = 14550 +PortLock = 0 + +[UdpEndpoint to_10_0_1_14668] +Mode = Normal +Address = 10.0.1.255 +Port = 14668 +PortLock = 1 + +[UdpEndpoint to_10_0_1_14669] +Mode = Normal +Address = 10.0.1.255 +Port = 14669 +PortLock = 1 diff --git a/RPI2/Ubuntu/remove-unattended-upgrades b/RPI2/Ubuntu/remove-unattended-upgrades new file mode 100755 index 00000000..4af9a863 --- /dev/null +++ b/RPI2/Ubuntu/remove-unattended-upgrades @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e +set -x + +. config.env + +tput setaf 3 +echo "Remove unattended-upgrades" +tput sgr0 + +apt-get remove -y unattended-upgrades diff --git a/RPI2/Ubuntu/set-hostname b/RPI2/Ubuntu/set-hostname new file mode 100755 index 00000000..aa9af3a0 --- /dev/null +++ b/RPI2/Ubuntu/set-hostname @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e +set -x + +. config.env + +../../Common/Ubuntu/set-hostname + +echo "127.0.0.1 apsync" >> /etc/hosts + diff --git a/RPI2/Ubuntu/setup_master_mavlink-router.sh b/RPI2/Ubuntu/setup_master_mavlink-router.sh new file mode 100755 index 00000000..2eec3fe5 --- /dev/null +++ b/RPI2/Ubuntu/setup_master_mavlink-router.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +if [ $(id -u) -ne 0 ]; then + echo >&2 "Must be run as root" + exit 1 +fi + +tput setaf 3 +echo "Installing mavlink-router master branch" +tput sgr0 + +. config.env + +if [ -z "$TELEM_SERIAL_PORT" ]; then + echo 'TELEM_SERIAL_PORT must be set (e.g. "/dev/ttyS1" or "/dev/ttyMFD1")' + exit 1 +fi + +set -e +set -x + +adduser $NORMAL_USER dialout + +apt install autoconf automake libtool -y +pip install future +pip3 install future + +sudo -u $NORMAL_USER -H bash <