---
# System prepended metadata

title: PX4 and MAVROS Installation
tags: [ROS]

---

# PX4 and MAVROS Installation

<details>
    <summary style="font-size: 18px; font-weight: bold;">Official Documentation</summary>

### PX4 Installation

https://docs.px4.io/main/en/dev_setup/dev_env_linux_ubuntu.html

### MAVROS Installation

https://docs.px4.io/main/en/ros/mavros_installation.html

### MAVROS Offboard control example (Python)

https://docs.px4.io/main/en/ros/mavros_offboard_python.html
</details>

<details>
    <summary style="font-size: 18px; font-weight: bold;">TL;DR</summary>

## The extra Steps you need to do
### 1. Install catkin_tools
https://catkin-tools.readthedocs.io/en/latest/installing.html


### 2. Modify .bashrc
https://docs.px4.io/main/en/ros/mavros_offboard_python.html#launching-your-script
將下面幾行放到你的 .bashrc 中，並且 setup.bash 要在 PX4 的四行命令之前，並且後面不能再 source 其他 workspace 的 setup.bash。
```
source ~/<你的工作目錄>/devel/setup.bash
source ~/PX4-Autopilot/Tools/simulation/gazebo-classic/setup_gazebo.bash ~/PX4-Autopilot ~/PX4-Autopilot/build/px4_sitl_default
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Autopilot
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic
export GAZEBO_PLUGIN_PATH=$GAZEBO_PLUGIN_PATH:/usr/lib/x86_64-linux-gnu/gazebo-11/plugins
```

### 3. 修改 offb_node.py 將 Shebang 移到最上方，並改成 python3

<details>
    <summary>修改後的 offb_node.py</summary>

```python=
#! /usr/bin/env python3
"""
 * File: offb_node.py
 * Stack and tested in Gazebo Classic 9 SITL
"""

import rospy
from geometry_msgs.msg import PoseStamped
from mavros_msgs.msg import State
from mavros_msgs.srv import CommandBool, CommandBoolRequest, SetMode, SetModeRequest

current_state = State()

def state_cb(msg):
    global current_state
    current_state = msg


if __name__ == "__main__":
    rospy.init_node("offb_node_py")

    state_sub = rospy.Subscriber("mavros/state", State, callback = state_cb)

    local_pos_pub = rospy.Publisher("mavros/setpoint_position/local", PoseStamped, queue_size=10)

    rospy.wait_for_service("/mavros/cmd/arming")
    arming_client = rospy.ServiceProxy("mavros/cmd/arming", CommandBool)

    rospy.wait_for_service("/mavros/set_mode")
    set_mode_client = rospy.ServiceProxy("mavros/set_mode", SetMode)


    # Setpoint publishing MUST be faster than 2Hz
    rate = rospy.Rate(20)

    # Wait for Flight Controller connection
    while(not rospy.is_shutdown() and not current_state.connected):
        rate.sleep()

    pose = PoseStamped()

    pose.pose.position.x = 0
    pose.pose.position.y = 0
    pose.pose.position.z = 2

    # Send a few setpoints before starting
    for i in range(100):
        if(rospy.is_shutdown()):
            break

        local_pos_pub.publish(pose)
        rate.sleep()

    offb_set_mode = SetModeRequest()
    offb_set_mode.custom_mode = 'OFFBOARD'

    arm_cmd = CommandBoolRequest()
    arm_cmd.value = True

    last_req = rospy.Time.now()

    while(not rospy.is_shutdown()):
        if(current_state.mode != "OFFBOARD" and (rospy.Time.now() - last_req) > rospy.Duration(5.0)):
            if(set_mode_client.call(offb_set_mode).mode_sent == True):
                rospy.loginfo("OFFBOARD enabled")

            last_req = rospy.Time.now()
        else:
            if(not current_state.armed and (rospy.Time.now() - last_req) > rospy.Duration(5.0)):
                if(arming_client.call(arm_cmd).success == True):
                    rospy.loginfo("Vehicle armed")

                last_req = rospy.Time.now()

        local_pos_pub.publish(pose)

        rate.sleep()
```
    
</details>

官方的說明文件上未將 Shebang 置於程式碼最上方，導致執行時會發生錯誤，且 ubuntu 20.04 版本的 ```python``` 環境變數是未被設定的，應該將 Shebang 裡的 ```python``` 改成 ```python3```。

```#! /usr/bin/env python3``` 

