How to make a PX4 drone fly using MAVLink (via pymavlink + ROS 2)?

I successfully connected to the PX4 drone using MAVLink and started sending SET_ATTITUDE_TARGET messages. I also armed the drone and set it to OFFBOARD mode (see screenshot below). However, there’s no movement visible in the logs or RViz.

Could you help me diagnose what’s wrong and how to make the drone actually fly?

Environment:

  • Ubuntu 22 04
  • PX4 1.15
  • Python, pymavlink, ROS 2
  • mavlink UDP connection: 127.0.0.1:14540
  • QGround station for debug (on picture)

class FlipControlNode(Node):
    def __init__(self):
        super().__init__('flip_control_node')  
        self.master = mavutil.mavlink_connection('udp:127.0.0.1:14540')
        # send heartbeat to connect with PX4
        self.master.mav.heartbeat_send(
            mavutil.mavlink.MAV_TYPE_GCS,
            mavutil.mavlink.MAV_AUTOPILOT_INVALID,
            0, 0, 0
        )

        self.get_logger().info("Жду heartbeat от PX4...")
        self.master.wait_heartbeat()
        self.get_logger().info("MAVLink: heartbeat received")

        # Arming
        self.master.mav.command_long_send(
            self.master.target_system,
            self.master.target_component,
            mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
            0,
            1, 0, 0, 0, 0, 0, 0)
        time.sleep(1.0)

        if self.arming_state != VehicleStatus.ARMING_STATE_ARMED:
            self.arm()

        # Turn OFFBOARD 
        self.master.mav.set_mode_send(
            self.master.target_system,
            mavutil.mavlink.MAV_MODE_FLAG_CUSTOM_MODE_ENABLED,
            VehicleStatus.NAVIGATION_STATE_OFFBOARD)
        time.sleep(0.1)

        # Timer 10 Gz
        self.create_timer(0.1, self.send_pwm_loop)

    def send_pwm_loop(self):
        if not rclpy.ok():
            return

        level_quat = [1.0, 0.0, 0.0, 0.0]  # без наклона
        type_mask = (
        mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_BODY_ROLL_RATE_IGNORE |
        mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_BODY_PITCH_RATE_IGNORE |
        mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_BODY_YAW_RATE_IGNORE
        ) 
        self.get_logger().info(f"type_mask: {type_mask}")  #  0b00000111 = 7 
        self.master.mav.set_attitude_target_send(
            int(self.master.time_since('BOOT') * 1e3),
            self.master.target_system,
            self.master.target_component,
            type_mask,
            level_quat,
            0.0, 0.0, 0.0,
            0.7
        )

Ok, I find:

I really do not understand why you want to use directly mavlink, since the micro agent will take care of all the communication between ROS2 nodes and the flight controller. You can write your ROS2 nodes either in python or C++, and leave the work to the agent and the flight controller.

All the /fmu/in ROS2 topics can be used to command the flight controller in different ways. You can move your drone using coordinates, by publish on the dedicated ROS2 topic /fmu/in/trajectory_setpoint the coordinates you want to reach. With such topic you can send coordinates in the local NED of the drone and even velocities or accelerations. The flight controller then takes care of all to actually move your drone to the target position.

If you’re using ROS (2?) already I would suggest to use the ROS 2 interface instead of pymavlink:

1 Like