# Can't connect to drone from laptop using MAVSDK

Source: https://forum.modalai.com/topic/4313/can-t-connect-to-drone-from-laptop-using-mavsdk
Category: VOXL 2 and VOXL 2 Mini (https://forum.modalai.com/category/26/voxl-2-and-voxl-2-mini)
Tags: mavsdk, mavlink-server, mavlink, voxl-2
Posted: 2025-04-03 14:20:55 UTC by luisdelavega
Replies: 1 · Views: 1925

## luisdelavega · 2025-04-03 14:20:55 UTC

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.

## Reply by luisdelavega · 2025-04-03 15:33:56 UTC

#### 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.
