.. _tutorial_offboard_python: Offboard Control with Python (Single Vehicle Case) ========================================================== **Note: This tutorial is applicable for DASA indoor configuration.** Controlling a single vehicle with python language can be the starting point for entry users. The offboard control of Kerloud vehicles (UAV, flying rover and rover) in the DASA indoor environment is realized by utilizing the internal Mavros API provided in the localization workspace located in ~/DASA_space/catkinws_dasa. Note that the Mavros package is customized for DASA system to support extended vehicle operations, and standard versions in the ROS community cannot be used here. 1. File Directory ------------------ The demo program can be found in ~/DASA_space/offboard_python_dasa, and the file directory is illustrated below: * **scripts/**: convenience scripts for program operation, such as copying the whole directory to remote DASA agents. * **commander.py**: commander interface that implements various behaviors for robot operations, such as position move, arm, etc. * **px4_mavros_run.py**: control Interface implements low level communication with the Mavros gateway in the DASA localization workspace. * **uav_demo.py**: demo program to operate a Kerloud uav. * **flyingrover_demo.py**: demo program to operate a Kerloud flying rover. * **rover_demo.py**: demo program to operate a Kerloud rover. 2. Environment Requirements ------------------------------ Recommended environment is Ubuntu 18.04, ROS melodic and python 3.6.9 Dependencies: * mavros (dev_kerlouddasa branch): https://github.com/cloudkernel-tech/mavros * mavlink (dev_kerlouddasa branch): https://github.com/cloudkernel-tech/mavlink-gdp-release python module requirements: :: python3 -m pip install rospkg pyquaternion We assume that the DASA localization workspace is located in ~/DASA_space/catkinws_dasa by default, and users can install other prerequisites simply by running setup.sh. All necessary prerequisites are set up in factory. 3. Code Explanation ------------------------ 3.1 Commander Interface ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The commander interface that implements various behaviors for robot operations, such as position move, arm, etc. The reason behind is that different DASA vehicles share similar behavior interfaces in the operation level, so users can construct the application programs by simply calling those functions. For brevity, we illustrate the code in blocks below: (1) Initialization function: the __init__() function initializes variables, subscriptions and publications :: def __init__(self, flag_dasa=False) (2) Callback block: this part declares callback function for ros subscriptions. :: # callback for local position infor def local_pose_callback(self, msg): self.local_position = [msg.pose.position.x, msg.pose.position.y, msg.pose.position.z] def local_velocity_callback(self, msg): self.local_velocity = [msg.twist.linear.x, msg.twist.linear.y, msg.twist.linear.z] ... (3) Behavior block: behavior functions for position, velocity and command requests. Please be careful with the frame definition inside. These functions support maneuvers in both ENU (East-North-Up) and DASA frames. :: # move to a target position def move_position(self, x, y, z, BODY_FLU=False): self.position_target_pub.publish(self.set_pose(x, y, z, BODY_FLU)) def move_velocity(self, vx, vy, vz=0, BODY_FLU=False): self.velocity_target_pub.publish(self.set_velocity(vx, vy, vz, BODY_FLU)) # turn to a desired yaw angle def turn(self, yaw_degree): self.yaw_target_pub.publish(yaw_degree) ... (4) Supporting function block: This block contains some supporting functions for pose or velocity constructions and math computations. For instance, the following function construct a waypoint pose with requested coordinates. :: # set waypoint pose def set_pose(self, x=0, y=0, z=2, BODY_FLU = False): pose = PoseStamped() pose.header.stamp = rospy.Time.now() # ROS uses ENU internally, so we will stick to this convention if BODY_FLU: pose.header.frame_id = 'base_link' else: pose.header.frame_id = 'map' pose.pose.position.x = x pose.pose.position.y = y pose.pose.position.z = z return pose 3.2 Control Interface ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The Control Interface implements low level communication with the mavros gateway, and there is no need to change it for most cases. The entry function is start() in the Px4Controller class, which will be called when the px4_mavros_run.py is executed. In the start() function, the ros node will wait first for DASA frame initialization by utilizing a service call to the localization workspace, then the autopilot data must arrive before further processing. :: # waiting for dasa frame initialization if self.flag_dasa_frame: print("Waiting for DASA frame initialization") self.getDasaFrameInfo() print("Waiting for autopilot data...") while (self.current_heading is None or self.local_pose is None): time.sleep(1.0) self.cur_pos_target = self.construct_position_target(self.local_pose.pose.position.x, self.local_pose.pose.position.y, self.local_pose.pose.position.z, self.current_heading) Then the program will arm and set offboard control mode automatically in the simulation mode, or wait for manual triggering in real flights. :: '''arm and set offboard automatically in simulation mode''' if flag_simulation_mode: print("setting arm and offboard in simulation mode...") while True: self.local_target_pub.publish(self.cur_pos_target) if not self.arm_state: self.arm() if not self.offboard_state: self.offboard() if self.arm_state and self.offboard_state: print("vehicle is armed and set in offboard mode") break time.sleep(0.1) else: print("Control interface: starting in real test...") Finally, the program will enter a while loop to respond to different commands from the Commander Interface, including position setpoints, turn, hover, etc. :: ''' main ROS thread ''' while not rospy.is_shutdown(): # publications if self.cmd_mode == MC_POSITION_COMMAND_MODE: self.local_target_pub.publish(self.cur_pos_target) elif self.cmd_mode == MC_VELOCITY_COMMAND_MODE: self.local_target_pub.publish(self.cur_vel_target) elif self.cmd_mode == ROVER_POSITION_ROVER_COMMAND_MODE: self.local_target_pub.publish(self.cur_pos_target) elif self.cmd_mode == ROVER_VELOCITY_ROVER_COMMAND_MODE: self.local_target_pub.publish(self.cur_vel_target) elif self.cmd_mode == ROVER_ACTUATOR_CONTROL_ROVER_COMMAND_MODE: self.actuator_control_target_pub.publish(self.cur_actuator_control_target) if self.vehicle_type == "flyingrover": self.flyingrover_mode_pub.publish(self.current_fr_mode) self.landedstate_pub.publish(String(self.landed_state)) ... 4. Simulation Test -------------------------------------- Operating Procedure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We highly recommend users to conduct simulation tests before real flights. The virtual simulation environment are prepared in the directory ~/DASA_space/virtual_simulation for all Kerloud vehicles. Note that simulation tests can only be performed in a personal computer. :: # Attention: users have to start STIL simulation for Kerloud vehicles in virtual environment first # uav case: cd ~/DASA_space/virtual_simulation/sitl_space_kerloud_uav bash sitl_run.sh $PWD/bin/px4 none gazebo kerloud300 # flying rover case: # cd ~/DASA_space/virtual_simulation/sitl_space_kerloud_flyingrover # bash sitl_run.sh $PWD/bin/px4 none gazebo kerloud_fr_scorpion # rover case: # cd ~/DASA_space/virtual_simulation/sitl_space_kerloud_rover # bash sitl_run.sh $PWD/bin/px4 none gazebo kerloud_rover # terminal 1 # source the mavros workspace in dasa locolization workspace cd ~/DASA_space/offboard_python_dasa source ../catkinws_dasa/devel/setup.bash # launch the mavros node for simulation roslaunch mavros px4.launch fcu_url:="udp://:14540@127.0.0.1:14557" # terminal 2: start the commander interface # source the mavros workspace in dasa locolization workspace cd ~/DASA_space/offboard_python_dasa source ../catkinws_dasa/devel/setup.bash # start demo programs for a specific vehicle type python3 uav_demo.py --flag_dasa False # python3 flyingrover_demo.py --flag_dasa False # python3 rover_demo.py --flag_dasa False # terminal 3: start the control interface # source the mavros workspace in dasa locolization workspace cd ~/DASA_space/offboard_python_dasa source ../catkinws_dasa/devel/setup.bash python3 px4_mavros_run.py --sim True --flag_dasa False --vehicle uav # python3 px4_mavros_run.py --sim True --flag_dasa False --vehicle flyingrover # python3 px4_mavros_run.py --sim True --flag_dasa False --vehicle rover Or simply use convenience scripts: :: bash scripts/start_uav_sitldemo.sh # uav case bash scripts/start_flyingrover_sitl_demo.sh # flyingrover case bash scripts/start_rover_sitl_demo.sh # rover case 5. Real Flights in DASA Environment ---------------------------------------------------- Operating Procedure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Users are advised to follow the procedures below exactly to run the demo. Keep in mind that safety comes first, and a safety pilot should be at presence for every flight. Step 1: Mount the battery ready with a battery cable, make sure that it will not fall down during flight. Step 2: Make sure that all switches are in their initial position and the throttle channel is lowered down. Step 3: Turn on the DASA wifi router with the network name DASA_swarm, and also those UWB devices in the experiment setup. Users shall configure the DASA indoor localization system properly according to the user manual. Step 4: Make sure that the safety pilot is standby, and there are no people surrounding the vehicle. Power on the vehicle, and wait a few minutes for the onboard computer to boot. The DASA system provides a ready-to-use DASA_swarm network that all Kerloud vehicles can automatically connect on boot. For each vehicle, a unique ID is configured in its hostname. To check whether a vehicle with ID x is connected to the local network, simply ping its ip or hostname in the master computer. :: ping or ping ubuntu The vehicle can only be remotely operated if replies can be returned from the target ip address. Step 5: We have to synchronize the python workspace to the remote machine, simply run the script in scripts/ folder: :: bash scripts/sync_python_demo_remote.sh Step 6: Log into the remote vehicle using the ssh command: :: ssh ubuntu@ or ssh ubuntu@ubuntu and then perform the following commands. Note that localization nodes have to be brought up before we run the python demo code. :: # terminal 1: start DASA localization nodes # source the mavros workspace in dasa locolization workspace cd ~/DASA_space/catkinws_dasa && source devel/setup.bash # launch nodes for dasa localization bash scripts/single_case/.sh # terminal 2: start the control interface # source the mavros workspace in dasa locolization workspace cd ~/DASA_space/offboard_python_dasa source ../catkinws_dasa/devel/setup.bash python3 px4_mavros_run.py --sim False --flag_dasa True --vehicle # terminal 3: start the commander interface # source the mavros workspace in dasa locolization workspace cd ~/DASA_space/offboard_python_dasa source ../catkinws_dasa/devel/setup.bash # start demo programs for a specific vehicle type python3 uav_demo.py --flag_dasa True # python3 flyingrover_demo.py --flag_dasa True # python3 rover_demo.py --flag_dasa True # then users can arm and set offboard mode with a transmitter to start the mission Or simply use convenience scripts and then operate with the transmitter: :: bash scripts/run_uav_demo.sh # uav case bash scripts/run_flyingrover_demo.sh # flyingrover case bash scripts/run_rover_demo.sh # rover case 6. Demonstrations --------------------------- Offboard control simulation for DASA vehicles: .. raw:: html