Skip to content

Issue with PX4 SITL Lockstep Synchronization #129

@yalindem

Description

@yalindem

Hi everyone,

I am experiencing issues with Lockstep synchronization between PX4 (SITL) and Cosys-AirSim. Despite enabling lockstep in the configuration files, the simulation does not seem to maintain a synchronous clock.

Setup

Cosys-Airsim: 5.5-v3.3 (docker container)
PX4: v1.16.0 (host)
QGroundControl: v5.0.8 (host)
Operating System: Ubuntu 22.04

The Core Issue:

The flight in the simulation is stable and responsive. I have added a LiDAR to the drone to test the PX4 Collision Prevention feature. The simulator publishes the sensor topics as expected and I can echo them successfully.

I am currently processing and converting the /airsim_node/PX4/lidar/points/lidar_horizontal topic and re-publishing it to /fmu/in/obstacle_distance. However, PX4 appears to reject this data. When I run the listener obstacle_distance command in the QGroundControl MAVLink Console, I noticed that the messages are consistently flagged as being '~1.2s ago'.

I suspect that PX4 is rejecting the data because it perceives it as stale/old. It seems there is a synchronization gap or a timestamp mismatch between the AirSim clock and the PX4 lockstep clock, specifically affecting the obstacle data pipeline.

To confirm the issue, I compared the timestamps of the topics /airsim_node/PX4/imu/imu and /fmu/out/sensor_combined. There is clearly a ~1-second gap between them. That is why I wanted to investigate the lockstep feature in Cosys-AirSim.

I set the relevant configuration options according to the documentation. I also debugged the code at the following location:
https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/AirLib/include/vehicles/multirotor/firmwares/mavlink/MavLinkMultirotorApi.hpp#L993

However, even when lockstep is enabled in the configuration, the variable lock_step_enabled_ always remains false.

Configuration

My settings.json file:

{
  "SettingsVersion": 2.0,
  "SimMode": "Multirotor",
  "ClockType": "SteppableClock",
  "PawnPaths": {
    "DefaultQuadrotor": {
      "PawnBP": "Class'/Game/Geometry/Meshes/drone8/drone_m_v1_poc2_BP.drone_m_v1_poc2_BP_C'"
    }
  },
  "CameraDefaults": {
    "CaptureSettings": [
      {
        "ImageType": 0,
        "Width": 640,
        "Height": 360,
        "FOV_Degrees": 90
      }
    ]
  },
  "Vehicles": {
    "PX4": {
      "VehicleType": "PX4Multirotor",
      "UseSerial": false,
      "LockStep": true,
      "UseTcp": true,
      "TcpPort": 4560,
      "ControlPortLocal": 14540,
      "ControlPortRemote": 14580,
      "Sensors": {
        "barometer": {
          "SensorType": 1,
          "Enabled": true,
          "X": 0,
          "Y": 0,
          "Z": -0.0230131783400001,
          "Roll": 0,
          "Pitch": 0,
          "Yaw": 0,
          "PressureFactorSigma": 0.0012,
          "PressureFactorTau": 3600,
          "UncorrelatedNoiseSigma": 0.1,
          "UpdateLatency": 0.009,
          "UpdateFrequency": 50,
          "StartupDelay": 0.01
        },
        "imu": {
          "Enabled": true,
          "SensorType": 2,
          "X": 0,
          "Y": 0,
          "Z": -0.0230131783400001,
          "Roll": 0,
          "Pitch": 0,
          "Yaw": 0,
          "UpdateRate": 200,
          "AngularRandomWalk": 0.25,
          "GyroBiasStabilityTau": 500,
          "GyroBiasStability": 4.0,
          "VelocityRandomWalk": 0.21,
          "AccelBiasStabilityTau": 800,
          "AccelBiasStability": 30
        },
        "gps": {
          "Enabled": true,
          "SensorType": 3,
          "X": 0.34038367521363305,
          "Y": -0.44916859822052396,
          "Z": -0.10979996163945907,
          "Roll": 0,
          "Pitch": 0,
          "Yaw": 0,
          "UpdateFrequency": 10,
          "EPH_TimeConstant": 0.9,
          "EPV_TimeConstant": 0.9,
          "EphInitial": 1.5,
          "EpvInitial": 2.0,
          "EphFinal": 0.7,
          "EpvFinal": 1.0,
          "EphMin3d": 1.0,
          "EphMin2d": 1.0,
          "StartupDelay": 25.0
        },
        "magnetometer": {
          "Enabled": true,
          "SensorType": 4
        },
        "lidar_horizontal": {
          "SensorType": 6,
          "Enabled": true,
          "External": false,
          "NumberOfChannels": 1,
          "Range": 40,
          "UpdateFrequency": 10.0,
          "RotationsPerSecond": 10,
          "MeasurementsPerCycle": 50,
          "X": 0.041304643733013284,
          "Y": 0,
          "Z": -0.19857589582336602,
          "Roll": 0,
          "Pitch": 0,
          "Yaw": 180,
          "VerticalFOVUpper": 0,
          "VerticalFOVLower": 0,
          "HorizontalFOVStart": 0,
          "HorizontalFOVEnd": 360,
          "DrawDebugPoints": false,
          "IgnoreMarked": true,
          "GenerateNoise": true,
          "DrawSensor": false,
          "StartupDelay": 0.0
        },
        "lidar_vertical": {
          "SensorType": 6,
          "Enabled": false,
          "External": false,
          "NumberOfChannels": 1,
          "Range": 40,
          "RotationsPerSecond": 10,
          "MeasurementsPerCycle": 50,
          "X": -0.22784134841842799,
          "Y": 0.0010974808245300493,
          "Z": -0.04219995880569029,
          "Roll": 0,
          "Pitch": 90,
          "Yaw": 0,
          "VerticalFOVUpper": 0,
          "VerticalFOVLower": 0,
          "HorizontalFOVStart": 0,
          "HorizontalFOVEnd": 360,
          "DrawDebugPoints": false,
          "IgnoreMarked": true,
          "GenerateNoise": true,
          "DrawSensor": false
        }
      },
      "Parameters": {
        "LPE_LAT": 47.641468,
        "LPE_LON": -122.140165
      }
    }
  }
}

