2024-11-06 15:44:18 -04:00
|
|
|
from nicegui import ui, binding, app, run
|
2024-09-19 14:14:07 -03:00
|
|
|
import subprocess
|
2024-11-05 14:49:32 -04:00
|
|
|
from collections import defaultdict
|
2024-11-06 12:58:14 -04:00
|
|
|
import docker
|
|
|
|
import time
|
|
|
|
|
|
|
|
docker_client = docker.from_env()
|
2024-09-19 14:14:07 -03:00
|
|
|
|
|
|
|
# Dictionary of applications: key is the button text, value is the command to execute
|
|
|
|
applications = {
|
2024-11-05 11:22:15 -04:00
|
|
|
"Terminal": ["qterminal"],
|
|
|
|
"rqt": ["rqt"],
|
|
|
|
"rviz2": ["rviz2"],
|
2024-11-07 13:09:37 -04:00
|
|
|
"Gazebo": ["/gz_entrypoint.sh"],
|
2024-11-05 11:22:15 -04:00
|
|
|
"Gazebo Standalone": "gz sim -v4".split(),
|
2024-09-19 14:14:07 -03:00
|
|
|
# Add more applications here if needed
|
|
|
|
}
|
|
|
|
|
|
|
|
# Function to launch an application
|
|
|
|
def launch_app(command):
|
|
|
|
try:
|
|
|
|
subprocess.Popen(command)
|
|
|
|
except FileNotFoundError:
|
2024-11-05 10:29:34 -04:00
|
|
|
print(f"{command[0]} not found. Make sure it's installed and accessible in the PATH.")
|
2024-09-19 14:14:07 -03:00
|
|
|
|
2024-11-05 10:29:34 -04:00
|
|
|
# Create the NiceGUI interface
|
2024-11-05 11:22:15 -04:00
|
|
|
ui.label("Spiri Robotics SDK").style('font-size: 40px; margin-bottom: 10px;').classes('w-full text-center')
|
2024-09-19 14:33:29 -03:00
|
|
|
|
2024-11-05 14:49:32 -04:00
|
|
|
robots = []
|
|
|
|
from spiri_sdk_guitools.sim_drone import Robot
|
2024-11-06 15:44:18 -04:00
|
|
|
import aiodocker
|
|
|
|
import asyncio
|
2024-11-06 12:58:14 -04:00
|
|
|
|
2024-11-05 14:49:32 -04:00
|
|
|
@ui.page('/')
|
2024-11-06 15:44:18 -04:00
|
|
|
async def main():
|
2024-11-05 14:49:32 -04:00
|
|
|
with ui.tabs().classes('w-full') as tabs:
|
|
|
|
tab_tools = ui.tab('Tools')
|
|
|
|
tab_robots = ui.tab('Robots')
|
|
|
|
# two = ui.tab('Two')
|
2024-11-06 12:58:14 -04:00
|
|
|
with ui.tab_panels(tabs, value=tab_tools).classes("w-full"):
|
2024-11-05 14:49:32 -04:00
|
|
|
with ui.tab_panel(tab_tools):
|
|
|
|
# Create and place buttons dynamically based on the dictionary
|
|
|
|
with ui.grid(columns=3):
|
|
|
|
for app_name, command in applications.items():
|
|
|
|
ui.button(app_name, on_click=lambda cmd=command: launch_app(cmd)).style('width: 150px; height: 50px; margin: 5px;')
|
|
|
|
with ui.tab_panel(tab_robots):
|
2024-11-06 16:40:07 -04:00
|
|
|
new_robot_widget = ui.element().classes("w-1/2")
|
|
|
|
with ui.element().classes("w-1/2"):
|
2024-11-07 12:18:53 -04:00
|
|
|
ui.label("Debug").classes("text-xl")
|
2024-11-06 12:58:14 -04:00
|
|
|
def cleanup_all_containers():
|
|
|
|
#Find all containers that start with spiri-sdk
|
|
|
|
containers = docker_client.containers.list(all=True)
|
|
|
|
removal_count = 0
|
|
|
|
for container in containers:
|
|
|
|
if container.name.startswith("robot-sim-"):
|
|
|
|
container.remove(force=True)
|
|
|
|
removal_count += 1
|
|
|
|
ui.label(f"Removed {removal_count} containers")
|
|
|
|
ui.button("Cleanup all containers", on_click=cleanup_all_containers)
|
|
|
|
|
|
|
|
ui.separator()
|
2024-11-07 12:18:53 -04:00
|
|
|
ui.label("Current robots").classes("text-3xl")
|
2024-11-06 15:59:04 -04:00
|
|
|
robots_widget = ui.element().classes("w-full")
|
2024-11-06 15:44:18 -04:00
|
|
|
|
|
|
|
#Add a new robot
|
|
|
|
with new_robot_widget:
|
2024-11-07 12:18:53 -04:00
|
|
|
ui.label("Add new robot").classes("text-3xl")
|
2024-11-06 15:44:18 -04:00
|
|
|
newRobotParams = defaultdict(binding.BindableProperty)
|
|
|
|
ui.number(value=1, label="SysID", min=1, max=254,
|
|
|
|
).bind_value(newRobotParams, 'sysid')
|
2024-11-14 11:46:00 -04:00
|
|
|
default_robot_compose = (
|
|
|
|
"/robots/spiri-mu/core/docker-compose.yaml\n"
|
2024-11-15 12:52:27 -04:00
|
|
|
"#/robots/spiri-mu/virtual_camera/docker-compose.yaml --build"
|
2024-11-14 11:46:00 -04:00
|
|
|
)
|
|
|
|
ui.label("Compose files").classes("text-xl")
|
|
|
|
ui.codemirror(value=default_robot_compose, language="bash", theme="basicDark").bind_value(newRobotParams, 'compose_files')
|
2024-11-06 15:44:18 -04:00
|
|
|
async def new_robot():
|
2024-11-14 11:46:00 -04:00
|
|
|
compose_files = []
|
|
|
|
#Split on comma or newline, and remove comments
|
|
|
|
for line in newRobotParams['compose_files'].split('\n'):
|
|
|
|
line = line.split('#')[0].strip()
|
|
|
|
if line:
|
|
|
|
compose_files.append(line)
|
|
|
|
current_robot = newRobotParams.copy()
|
|
|
|
current_robot['compose_files'] = compose_files
|
|
|
|
robot = Robot(**current_robot)
|
2024-11-06 15:44:18 -04:00
|
|
|
asyncio.tasks.create_task(robot.ui(robots_widget))
|
|
|
|
|
|
|
|
newRobotParams['sysid'] += 1
|
|
|
|
ui.button("Add", on_click=new_robot)
|
|
|
|
|
2024-11-05 10:29:34 -04:00
|
|
|
# Start the NiceGUI application
|
|
|
|
ui.run(title="Spiri SDK Launcher", port=8923, dark=None)
|