Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/test_on_self_hosted.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ jobs:
timeout-minutes: 120

env:
UE_ROOT: ${{ secrets.UE_ROOT }}
AIRSIM_PY_ENV: ${{ github.workspace }}/airsimenv
DEBIAN_FRONTEND: noninteractive

Expand Down
78 changes: 68 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ if (UNIX)
set(PROJECTAIRSIM_USE_UE_TOOLCHAIN ON)
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_SOURCE_DIR}/unreal-linux-toolchain.cmake")
set(UNREAL_LINUX_TOOLCHAIN "${CMAKE_SOURCE_DIR}/unreal-linux-toolchain.cmake")
set(UE_LIBCXX_LIB_DIR "$ENV{UE_ROOT}/Engine/Source/ThirdParty/Unix/LibCxx/lib/Unix/x86_64-unknown-linux-gnu")
link_directories("${UE_LIBCXX_LIB_DIR}")
else()
message("Building/linking against system-installed toolchain")
set(CMAKE_C_COMPILER clang-13)
Expand All @@ -54,6 +52,30 @@ endif()
# Set up project
project("ProjectAirSimLibs")

if(PROJECTAIRSIM_USE_UE_TOOLCHAIN)
set(UE_LEGACY_LIBCXX_ROOT "$ENV{UE_ROOT}/Engine/Source/ThirdParty/Unix/LibCxx")
set(UE_LIBCXX_INCLUDE_DIR "${UE_LEGACY_LIBCXX_ROOT}/include")
set(UE_LIBCXX_CXX_INCLUDE_DIR "${UE_LEGACY_LIBCXX_ROOT}/include/c++/v1")
set(UE_LIBCXX_LIB_DIR "${UE_LEGACY_LIBCXX_ROOT}/lib/Unix/x86_64-unknown-linux-gnu")

if(NOT EXISTS "${UE_LIBCXX_LIB_DIR}/libc++.a")
set(UE_LIBCXX_INCLUDE_DIR "${CMAKE_SYSROOT}/include")
set(UE_LIBCXX_CXX_INCLUDE_DIR "${CMAKE_SYSROOT}/include/c++/v1")
set(UE_LIBCXX_LIB_DIR "${CMAKE_SYSROOT}/lib64")
endif()

if(NOT EXISTS "${UE_LIBCXX_CXX_INCLUDE_DIR}" OR
NOT EXISTS "${UE_LIBCXX_LIB_DIR}/libc++.a" OR
NOT EXISTS "${UE_LIBCXX_LIB_DIR}/libc++abi.a")
message(FATAL_ERROR "Could not find Unreal libc++ headers/libraries. "
"Checked legacy LibCxx and SDK sysroot paths for UE_ROOT=$ENV{UE_ROOT}")
endif()

message("Using Unreal libc++ includes from ${UE_LIBCXX_CXX_INCLUDE_DIR}")
message("Using Unreal libc++ libraries from ${UE_LIBCXX_LIB_DIR}")
link_directories("${UE_LIBCXX_LIB_DIR}")
endif()

# Capture build commit hash once during configure. Fallback to "unknown"
# when git is unavailable (or source is not a git checkout).
set(PROJECTAIRSIM_BUILD_COMMIT_HASH "unknown")
Expand Down Expand Up @@ -772,18 +794,54 @@ endif()
if(UNIX)
set(ONNXRUNTIME_LIBRARY "${ONNX_LIB_DIR}/libonnxruntime.so")
if(PROJECTAIRSIM_USE_UE_TOOLCHAIN)
function(projectairsim_resolve_ue_runtime_library OUTPUT_VARIABLE LIBRARY_NAME)
set(SEARCH_DIRECTORIES ${ARGN})
foreach(SEARCH_DIRECTORY IN LISTS SEARCH_DIRECTORIES)
set(LIBRARY_PATH "${SEARCH_DIRECTORY}/${LIBRARY_NAME}")
if(EXISTS "${LIBRARY_PATH}")
message(STATUS "Using Unreal C++ runtime library: ${LIBRARY_PATH}")
set(${OUTPUT_VARIABLE} "${LIBRARY_PATH}" PARENT_SCOPE)
return()
endif()
endforeach()

list(JOIN SEARCH_DIRECTORIES "\n " SEARCHED_DIRECTORIES)
message(FATAL_ERROR
"ONNX Runtime C++ runtime dependency '${LIBRARY_NAME}' not found.\n"
"Searched Unreal-owned directories:\n ${SEARCHED_DIRECTORIES}"
)
endfunction()