ROS2 launch file:

import os

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch.launch_description_sources import PythonLaunchDescriptionSource

from ament_index_python.packages import get_package_share_directory


def generate_launch_description():

    output = DeclareLaunchArgument("output", default_value="screen")
    publish_clock = DeclareLaunchArgument("publish_clock", default_value="True")
    is_vulkan = DeclareLaunchArgument("is_vulkan", default_value="True")
    host_ip = DeclareLaunchArgument("host_ip", default_value="localhost")
    host_port = DeclareLaunchArgument("host_port", default_value="41451")
    enable_api_control = DeclareLaunchArgument(
        "enable_api_control", default_value="False"
    )
    enable_object_transforms_list = DeclareLaunchArgument(
        "enable_object_transforms_list", default_value="True"
    )

    airsim_node = Node(
        package="airsim_ros_pkgs",
        executable="airsim_node",
        name="airsim_node",
        output=LaunchConfiguration("output"),
        parameters=[
            {
                "is_vulkan": LaunchConfiguration("is_vulkan"),
                "update_airsim_img_response_every_n_sec": 0.05,
                "update_airsim_control_every_n_sec": 0.005,
                "update_lidar_every_n_sec": 0.1,
                "update_gpulidar_every_n_sec": 0.01,
                "update_echo_every_n_sec": 0.01,
                "publish_clock": LaunchConfiguration("publish_clock"),
                "host_ip": LaunchConfiguration("host_ip"),
                "host_port": LaunchConfiguration("host_port"),
                "enable_api_control": LaunchConfiguration("enable_api_control"),
                "enable_object_transforms_list": LaunchConfiguration(
                    "enable_object_transforms_list"
                ),
                "use_sim_time": True,
            }
        ],
        remappings=[
            ("/airsim_node/clock", "/clock"),
        ],
    )

    ld = LaunchDescription()

    ld.add_action(output)
    ld.add_action(publish_clock)
    ld.add_action(is_vulkan)
    ld.add_action(host_ip)
    ld.add_action(host_port)
    ld.add_action(enable_api_control)
    ld.add_action(enable_object_transforms_list)
    ld.add_action(airsim_node)

    return ld

Docker-compose file

services:
  airsim:
    image: "xyz"
    container_name: "cosys_airsim_simulation"
    command: ["sleep", "infinity"]
    network_mode: host
    gpus: all
    environment:
      - DISPLAY
      - XAUTHORITY=/home/ue4/.Xauthority
      - ROS_DOMAIN_ID=${ROS_DOMAIN_ID}
      - ROS_LOCALHOST_ONLY=${ROS_LOCALHOST_ONLY}
      - RMW_IMPLEMENTATION=rmw_fastrtps_cpp
      - TZ=Europe/Berlin
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix:rw
      - ${HOME}/.Xauthority:/home/ue4/.Xauthority
      - ../airsim_share_folder:/home/ue4/airsim_share_folder:rw
      - ./launch/:/home/ue4/Cosys-AirSim/ros2/src/airsim_ros_pkgs/launch/
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    restart: "no"

How i launch the airsim ros wrapper:

ros2 launch /home/ue4/Cosys-AirSim/ros2/src/airsim_ros_pkgs/launch/t7_airsim_node.launch.py use_sim_time:=true

** How i launch the px4:**

env PX4_SYS_AUTOSTART=<custom_airframe_for_my_use_case> ./build/px4_sitl_default/bin/px4

i would be very happy for any help.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions