Issue running PX4 SITL in a container

Good morning,
I have been working on a new project to control a drone autonomously. For testing, I have been using the PX4 SITL, commanded by my code via MAVLink. To simplify deployment, I decided to use a Docker Compose setup, with the PX4 SITL running in one container and the drone controller in another. However, the connection between my code and the simulation doesn’t seem to be working. I have verified that the PX4 SITL works correctly when run independently.
The issue seems to stem either from the communication link between the Docker containers or from my own code. I have tested various configurations for the MAVLink port—such as udp, udpin, and udpout—but none of them resolved the problem. In some cases, there is no output at all (as shown in the logs at the end of this post), and in others, the connection drops immediately, likely because it’s not being used properly.
I would gladly take advice if anybody has an idea or has already worked with a similar setup.
Thank you in advance for the help.

Here is my compose file:

services:
  # PX4 SITL Simulation (Using px4-gazebo-headless)
  px4-sitl:
    image: jonasvautherin/px4-gazebo-headless:1.15.4
    container_name: erc-px4-sitl
    networks:
      - simulation_net
    ports:
      - "14540:14540/udp"  # MAVLink for drone controller (API port)
      - "14550:14550/udp"  # MAVLink for QGroundControl
      - "8554:8554"        # RTSP video stream from typhoon_h480 camera
    environment:
      # Set custom starting location
      - PX4_HOME_LAT=47.397742
      - PX4_HOME_LON=8.545594
      - PX4_HOME_ALT=488.0
    # Use typhoon_h480 vehicle to get video stream, empty world for simplicity
    command: ["-v", "typhoon_h480", "-w", "empty"]
    restart: "no"
    healthcheck:
      test: ["CMD", "bash", "-c", "ps aux | grep -q '[p]x4' && ps aux | grep -q '[g]azebo'"]
      interval: 30s
      timeout: 15s
      retries: 20
      start_period: 60s

  # Same drone-controller as production, but configured for simulation
  drone-controller:
    build:
      context: .
      dockerfile: docker/drone-controller/Dockerfile
    container_name: erc-drone-controller
    privileged: true
    networks:
      - simulation_net
    volumes:
      # Mount only necessary drone control files
      - ./drone_pkg:/app/src/drone_pkg:ro
      - ./custom_msg:/app/src/custom_msg:ro
    environment:
      - ROS_DOMAIN_ID=30
      - SIM=sim 
      - PX4_SIM_HOST_ADDR=px4-sitl
      - PX4_SITL_PORT=14540
      - MAVSDK_SERVER_PORT=50051
    depends_on:
      px4-sitl:
        condition: service_healthy
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "bash", "-c", "source /opt/ros/humble/setup.bash && ros2 topic list"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

And here is my connection code:

def __init__(self):

        rclpy.init(args=sys.argv)

        self.node = rclpy.create_node('DRONE')

        self.state = State.IDLE

        self.START_LATITUDE_DEG = 0.0
        self.START_LONGITUDE_DEG = 0.0

        self.pos = np.array([0, 0, 0])
        self.thrust = 0.0
        self.goal = np.array([0.0, 0.0, 0.0])

        if os.getenv('SIM', 'real') == 'sim':

            # Connect to PX4 SITL container by hostname
            print("Starting simulation")
            px4_host = os.getenv('PX4_SIM_HOST_ADDR', 'px4-sitl')
            px4_port = os.getenv('PX4_SITL_PORT', '14540')
            port = f"udpin://{px4_host}:{px4_port}"
            print(f"Connecting to PX4 SITL at: {port}")
        else:
            VID = 0x3185
            PID = 0x0035

            print(f"Looking for Pixhawk 6X, VID: {hex(VID)}, PID: {hex(PID)}")
            port = None
            while port is None:
                port = self.find_device_by_id(VID, PID)
                time.sleep(1)
            
            port_name = self.find_device_by_id(VID, PID).name
            port = f"serial://{port_name}"
            print(port_name)

        self.fmu = FMU(self, port)

        # Initialize the camera only in real hardware mode
        self.depthai_camera = None
        if os.getenv('SIM', 'real') == 'real' and DepthAICamera is not None:
            try:
                self.depthai_camera = DepthAICamera()
                threading.Thread(target=self.depthai_camera.take_picture, args=()).start()
                print("DepthAI camera initialized successfully")
            except Exception as e:
                print(f"Failed to initialize DepthAI camera: {str(e)}")
                print("Running without camera functionality")
        else:
            print("Simulation mode: Skipping camera initialization")
async def init_drone(self):
        if os.getenv('FAKE_DRONE', 'real') == 'fake':
            self.drone = FakeDrone()
            print("FakeDrone discovered!")
        else:
            # Let MAVSDK auto-manage the server for both sim and real modes
            self.drone = System()
                
            print(self.port)
            await self.drone.connect(system_address=self.port)

            print("\nWaiting for drone to connect...")
            async for state in self.drone.core.connection_state():
                print("hehe")
                if state.is_connected:
                    print("Drone discovered!")
                    break

And here are the logs of my container:

