diff --git a/Dockerfile b/Dockerfile index ded1564..07fab0a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get clean RUN apt-get update && apt-get upgrade --yes #RUN apt-get install --yes gz-garden -RUN apt-get remove gz-garden +RUN apt-get remove gz-garden mutter RUN apt-get install --yes ros-noetic-desktop gazebo11 libgazebo11 libgazebo11-dev #Install ROS diff --git a/README.md b/README.md index 7c1bf20..426e6bb 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,3 @@ -# Ways of running +New SDK -There are two main ways of running this software. - -Most users are recomended to install [VirtualBox](https://www.virtualbox.org/), create a new -VM, and use the supplied VDI as the disk image. You will likely want -to increase memory limits and CPU count above the default. - -Advanced users can also use the SDK as a docker image. It pairs well with -[distrobox](https://github.com/89luca89/distrobox) to better -integrate it with their existing linux workflows. - -```bash -distrobox create --image git.spirirobotics.com/spiri/spiri-sdk-desktop:master -distrobox enter spiri-sdk-desktop-master - -cp -r /opt/spiri-sdk/user-home-skeleton/* ~/ -cd ~/Desktop/simulated-drone/ -./sim_drone.py launch -``` - -# Usage - -Each drone has it's own ros master, you can specify a ros master by adding a sys_id to your port - -To launch the drone, run the command `sim_drone.py start-group 2`. For more detailed information user -the `--help` command. You must run the command from inside a folder with a compliant dockerfile. - -If using the VM there should be one on your desktop, if not you can run `cp -r /opt/spiri-sdk/user-home-skeleton/ ~/` -and all relevent development resources will be added to your home folder. - -```bash -ROS_MASTER_URI=http://localhost:11311 rostopic list #Drone with sys_id 1 -ROS_MASTER_URI=http://localhost:11312 rostopic list #Drone with sys_id 2 -``` - -# Building - -```bash -#Note that because this is running in a container, the -o output flag must be relative to the current directory. -# We mount the current working directory in the docker container as part of this script. -./virtualize.sh build ./ -s 100gb -o sdk.vdi -``` - -For testing the VM, I use the following - -```bash -./virtualize.sh build ./ -s 100gb -o sdk.qcow2 -qemu-system-x86_64 -display default,show-cursor=on -enable-kvm -device virtio-gpu -m 4g -smp 4 -hda sdk.qcow2 -``` +toDo, usage instructions diff --git a/skel/Desktop/simulated-drone/sim_drone.py b/skel/Desktop/simulated-drone/sim_drone.py index 1968f72..ba77554 100755 --- a/skel/Desktop/simulated-drone/sim_drone.py +++ b/skel/Desktop/simulated-drone/sim_drone.py @@ -107,22 +107,44 @@ def wait_for_gazebo(timeout=60, interval=1): 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", @@ -132,6 +154,25 @@ def start(sys_id: int = 1, extra_apps: List[pathlib.Path] = []): _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",