diff --git a/guiTools/spiri_sdk_guitools/launcher.py b/guiTools/spiri_sdk_guitools/launcher.py index 918f2cb..53e6082 100644 --- a/guiTools/spiri_sdk_guitools/launcher.py +++ b/guiTools/spiri_sdk_guitools/launcher.py @@ -70,7 +70,7 @@ async def main(): ).bind_value(newRobotParams, 'sysid') default_robot_compose = ( "/robots/spiri-mu/core/docker-compose.yaml\n" - "#/robots/spiri-mu/virtual_camera/docker-compose.yaml" + "#/robots/spiri-mu/virtual_camera/docker-compose.yaml --build" ) ui.label("Compose files").classes("text-xl") ui.codemirror(value=default_robot_compose, language="bash", theme="basicDark").bind_value(newRobotParams, 'compose_files') diff --git a/guiTools/spiri_sdk_guitools/sim_drone.py b/guiTools/spiri_sdk_guitools/sim_drone.py index c7f3d2b..b46b15d 100644 --- a/guiTools/spiri_sdk_guitools/sim_drone.py +++ b/guiTools/spiri_sdk_guitools/sim_drone.py @@ -6,6 +6,7 @@ import os import sh import subprocess from nicegui import ui, run, app +import yaml import docker import aiodocker @@ -96,38 +97,47 @@ class Robot: container_status = {} with element: while True: - # Poll for data that changes - for container in self.containers(): - try: - health = container.attrs["State"]["Health"]["Status"] - except KeyError: - health = "Unknown" + with logger.catch(): + # Poll for data that changes + for container in self.containers(): + try: + health = container.attrs["State"]["Health"]["Status"] + except KeyError: + health = "Unknown" - container_status[container] = ( - f"{container.name} {container.status} {health}" - ) - if container not in docker_elements: - docker_elements[container] = ui.element().classes("w-full") - with docker_elements[container]: - ui.label().bind_text(container_status, container).classes( - "text-lg" - ) - #Show the command the container is running - # ui.label(container.attrs["Config"]["Cmd"]) - cmd_widget = ui.codemirror(" ".join(container.attrs["Config"]["Cmd"]), language="bash",theme="basicDark").classes('h-auto max-h-32') - cmd_widget.enabled = False - logelement = ( - ui.expansion("Logs") - .style("margin: 10px;") - .classes("w-full outline outline-1") - ) - asyncio.create_task(container_logs(container, logelement)) - # Check for containers that have been removed - removed = set(docker_elements.keys()) - set(self.containers()) - for container in removed: - self.robot_ui.remove(docker_elements[container]) - docker_elements.pop(container) - await asyncio.sleep(1) + container_status[container] = ( + f"{container.name} {container.status} {health}" + ) + if container not in docker_elements: + docker_elements[container] = ui.element().classes("w-full") + with docker_elements[container]: + ui.label().bind_text(container_status, container).classes( + "text-2xl" + ) + #Show the command the container is running + # ui.label(container.attrs["Config"]["Cmd"]) + cmd_widget = ui.codemirror(" ".join(container.attrs["Config"]["Cmd"]), language="bash",theme="basicDark").classes('h-auto max-h-32') + cmd_widget.enabled = False + + with ui.expansion("Env Variables").classes("w-full outline outline-1").style("margin: 10px;"): + env_widget = ui.codemirror("\n".join(container.attrs["Config"]["Env"]), language="bash",theme="basicDark") + env_widget.enabled = False + + logelement = ( + ui.expansion("Logs") + .style("margin: 10px;") + .classes("w-full outline outline-1") + ) + asyncio.create_task(container_logs(container, logelement)) + with ui.expansion("Full details").classes("w-full outline outline-1").style("margin: 10px;"): + details_widget = ui.codemirror(yaml.dump(container.attrs), language="yaml",theme="basicDark") + details_widget.enabled = False + # Check for containers that have been removed + removed = set(docker_elements.keys()) - set(self.containers()) + for container in removed: + self.robot_ui.remove(docker_elements[container]) + docker_elements.pop(container) + await asyncio.sleep(1) async def ui_ros(self, element): with element: @@ -138,7 +148,7 @@ class Robot: scroll_area.clear() #Filter for topics that start with self.robot_name for topic in node_dummy.get_topic_names_and_types(): - if topic[0].startswith(f"/{self.robot_name}/") or topic[0].startswith(f"/world/{self.world_name}/model/{self.robot_name}/"): + if self.robot_name in topic[0]: ui.label(topic[0]) await asyncio.sleep(10) @@ -221,6 +231,11 @@ class Robot: self.spawn_gz_model() logger.info("Starting drone stack, this may take some time") for compose_file in self.compose_files: + arguments = compose_file.split(" ") + arguments = [arg.strip() for arg in arguments] + compose_file = arguments[0] + arguments = arguments[1:] + if not isinstance(compose_file, Path): compose_file = Path(compose_file) if not compose_file.exists(): @@ -236,15 +251,17 @@ class Robot: "-f", compose_file.as_posix(), "up", + *arguments, ] command = " ".join(args) logger.info(f"Starting drone stack with command: {command}") docker_stack = subprocess.Popen( args, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + # stdout=subprocess.PIPE, + # stderr=subprocess.PIPE, ) + logger.info(f"Started drone stack with PID: {docker_stack.pid}") @logger.catch def spawn_gz_model(self): diff --git a/robots/spiri-mu/virtual_camera/Dockerfile b/robots/spiri-mu/virtual_camera/Dockerfile index ffbfbdc..69bb0af 100644 --- a/robots/spiri-mu/virtual_camera/Dockerfile +++ b/robots/spiri-mu/virtual_camera/Dockerfile @@ -1,5 +1,8 @@ FROM git.spirirobotics.com/spiri/services-ros2-mavros:main RUN apt-get update -RUN apt-get --yes install ros-${ROS_DISTRO}-ros-gz-bridge ros-${ROS_DISTRO}-compressed-image-transport ros-${ROS_DISTRO}-rmw-cyclonedds-cpp +RUN apt-get --yes install ros-${ROS_DISTRO}-ros-gz-bridge \ + ros-${ROS_DISTRO}-ros-gz-image \ + ros-${ROS_DISTRO}-compressed-image-transport \ + ros-${ROS_DISTRO}-rmw-cyclonedds-cpp diff --git a/robots/spiri-mu/virtual_camera/docker-compose.yaml b/robots/spiri-mu/virtual_camera/docker-compose.yaml index 1969fd3..5a4bcf7 100644 --- a/robots/spiri-mu/virtual_camera/docker-compose.yaml +++ b/robots/spiri-mu/virtual_camera/docker-compose.yaml @@ -4,7 +4,10 @@ services: ipc: host network_mode: host # image: git.spirirobotics.com/spiri/services-ros2-mavros:main + #Build the iamge, give it a name, don't try to pull the image build: ./ + image: spirisdk-virtual_camera + pull_policy: never environment: - RMW_IMPLEMENTATION=rmw_cyclonedds_cpp - command: ros2 run ros_gz_image image_bridge /world/${WORLD_NAME}/model/${ROBOT_NAME}/link/pitch_link/sensor/camera/image \ No newline at end of file + command: ros2 run ros_gz_image image_bridge /world/${WORLD_NAME}/model/${ROBOT_NAME}/link/pitch_link/sensor/camera/image