這行指令就是 Shebang，用於指定該檔案的直譯器，可使該程式檔可如同一般的執行檔一樣直接呼叫。

> e.g., 直接在 terminal 打 ```./foo.py```，前面不必加 python。

### 4. Compile PX4 SITL and Gazebo Classic

```
make -C ./PX4-Autopilot/ px4_sitl gazebo-classic
```
</details>

<iframe height="405" src="https://www.youtube.com/embed/3CWNg_pJPFQ?si=IupvA6u8OGqOPXYy" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

> This video starts after completing the "Run the `ubuntu.sh` to install" step.

> Download the vdi file from my Google Drive [here](https://drive.google.com/file/d/1LMt0zbts0C5hIjb7dVVFDUKfM0ROCESi/view?usp=drive_link) if you want to follow along with the video. (The user password is "rvl".)

<span style=color:red;font-weight:bold>!! If you are a student from the Robot Vision Lab, make sure to download from our [NAS](http://gofile.me/3rsol/q4LWCGK8x). Downloading from external sources could lead to our lab's network being blocked. !!</span>

> Additionally, check out the note in the [README](https://github.com/cjzrv/summer-course/blob/main/week3/HW2/README.md) of my GitHub repository (for easier copy-pasting of commands).
    
## 1. Install PX4

#### Download PX4 Source Code

```shell
git clone https://github.com/PX4/PX4-Autopilot.git --recursive
```

#### Run the `ubuntu.sh` to install

```shell
bash ./PX4-Autopilot/Tools/setup/ubuntu.sh
```

#### Compile PX4 SITL and Gazebo Classic

```
DONT_RUN=1 make -C ./PX4-Autopilot/ px4_sitl gazebo-classic
```
[](https://)
## 2. Install catkin_tools
#### Add ROS apt repositories
```
sudo sh \
    -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" \
    > /etc/apt/sources.list.d/ros-latest.list' && \
    wget http://packages.ros.org/ros.key -O - | sudo apt-key add -
```
#### Install catkin-tools with apt-get

```
sudo apt-get update && sudo apt-get install -y python3-catkin-tools
```

## 3. Install MAVROS

#### Install MAVROS with apt-get (Binary Install)
```
sudo apt-get install -y ros-${ROS_DISTRO}-mavros ros-${ROS_DISTRO}-mavros-extras ros-${ROS_DISTRO}-mavros-msgs
```

#### Install GeographicLib datasets
```
wget https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh && \
    sudo bash ./install_geographiclib_datasets.sh && \
    rm -f ./install_geographiclib_datasets.sh
```

## 4. Run the MAVROS Offboard control example

    
#### Create Catkin Workspace
```
mkdir -p ~/poop_space/src
cd ~/poop_space
catkin init
wstool init src
```

#### Create the ROS Package
```
cd src
catkin_create_pkg offboard_py rospy
cd ..
catkin build
source devel/setup.bash
roscd offboard_py
mkdir scripts
cd scripts
touch offb_node.py
chmod +x offb_node.py
```
#### Edit `offb_node.py` with following code:
    
<details>
  <summary style="font-weight: bold;">offb_node.py (modified)</summary>
    
```python=
#! /usr/bin/env python3
"""
 * File: offb_node.py
 * Stack and tested in Gazebo Classic 9 SITL
"""

import rospy
from geometry_msgs.msg import PoseStamped
from mavros_msgs.msg import State
from mavros_msgs.srv import CommandBool, CommandBoolRequest, SetMode, SetModeRequest

current_state = State()

def state_cb(msg):
    global current_state
    current_state = msg


if __name__ == "__main__":
    rospy.init_node("offb_node_py")

    state_sub = rospy.Subscriber("mavros/state", State, callback = state_cb)

    local_pos_pub = rospy.Publisher("mavros/setpoint_position/local", PoseStamped, queue_size=10)

    rospy.wait_for_service("/mavros/cmd/arming")
    arming_client = rospy.ServiceProxy("mavros/cmd/arming", CommandBool)

    rospy.wait_for_service("/mavros/set_mode")
    set_mode_client = rospy.ServiceProxy("mavros/set_mode", SetMode)


    # Setpoint publishing MUST be faster than 2Hz
    rate = rospy.Rate(20)

    # Wait for Flight Controller connection
    while(not rospy.is_shutdown() and not current_state.connected):
        rate.sleep()

    pose = PoseStamped()

    pose.pose.position.x = 0
    pose.pose.position.y = 0
    pose.pose.position.z = 2

    # Send a few setpoints before starting
    for i in range(100):
        if(rospy.is_shutdown()):
            break

        local_pos_pub.publish(pose)
        rate.sleep()

    offb_set_mode = SetModeRequest()
    offb_set_mode.custom_mode = 'OFFBOARD'

    arm_cmd = CommandBoolRequest()
    arm_cmd.value = True

    last_req = rospy.Time.now()

    while(not rospy.is_shutdown()):
        if(current_state.mode != "OFFBOARD" and (rospy.Time.now() - last_req) > rospy.Duration(5.0)):
            if(set_mode_client.call(offb_set_mode).mode_sent == True):
                rospy.loginfo("OFFBOARD enabled")

            last_req = rospy.Time.now()
        else:
            if(not current_state.armed and (rospy.Time.now() - last_req) > rospy.Duration(5.0)):
                if(arming_client.call(arm_cmd).success == True):
                    rospy.loginfo("Vehicle armed")

                last_req = rospy.Time.now()

        local_pos_pub.publish(pose)

        rate.sleep()
```
</details>

<details>
    <summary style="font-weight: bold;">Additional explanation</summary>

官方的說明文件上未將 Shebang 置於程式碼最上方，導致執行時會發生錯誤，且 ubuntu 20.04 版本的 ```python``` 環境變數是未被設定的，應該將 Shebang 裡的 ```python``` 改成 ```python3```。

```#! /usr/bin/env python3``` 

這行指令就是 Shebang，用於指定該檔案的直譯器，可使該程式檔可如同一般的執行檔一樣直接呼叫。

> e.g., 直接在 terminal 打 ```./foo.py```，前面不必加 python。
    
</details>

#### Create the ROS launch file 
```
roscd offboard_py
mkdir launch
cd launch
touch start_offb.launch
```
#### Edit `start_offb.launch` with following code:
```XML=
<?xml version="1.0"?>
<launch>
	<!-- Include the MAVROS node with SITL and Gazebo -->
	<include file="$(find px4)/launch/mavros_posix_sitl.launch">
	</include>

	<!-- Our node to control the drone -->
	<node pkg="offboard_py" type="offb_node.py" name="offb_node_py" required="true" output="screen" />
</launch>
```

## Modify your .bashrc

#### Add following lines to your `.bashrc`
```=
source ~/poop_space/devel/setup.bash
source ~/PX4-Autopilot/Tools/simulation/gazebo-classic/setup_gazebo.bash ~/PX4-Autopilot ~/PX4-Autopilot/build/px4_sitl_default
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Autopilot
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic
export GAZEBO_MODEL_PATH=${GAZEBO_MODEL_PATH}:~/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models
```

<details>
  <summary style="font-weight: bold;">(optional) Edit .bashrc with echo and ">>"</summary>
    
```=
echo -e "source ~/poop_space/devel/setup.bash \n\
    source ~/PX4-Autopilot/Tools/simulation/gazebo-classic/setup_gazebo.bash ~/PX4-Autopilot ~/PX4-Autopilot/build/px4_sitl_default \n\
    export ROS_PACKAGE_PATH=\$ROS_PACKAGE_PATH:~/PX4-Autopilot \n\
    export ROS_PACKAGE_PATH=\$ROS_PACKAGE_PATH:~/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic \n\
    export GAZEBO_MODEL_PATH=\${GAZEBO_MODEL_PATH}:~/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models" \
    >> ~/.bashrc
```
</details>

#### Source your `.bashrc`
    
```
source ~/.bashrc
```

## Launching your script
```
roslaunch offboard_py start_offb.launch
```


---

<details>
  <summary style="font-weight: bold;">Reference</summary>
    
PX4 Installation  
https://docs.px4.io/main/en/dev_setup/dev_env_linux_ubuntu.html

MAVROS Installation  
https://docs.px4.io/main/en/ros/mavros_installation.html

MAVROS Offboard control example (Python)  
https://docs.px4.io/main/en/ros/mavros_offboard_python.html
    
PX4 UAV uses Mavros in Gazebo-classic simulation  
https://github.com/FCWTW/SummerCourse/blob/main/Week%203/HW2/README.md

ERROR: cannot launch node of type [px4/px4]  
https://github.com/PX4/PX4-Autopilot/issues/14762

</details>