❯ docker logs erc-drone-controller -f
🚁 Starting ERC Drone Controller...
🎮 Simulation mode detected
⏳ Brief wait for PX4 SITL initialization...
✅ Proceeding to start drone controller
🚀 Starting drone node...
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at action/action.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at mavsdk_options.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at action_server/action_server.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at calibration/calibration.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at camera/camera.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at camera_server/camera_server.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at core/core.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at failure/failure.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at follow_me/follow_me.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at ftp/ftp.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at geofence/geofence.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at gimbal/gimbal.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at gripper/gripper.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at info/info.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at log_files/log_files.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at log_streaming/log_streaming.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at manual_control/manual_control.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at mission/mission.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at mission_raw/mission_raw.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
/usr/local/lib/python3.10/dist-packages/google/protobuf/runtime_version.py:98: UserWarning: Protobuf gencode version 5.29.0 is exactly one major version older than the runtime version 6.31.1 at mission_raw_server/mission_raw_server.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
  warnings.warn(
Starting simulation
Connecting to PX4 SITL at: udpin://px4-sitl:1454
DEBUG:asyncio:Using selector: EpollSelector
🎮 Simulation mode: Skipping camera initialization
🚀 Starting drone node...
udpin://px4-sitl:1454

Drone node spinning !
DEBUG:grpc._cython.cygrpc:Using AsyncIOEngine.POLLER as I/O engine
DEBUG:mavsdk.async_plugin_manager:Waiting for mavsdk_server to be ready...
DEBUG:mavsdk.system:[11:00:22|Info ] MAVSDK version: v3.5.0 (mavsdk_impl.cpp:30)
Scanning dependencies of target gazebo-classic_typhoon_h480__empty
SITL ARGS
sitl_bin: /root/Firmware/build/px4_sitl_default/bin/px4
debugger: none
model: typhoon_h480
world: empty
src_path: /root/Firmware
build_path: /root/Firmware/build/px4_sitl_default
GAZEBO_PLUGIN_PATH :/root/Firmware/build/px4_sitl_default/build_gazebo-classic
GAZEBO_MODEL_PATH :/root/Firmware/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models
LD_LIBRARY_PATH :/root/Firmware/build/px4_sitl_default/build_gazebo-classic
Using: /root/Firmware/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models/typhoon_h480/typhoon_h480.sdf
ALSA lib confmisc.c:767:(parse_card) cannot find card '0'
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1246:(snd_func_refer) error evaluating name
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5007:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM default
AL lib: (EE) ALCplaybackAlsa_open: Could not open playback device 'default': No such file or directory
not running gazebo gui
SITL COMMAND: "/root/Firmware/build/px4_sitl_default/bin/px4" "/root/Firmware/build/px4_sitl_default"/etc

______  __   __    ___ 
| ___ \ \ \ / /   /   |
| |_/ /  \ V /   / /| |
|  __/   /   \  / /_| |
| |     / /^\ \ \___  |
\_|     \/   \/     |_/

px4 starting.

INFO  [px4] startup script: /bin/sh etc/init.d-posix/rcS 0
INFO  [init] found model autostart file as SYS_AUTOSTART=6011
INFO  [param] selected parameter default file parameters.bson
INFO  [param] selected parameter backup file parameters_backup.bson
  SYS_AUTOCONFIG: curr: 0 -> new: 1
ERROR [param] Parameter UXRCE_DDS_KEY not found.
  SYS_AUTOSTART: curr: 0 -> new: 6011
  CAL_ACC0_ID: curr: 0 -> new: 1310988
  CAL_GYRO0_ID: curr: 0 -> new: 1310988
  CAL_ACC1_ID: curr: 0 -> new: 1310996
  CAL_GYRO1_ID: curr: 0 -> new: 1310996
  CAL_ACC2_ID: curr: 0 -> new: 1311004
  CAL_GYRO2_ID: curr: 0 -> new: 1311004
  CAL_MAG0_ID: curr: 0 -> new: 197388
  CAL_MAG0_PRIO: curr: -1 -> new: 50
  CAL_MAG1_ID: curr: 0 -> new: 197644
  CAL_MAG1_PRIO: curr: -1 -> new: 50
  SENS_BOARD_X_OFF: curr: 0.0000 -> new: 0.0000
  SENS_DPRES_OFF: curr: 0.0000 -> new: 0.0010
INFO  [dataman] data manager file './dataman' size is 7872608 bytes
INFO  [init] PX4_SIM_HOSTNAME: localhost
INFO  [simulator_mavlink] Waiting for simulator to accept connection on TCP port 4560
sh: 1: exiftool: not found
INFO  [simulator_mavlink] Simulator connected on TCP port 4560.
INFO  [lockstep_scheduler] setting initial absolute time to 416000 us
WARN  [vehicle_angular_velocity] no gyro selected, using sensor_gyro_fifo:0 1310988
INFO  [commander] LED: open /dev/led0 failed (22)
ERROR [param] Parameter UXRCE_DDS_DOM_ID not found.
etc/init.d-posix/rcS: 310: etc/init.d-posix/rcS: uxrce_dds_client: not found
INFO  [mavlink] mode: Normal, data rate: 4000000 B/s on udp port 18570 remote port 14550
INFO  [mavlink] mode: Onboard, data rate: 4000000 B/s on udp port 14580 remote port 14540
INFO  [mavlink] mode: Onboard, data rate: 4000 B/s on udp port 14280 remote port 14030
INFO  [mavlink] mode: Gimbal, data rate: 400000 B/s on udp port 13030 remote port 13280
INFO  [mavlink] partner IP: 127.0.0.1
INFO  [mavlink] mode: Onboard, data rate: 4000 B/s on udp port 14558 remote port 14530
INFO  [logger] logger started (mode=all)
INFO  [logger] Start file log (type: full)
INFO  [logger] [logger] ./log/2025-06-17/10_41_22.ulg	
INFO  [logger] Opened full log file: ./log/2025-06-17/10_41_22.ulg
INFO  [mavlink] MAVLink only on localhost (set param MAV_{i}_BROADCAST = 1 to enable network)
INFO  [mavlink] MAVLink only on localhost (set param MAV_{i}_BROADCAST = 1 to enable network)
INFO  [px4] Startup script returned successfully
pxh> INFO  [tone_alarm] home set