set(UE_SYSROOT_RUNTIME_DIR "${CMAKE_SYSROOT}/lib64")
set(UE_LEGACY_LIBCXX_DIR
"$ENV{UE_ROOT}/Engine/Source/ThirdParty/Unix/LibCxx/lib/Unix/x86_64-unknown-linux-gnu"
)
projectairsim_resolve_ue_runtime_library(
UE_LIBCXX_LIBRARY
"libc++.a"
"${UE_SYSROOT_RUNTIME_DIR}"
"${UE_LEGACY_LIBCXX_DIR}"
)
projectairsim_resolve_ue_runtime_library(
UE_LIBCXXABI_LIBRARY
"libc++abi.a"
"${UE_SYSROOT_RUNTIME_DIR}"
"${UE_LEGACY_LIBCXX_DIR}"
)
projectairsim_resolve_ue_runtime_library(
UE_LIBSTDCXX_LIBRARY
"libstdc++.so.6"
"${UE_SYSROOT_RUNTIME_DIR}"
"${CMAKE_SYSROOT}/lib"
)

set(ONNXRUNTIME_CXX_RUNTIME_LIBRARIES
"-Wl,--start-group"
"${UE_LIBCXX_LIB_DIR}/libc++.a"
"${UE_LIBCXX_LIB_DIR}/libc++abi.a"
"${CMAKE_SYSROOT}/lib64/libstdc++.so.6"
"${UE_LIBCXX_LIBRARY}"
"${UE_LIBCXXABI_LIBRARY}"
"${UE_LIBSTDCXX_LIBRARY}"
"-Wl,--end-group"
)
foreach(ONNXRUNTIME_CXX_RUNTIME_LIBRARY IN LISTS ONNXRUNTIME_CXX_RUNTIME_LIBRARIES)
if(ONNXRUNTIME_CXX_RUNTIME_LIBRARY MATCHES "^/" AND NOT EXISTS "${ONNXRUNTIME_CXX_RUNTIME_LIBRARY}")
message(FATAL_ERROR "ONNX Runtime C++ runtime dependency not found: ${ONNXRUNTIME_CXX_RUNTIME_LIBRARY}")
endif()
endforeach()
else()
set(ONNXRUNTIME_CXX_RUNTIME_LIBRARIES stdc++)
endif()
Expand Down
4 changes: 4 additions & 0 deletions client/python/projectairsim/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ bonsai = [
datacollection = [
"albumentations==1.3.0",
]
tests = [
"pytest",
"psutil>=5.9.0",
]

[tool.setuptools]
# Source layout: packages live under src/
Expand Down
16 changes: 10 additions & 6 deletions client/python/projectairsim/src/projectairsim/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,6 @@ def connect(self):
)
projectairsim_log().info("Connection opened.")
self.state = True
self.recv_topic_thread = threading.Thread(target=self.__recv_topic)
self.recv_topic_thread.start()
projectairsim_log().info("Started the pub-sub topic receiving thread.")

def get_topic_info(self):
"""This is used by World to get the list of topic info on reload scene."""
Expand Down Expand Up @@ -125,6 +122,12 @@ def subscribe(self, topic, callback, reliability=1.0):
topic (str): the name of the topic
callback (callable): function to call when data is received
"""
# Lazily start the recv thread on first subscribe call
if self.recv_topic_thread is None:
self.socket_topics.recv_timeout = 100 # ms — bounded block for clean shutdown
self.recv_topic_thread = threading.Thread(target=self.__recv_topic)
self.recv_topic_thread.start()

if topic in self.subs:
self.subs[topic]["callbacks"].append(callback)
self.subs[topic]["reliability"] = reliability
Expand Down Expand Up @@ -479,9 +482,10 @@ def __make_message_frame(self, topic, message):

def __recv_topic_frame(self):
try:
# Check if new data is ready to be received with non-blocking recv() call
frame_packed = self.socket_topics.recv(block=False)
except pynng.exceptions.TryAgain:
# Blocking recv with timeout (set on socket in subscribe()).
# Returns None on timeout so the loop can check self.state.
frame_packed = self.socket_topics.recv()
except (pynng.exceptions.TryAgain, pynng.exceptions.Timeout):
return

# If data was ready to be received, process and return it.
Expand Down
29 changes: 28 additions & 1 deletion client/python/projectairsim/src/projectairsim/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,34 @@ def continue_for_single_step(self, wait_until_complete: bool = True) -> int:
single_step_result: str = self.client.request(single_step_req)
return single_step_result

def list_actors(self) -> List[str]:
def step(self, dt_ns: int) -> dict:
"""Advance sim by dt_ns nanoseconds and return bundled state + events.

This is the pull API entry point. The sim advances time, then returns
per-drone kinematics and any events (collisions) that
occurred during the step.

Actions should be sent to individual robots via their existing move
methods before calling step().

Args:
dt_ns: simulation time to advance, in nanoseconds

Returns:
dict with keys:
sim_time_ns (int): current sim time after the step
robots (dict): per-drone data keyed by drone ID, each containing:
state (dict): position, orientation, linear_velocity, angular_velocity
events (list): collision and gate_pass events with sim_time_ns ordering
"""
step_req: dict = {
"method": f"{self.parent_topic}/Step",
"params": {"dt_ns": dt_ns},
"version": 1.0,
}
return self.client.request(step_req)

def list_actors(self) -> list[str]:
"""List actor names in the scene

Returns:
Expand Down
Loading
Loading