• Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Register
  • Login
ModalAI Forum
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
    • Register
    • Login

    Can't connect to drone from laptop using MAVSDK

    VOXL 2
    mavsdk mavlink-server mavlink
    1
    2
    130
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • L
      luisdelavega
      last edited by luisdelavega 3 Apr 2025, 14:37 3 Apr 2025, 14:20

      I've got a Starling Max 2 (VOXL2) connected to my home network. My laptop is also connected to that same network. I'm trying to connect to the drone using MAVSDK-Python but it just doesn't work. I've lost count of everything I've tried, nothing related to MAVSDK has worked for me.

      I've updated the configuration file’s primary_static_gcs_ip field at /etc/modalai/voxl-mavlink-server.conf to my laptops IP address.

      I'm able to connect with it using pymavlink. I can adb shell in and see the messages coming in by running voxl-inspect-mavlink mavlink_from_gcs. But like I said, MAVSDK just does not connect to the VOXL2...

      Here's an actual snippet I'm trying to run:

      #!/usr/bin/env python3
      
      import asyncio
      import time
      from mavsdk import System
      from pymavlink import mavutil
      
      async def send_heartbeat_and_param_requests(target_ip="192.168.1.187", target_port=14550):
          """Send MAVLink heartbeats and parameter requests to initiate connection with VOXL2"""
          print(f"Sending heartbeats to {target_ip}:{target_port}")
          
          # Create a UDP connection to VOXL2
          connection = mavutil.mavlink_connection(f'udpout:{target_ip}:{target_port}')
          
          # Important: Set specific system and component IDs
          # System ID should not be 1 (typically the vehicle) or 255
          # Component ID should NOT be 0 as that's invalid for a source
          connection.source_system = 2       # Use 2 for a secondary GCS
          connection.source_component = 1    # Use 1 for autopilot component
          
          # Send heartbeats in a loop
          counter = 0
          while True:
              # Send a heartbeat message
              connection.mav.heartbeat_send(
                  mavutil.mavlink.MAV_TYPE_GCS,              # Type: Ground Control Station
                  mavutil.mavlink.MAV_AUTOPILOT_INVALID,     # Autopilot type
                  0,                                          # Base mode
                  0,                                          # Custom mode
                  mavutil.mavlink.MAV_STATE_ACTIVE           # System status
              )
              
              counter += 1
              if counter % 5 == 0:  # Every 5 seconds
                  # Send a parameter request list (this is what QGC does on connection)
                  connection.mav.param_request_list_send(
                      1,     # Target system (default autopilot is usually 1)
                      190    # Target component (default autopilot component)
                  )
                  
                  # Send a ping message
                  connection.mav.ping_send(
                      int(time.time() * 1000),  # Unix timestamp in milliseconds
                      0,                         # Sequence
                      connection.source_system,  # System ID
                      connection.source_component # Component ID
                  )
              
              print(f"Heartbeat sent (count: {counter})")
              await asyncio.sleep(1)  # Send heartbeats at 1Hz
      
      async def connect_to_drone():
          print("Connecting to VOXL2...")
          
          drone = System()
          
          # Different connection string formats to try
          await drone.connect(system_address="udp://:14550")
          
          print("Waiting for drone to connect...")
          timeout = 60  # Extended timeout
          start_time = asyncio.get_event_loop().time()
          
          try:
              async for state in drone.core.connection_state():
                  print(f"Connection state: {state}")
                  
                  if state.is_connected:
                      print(f"Connected to drone!")
                      return drone
                  
                  # Check if we've timed out
                  current_time = asyncio.get_event_loop().time()
                  if current_time - start_time > timeout:
                      print(f"Connection timed out after {timeout} seconds")
                      break
                      
                  await asyncio.sleep(1)
                  
          except Exception as e:
              print(f"Connection error: {e}")
          
          return None
      
      async def main():
          # Start sending heartbeats in the background
          heartbeat_task = asyncio.create_task(send_heartbeat_and_param_requests())
          
          # Wait to ensure heartbeats are being received
          await asyncio.sleep(5)
          
          # Try to connect to the drone
          drone = await connect_to_drone()
          
          # If connected, do something with the drone
          if drone and drone.core:
              try:
                  # Print basic information
                  info = await drone.info.get_version()
                  print(f"Version Info: {info}")
              except Exception as e:
                  print(f"Could not get info: {e}")
          
          # Clean up the heartbeat task
          heartbeat_task.cancel()
          try:
              await heartbeat_task
          except asyncio.CancelledError:
              print("Heartbeat task cancelled")
      
      if __name__ == "__main__":
          # Run the asyncio loop
          asyncio.run(main())
      

      It never even gets to print out the "Waiting for drone to connect..." mesage. The code doesn't execute past the await drone.connect(system_address="udp://:14550") line.

      For the await drone.connect(system_address="udp://:14550") line I've tried every permutation I've found. With or without the VOXL2 IP address. I've used udpout and all other variants, none work.

      I've tried with and without sending the messages using pymavlink in case there is some conflict.

      I've tried connecting with specific sysid and compid like below:

      # Create a System object with specific system ID and component ID
      # These match the IDs we're using in the heartbeat sender
      drone = System(sysid=2, compid=1)
      

      I don't know what else to do. Any help will be greatly appreciated.

      L 1 Reply Last reply 3 Apr 2025, 15:33 Reply Quote 0
      • L
        luisdelavega @luisdelavega
        last edited by luisdelavega 3 Apr 2025, 15:35 3 Apr 2025, 15:33

        UPDATE

        I've simplified my snippet and I'm now able to "connect" to the VOXL2 via MAVSDK. It's still now working as I would expect it to, but first, here's my new script:

        #!/usr/bin/env python3
        
        import asyncio
        from mavsdk import System
        
        target_ip="192.168.1.187"
        target_port=14550
        
        async def connect_to_drone():
            print("Connecting to VOXL2...")
            
            # Create a System object with specific system ID and component ID
            # These match the IDs we're using in the heartbeat sender
            print("Creating System object...")
            drone = System()
            
            # Different connection string formats to try
            print("Connecting to drone...")
            await drone.connect(system_address=f"udp://{target_ip}:{target_port}")
            
            print("Waiting for drone to connect...")
            timeout = 60  # Extended timeout
            start_time = asyncio.get_event_loop().time()
            
            try:
                async for state in drone.core.connection_state():
                    print(f"Connection state: {state}")
                    
                    if state.is_connected:
                        print(f"Connected to drone!")
                        return drone
                    
                    # Check if we've timed out
                    current_time = asyncio.get_event_loop().time()
                    if current_time - start_time > timeout:
                        print(f"Connection timed out after {timeout} seconds")
                        break
                        
                    await asyncio.sleep(1)
                    
            except Exception as e:
                print(f"Connection error: {e}")
            
            return None
        
        async def main():
            # Try to connect to the drone
            drone = await connect_to_drone()
            
            # If connected, do something with the drone
            if drone and drone.core:
                try:
                    # Print basic information
                    info = await drone.info.get_version()
                    print(f"Version Info: {info}")
                except Exception as e:
                    print(f"Could not get info: {e}")
        
        if __name__ == "__main__":
            # Run the asyncio loop
            asyncio.run(main())
        

        When I run this script I see only 3 logs:

        Connecting to VOXL2...
        Creating System object...
        Connecting to drone...
        

        When I adb shell and run voxl-inspect-mavlink mavlink_from_gcs I now see that the VOXL2 is receiving a heartbeat:

        ID Mavlink MSG Name Counter Hz
        0 heartbeat 5 1.1

        But like I mentioned above, the code doesn't execute past await drone.connect(system_address=f"udp://{target_ip}:{target_port}").

        I've tried udpout and nothing changes.

        1 Reply Last reply Reply Quote 0
        1 out of 2
        • First post
          1/2
          Last post
        Powered by NodeBB | Contributors