diff --git a/.gitmodules b/.gitmodules index dfa1abd..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "PX4-Autopilot"] - path = PX4-Autopilot - url = https://git.spirirobotics.com/Spiri/PX4-Autopilot.git diff --git a/PX4-Autopilot b/PX4-Autopilot deleted file mode 160000 index dd0fb2e..0000000 --- a/PX4-Autopilot +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dd0fb2ef11fc6882c005b16801b1ef47b5d8683b diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6abc5ac --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,65 @@ +version: '3.8' + +services: + ardupilot: + image: git.spirirobotics.com/spiri/ardupilot:spiri-master + command: > + ./Tools/autotest/sim_vehicle.py -v copter --no-rebuild + --out=udpin:0.0.0.0:5000 + --enable-dds + stdin_open: true + tty: true + + mavproxy: + image: git.spirirobotics.com/spiri/services-mavproxy:main + command: > + mavproxy.py --non-interactive + --out=udpbcast:192.168.7.255:14560 + --out=tcpin:0.0.0.0:5760 + --master=udpout:ardupilot:5000 + restart: always + ports: + - 5760:5760 + + mavros: + #This service bridges our mavlink-based robot-coprosessor into ROS + #In this example it connects to a simulated coprocessor. + image: git.spirirobotics.com/spiri/services-ros1-mavros:master + command: roslaunch mavros px4.launch fcu_url:="udp://:14555@mavproxy:14550" tgt_system:="1" + environment: + - "ROS_MASTER_URI=http://ros-master:11311" + depends_on: + ros-master: + condition: service_healthy + mavproxy: + condition: service_started + restart: always + deploy: + resources: + limits: + # cpus: '0.01' + memory: 200M + ulimits: + nofile: + soft: 1024 + hard: 524288 + + ros-master: + image: git.spirirobotics.com/spiri/services-ros1-core:main + command: stdbuf -o L roscore + environment: + - "ROS_MASTER_URI=http://ros-master:11311" + restart: always + ports: + - "127.0.0.1:11311:11311" + deploy: + resources: + limits: + memory: 1G + # Madness, setting a low ulimit here fixes memory leaks + # https://answers.ros.org/question/336963/rosout-high-memory-usage/ + ulimits: + nofile: + soft: 1024 + hard: 524288 + diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d0c3cbf..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 44b6013..0000000 --- a/docs/README.md +++ /dev/null @@ -1,11 +0,0 @@ -If you have a correctly configured sphinx environment you can build this project -using `make html latexpdf`. - -You can also use nektos/act to build this project in the same way our build does. -```bash -cd ../ #Make sure you're in the project root, you should have a hidden folder -# named ./.github/workflows available. -act --artifact-server-path ./doc-build -``` - -Your compiled doc project will now be in the ./doc-build folder. diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 747ffb7..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css deleted file mode 100644 index cdc1a92..0000000 --- a/docs/source/_static/custom.css +++ /dev/null @@ -1,34 +0,0 @@ -.wy-side-nav-search { - background: #FFFFFF !important; -} - - -.wy-nav-side { - background-color: #FFFFFF !important; -} - - -/* Add borders and box-shadow */ -.wy-side-nav { - border: 1px solid #899CA3 !important; -} - -.logo { - width: 100px !important; -} - -.wy-menu-vertical a { - color: #899CA3 !important; /* Change to your desired color */ -} - -.document-title { - color: #000 !important; - font-size: 24px !important; - text-transform: uppercase !important; -} - -.icon-home { - font-weight: bold !important; - text-transform: uppercase !important; - color: #000 !important; -} diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index d5b77c9..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,65 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -import sphinx_rtd_theme - -project = "spiri-sdk" -copyright = "2024, Spiri Robotics" -author = "Spiri Robotics" - -html_logo = "logos/SPIRI_STLockup_Mixed_RGB.png" # For HTML output -html_logo_width = '200px' -latex_logo = "logos/SPIRI_STLockup_Mixed_RGB.png" -latex_logo_width = '5cm' - - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - -extensions = [ - "sphinx.ext.duration", - "sphinx.ext.doctest", - "sphinx.ext.autodoc", - "sphinx.ext.autosummary", - "sphinx.ext.intersphinx", - "sphinx.ext.todo", -] - - -numfig = True - -todo_include_todos = True -todo_emit_warnings = True -todo_link_only = True - - -templates_path = ["_templates"] -exclude_patterns = [] - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - -html_static_path = ['_static'] - -html_css_files = [ - 'custom.css', -] - - -html_theme_options = { - 'collapse_navigation': True, - 'sticky_navigation': True, - 'navigation_depth': 4, #could be set to -1 if we want unlimited depth - 'includehidden': True, - 'titles_only': False -} - -latex_engine = "xelatex" -# Configure LaTeX options for PDF generation diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index e564e24..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. spiri-sdk documentation master file, created by - sphinx-quickstart on Wed Feb 14 11:51:45 2024. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to spiri-sdk's documentation! -============================================ - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/source/logos/SPIRI_STLockup_Mixed_RGB.png b/docs/source/logos/SPIRI_STLockup_Mixed_RGB.png deleted file mode 100644 index e1a4800..0000000 Binary files a/docs/source/logos/SPIRI_STLockup_Mixed_RGB.png and /dev/null differ diff --git a/skel/.gitkeep b/skel/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/skel/.kasmpasswd b/skel/.kasmpasswd deleted file mode 100644 index 85c8c91..0000000 --- a/skel/.kasmpasswd +++ /dev/null @@ -1 +0,0 @@ -spiri:$5$kasm$bc2Fwutowq1kSiQCv2rNYVgn8.bJeARYMydYCvU1WKC:wo diff --git a/skel/Desktop/simulated-drone/docker-compose.yaml b/skel/Desktop/simulated-drone/docker-compose.yaml deleted file mode 100644 index 9235962..0000000 --- a/skel/Desktop/simulated-drone/docker-compose.yaml +++ /dev/null @@ -1,107 +0,0 @@ -version: "3.8" - - -services: - mavros: - image: git.spirirobotics.com/spiri/services-ros1-mavros:master - command: roslaunch mavros px4.launch fcu_url:="udp://:${MAVROS_SIM_FCU_PORT}@127.0.0.1:${MAVROS_SIM_GCS_PORT:-14557}" tgt_system:=${DRONE_SYS_ID:-1} - environment: - - "ROS_MASTER_URI=http://ros-master:${ROS_MASTER_PORT:-11311}" - depends_on: - ros-master: - condition: service_healthy - restart: always - deploy: - resources: - limits: - memory: 200M - ulimits: - nofile: - soft: 1024 - hard: 524288 - ports: - - "${MAVROS_SIM_FCU_PORT:-14540}:${MAVROS_SIM_FCU_PORT:-14540}/udp" - - "${MAVROS_SIM_GCS_PORT:-14557}:${MAVROS_SIM_GCS_PORT:-14557}/udp" - - ros-master: - image: git.spirirobotics.com/spiri/services-ros1-core:main - command: stdbuf -o L roscore --port ${ROS_MASTER_PORT:-11311} - environment: - - "ROS_MASTER_URI=http://ros-master:${ROS_MASTER_PORT:-11311}" - restart: always - ports: - - "127.0.0.1:${ROS_MASTER_PORT:-11311}:${ROS_MASTER_PORT:-11311}" - deploy: - resources: - limits: - memory: 1G - ulimits: - nofile: - soft: 1024 - hard: 524288 - - # gscam: - # image: git.spirirobotics.com/spiri/services-ros1-gscam_all_in_one:main - # runtime: nvidia - # environment: - # ROS_MASTER_URI: http://localhost:11311 - # ROS_LOG_LEVEL: DEBUG - # PORT_GSCAM_CONFIG: > - # nvarguscamerasrc sensor-id=0 aelock=true awblock=true ! video/x-raw(memory:NVMM), width=(int)$(arg width), height=(int)$(arg height), format=(string)NV12, framerate=(fraction)$(arg fps)/1 ! nvvidconv flip-method=0 ! video/x-raw, format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR - # STARBOARD_GSCAM_CONFIG: > - # nvarguscamerasrc sensor-id=1 aelock=true awblock=true ! video/x-raw(memory:NVMM), width=(int)$(arg width), height=(int)$(arg height), format=(string)NV12, framerate=(fraction)$(arg fps)/1 ! nvvidconv flip-method=0 ! video/x-raw, format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR - # volumes: - # - /tmp/argus_socket:/tmp/argus_socket - # - # udp-stream: - # image: git.spirirobotics.com/spiri/services-ros1-gscam_all_in_one:main - # privileged: true - # runtime: nvidia - # network_mode: host - # environment: - # DISPLAY: ":0" - # volumes: - # - /tmp/argus_socket:/tmp/argus_socket - # - /tmp/.X11-unix:/tmp/.X11-unix - # - /var/run/xauth/:/var/run/xauth/ - # command: > - # gst-launch-1.0 - # nvarguscamerasrc sensor-id=0 - # ! 'video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12, framerate=(fraction)60/1' - # ! tee name=raw - # raw. ! queue - # ! nvegltransform ! nveglglessink sync=false async=false - # raw. ! queue - # ! videorate max-rate=30 drop-only=true - # ! queue max-size-buffers=3 leaky=downstream - # ! nvv4l2h265enc - # bitrate=2000000 - # iframeinterval=300 - # vbv-size=33333 - # insert-sps-pps=true - # control-rate=constant_bitrate - # profile=Main - # num-B-Frames=0 - # ratecontrol-enable=true - # preset-level=UltraFastPreset - # EnableTwopassCBR=false - # maxperf-enable=true - # ! rtph265pay name=pay0 pt=96 config-interval=-1 mtu=1400 - # ! udpsink host=192.168.1.100 auto-multicast=false port=5600 sync=false async=false - # - # mavproxy: - # image: git.spirirobotics.com/spiri/services-mavproxy:main - # command: > - # mavproxy.py --non-interactive - # --out=udpin:0.0.0.0:14551 - # --out=udpin:0.0.0.0:14550 - # --out=tcpin:0.0.0.0:5760 - # --master=/dev/ttyTHS2 --baudrate 921600 - # restart: always - # devices: - # - "/dev/ttyTHS2:/dev/ttyTHS2" - # ports: - # - "14550:14550/udp" - # - "5760:5760/tcp" - # - # diff --git a/skel/Desktop/simulated-drone/sim_drone.py b/skel/Desktop/simulated-drone/sim_drone.py deleted file mode 100755 index ba77554..0000000 --- a/skel/Desktop/simulated-drone/sim_drone.py +++ /dev/null @@ -1,229 +0,0 @@ -#!/bin/env python3 -import typer -import os -import sys -import contextlib -import pathlib -import time -import functools -from typing import List -from loguru import logger -import sh -import atexit - -logger.remove() -logger.add( - sys.stdout, format="{time} {level} {extra} {message}" -) - -px4Path = os.environ.get("SPIRI_SIM_PX4_PATH", "/opt/spiri-sdk/PX4-Autopilot/") -logger.info(f"SPIRI_SIM_PX4_PATH={px4Path}") - -app = typer.Typer() - -# This is a list of processes that we need to .kill and .wait for on exit -processes = [] - - -class outputLogger: - """ - Logs command output to loguru - """ - - def __init__(self, name, instance): - self.name = name - self.instance = instance - - def __call__(self, message): - with logger.contextualize(cmd=self.name, instance=self.instance): - if message.endswith("\n"): - message = message[:-1] - # ToDo, this doesn't work because the output is coloured - if message.startswith("INFO"): - message = message.lstrip("INFO") - logger.info(message) - elif message.startswith("WARN"): - message = message.lstrip("WARN") - logger.warning(message) - elif message.startswith("ERROR"): - message = message.lstrip("ERROR") - logger.error(message) - elif message.startswith("DEBUG"): - message = message.lstrip("DEBUG") - logger.debug(message) - else: - logger.info(message) - - -@contextlib.contextmanager -def modified_environ(*remove, **update): - """ - Temporarily updates the ``os.environ`` dictionary in-place. - - The ``os.environ`` dictionary is updated in-place so that the modification - is sure to work in all situations. - - :param remove: Environment variables to remove. - :param update: Dictionary of environment variables and values to add/update. - """ - env = os.environ - update = update or {} - remove = remove or [] - - # List of environment variables being updated or removed. - stomped = (set(update.keys()) | set(remove)) & set(env.keys()) - # Environment variables and values to restore on exit. - update_after = {k: env[k] for k in stomped} - # Environment variables and values to remove on exit. - remove_after = frozenset(k for k in update if k not in env) - - try: - env.update(update) - [env.pop(k, None) for k in remove] - yield - finally: - env.update(update_after) - [env.pop(k) for k in remove_after] - - -def wait_for_gazebo(timeout=60, interval=1): - start_time = time.time() - while time.time() - start_time < timeout: - try: - # Run the 'gz topic list' command - topics = sh.gz("topic", "-l").strip() - if topics: - logger.info("Gazebo Ignition is running.") - return True - except sh.ErrorReturnCode: - # If the command fails, Gazebo might not be running yet - pass - logger.info( - f"Gazebo Ignition is not running. Retrying in {interval} seconds..." - ) - time.sleep(interval) - - logger.error("Timeout reached. Gazebo Ignition is not running.") - return False - - -def wait_for_docker_on_port(port, timeout=60, interval=1): - start_time = time.time() - while time.time() - start_time < timeout: - try: - # Check if there's a working docker daemon listening at port - with modified_environ(DOCKER_HOST=f"tcp://localhost:{port}"): - sh.docker("version") - except sh.ErrorReturnCode: - # If the command fails, Gazebo might not be running yet - pass - logger.info(f"Docker port is not running. Retrying in {interval} seconds...") - time.sleep(interval) - logger.error("Timeout reached. Docker port is not running.") - return False - - -@app.command() -def start(sys_id: int = 1, extra_apps: List[pathlib.Path] = []): - """Starts the simulated drone with a given sys_id, - each drone must have it's own unique ID. - """ - if sys_id < 1 or sys_id > 254: - logger.error("sys_id must be between 1 and 254") - raise typer.Exit(code=1) - with logger.contextualize(syd_id=sys_id): - DOCKER_INSTANCE = (str(2375 + sys_id),) - with modified_environ( - # PX4_SIM_MODEL=os.environ.get("PX4_SIM_MODEL") or "gz_x500", - # ToDo: pose is not passed to gazebo classic - PX4_GZ_MODEL_POSE=os.environ.get("PX4_GZ_MODEL_POSE") or f"0,{(sys_id-1)}", - PX4_INSTANCE="intance_id", - DOCKER_INSTANCE=DOCKER_INSTANCE, - ROS_MASTER_PORT=str(11310 + sys_id), - MAVROS_SIM_GCS_PORT=str(14556 + sys_id), - MAVROS_SIM_FCU_PORT=str(14539 + sys_id), - DRONE_SYS_ID=str(sys_id), - ): - logger.info("Starting drone simulation") - # Run the make px4_sitl gazebo-classic command - px4_command = sh.make( - "px4_sitl", - "gazebo-classic_mu", - _bg=True, - _out=outputLogger("px4", sys_id), - _cwd=px4Path, - ) - processes.append(px4_command) - logger.info("Starting drone docker instance") - # Here we start a docker-in-docker instance with the DOCKER_INSTANCE port exposed to localhost - dockerinstance = sh.docker( - "run", - "--privileged", - "--name", - f"simulated_robot_{sys_id}_docker", - "-p", - f"localhost:{DOCKER_INSTANCE}:{DOCKER_INSTANCE}", - # Run the docker command in forground to capture the output - "docker:dind", - _bg=True, - _out=outputLogger("docker", sys_id), - ) - processes.append(dockerinstance) - # Wait for the docker daemon to start - logger.info(f"Waiting for docker daemon on port {DOCKER_INSTANCE}") - wait_for_docker_on_port(DOCKER_INSTANCE) - - logger.info("Starting drone stack, this may take some time") - docker_stack = sh.docker.compose( - "--project-name", - f"simulated_robot_{sys_id}", - "up", - _out=outputLogger("docker_stack", sys_id), - _err=sys.stderr, - _bg=True, - ) - processes.append(docker_stack) - for extra_app in extra_apps: - logger.info(f"Starting app {extra_app}, this may take some time") - app_name = extra_app.stem - app_stack = sh.docker.compose( - "--project-name", - f"simulated_robot_{sys_id}_{app_name}", - "up", - _out=outputLogger(app_name, sys_id), - _err=sys.stderr, - _bg=True, - ) - processes.append(app_stack) - - -@app.command() -def start_group( - count: int = typer.Argument(min=1, max=10), extra_apps: List[pathlib.Path] = [] -): - """Start a group of robots""" - for i in range(count): - logger.info(f"start robot {i}") - start(sys_id=i + 1, extra_apps=extra_apps) - if i == 0: - wait_for_gazebo() - - -def cleanup(): - # Wait for all subprocesses to exit - logger.info("Waiting for commands to exit") - print(processes) - for waitable in processes: - waitable.kill() - waitable.wait() - - -atexit.register(cleanup) - -if __name__ == "__main__": - try: - app() - except KeyboardInterrupt: - logger.info("KeyboardInterrupt caught, exiting...") - cleanup() - sys.exit(0) diff --git a/virtualize.sh b/virtualize.sh deleted file mode 100755 index f729386..0000000 --- a/virtualize.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -# Function to extract the output file from arguments -extract_output_file() { - while [[ $# -gt 0 ]]; do - key="$1" - case $key in - -o | --output) - output_file="$2" - shift # past argument - shift # past value - ;; - *) - shift # past argument - ;; - esac - done -} - -# Extract the -o argument -extract_output_file "$@" - -# Run the docker command -#docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock --privileged -v "$PWD":/d2vm -w /d2vm vmutil "$@" -docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock --privileged -v "$PWD":/d2vm -w /d2vm git.spirirobotics.com/spiri/utils-docker_to_ovf:2024-05-21 "$@" - -# Change the ownership of the output file to the current user -if [[ -n "$output_file" ]]; then - echo "Setting permissions on file" - sudo chown $(whoami) "$output_file" -fi