diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7944dc3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,164 @@ +influxdb.conf/ +influxdb2/ +config.yaml/ +.vscode +temp.py +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/assets/swarmbots-graphic.png b/assets/swarmbots-graphic.png new file mode 100644 index 0000000..a0974c5 Binary files /dev/null and b/assets/swarmbots-graphic.png differ diff --git a/assets/swarmbots-graphic_.png b/assets/swarmbots-graphic_.png new file mode 100644 index 0000000..ebc3041 Binary files /dev/null and b/assets/swarmbots-graphic_.png differ diff --git a/gui.py b/gui.py new file mode 100644 index 0000000..24a9042 --- /dev/null +++ b/gui.py @@ -0,0 +1,138 @@ +from nicegui import ui +import os +import signal +import subprocess + + +TABS = ["Home", + "Simulation", + "Observers"] + +LAUNCH = [ + "ros2 launch multirobot_bringup multirobot_bringup.launch.xml", + "ros2 run multirobot_formation agent_formation_node", + "ros2 run multirobot_formation mock_test", + "ros2 run multirobot_formation resetPose",] + +OBSERVERS = [ + "ros2 run formation_error_observer main", + "ros2 run localization_error_observer localization_error_observer 4", + "ros2 run mileage_observer main 10 4", + "ros2 run power_usage_observer main 4",] + +process = None +task = None + + +async def read_markdown_file(file_path): + with open(file_path, "r") as f: + markdown_content = f.read() + return markdown_content + +# Global variable to store the processes +ros2_processes = [] + +async def start_ros2_launch(ros_launch_command): + global ros2_processes + + try: + # Start the ROS 2 launch process + process = subprocess.Popen( + ros_launch_command, + shell=True, + cwd=os.path.dirname(os.path.abspath(__file__)), + preexec_fn=os.setsid # This is used to create a process group to enable sending signals to the entire group + ) + ros2_processes.append(process) + print(f"ROS 2 launch process started: {ros_launch_command}") + except Exception as e: + print(f"Error starting ROS 2 launch process: {str(e)}") + +async def stop_ros2_launch(): + global ros2_processes + + for process in ros2_processes: + try: + # Send the SIGINT signal to the entire process group to gracefully terminate ROS 2 launch + os.killpg(os.getpgid(process.pid), signal.SIGINT) + process.wait() # Wait for the process to finish + print(f"ROS 2 launch process terminated.") + except Exception as e: + print(f"Error stopping ROS 2 launch process: {str(e)}") + + ros2_processes = [] + +@ui.page('/') +def view(): + with ui.footer(value=True).style('background-color: #bd94ea') as footer: + ui.label( + 'SwarmBots @ Fraunhofer IPA 2023').classes('absolute-center items-center') + with ui.column().classes('w-full items-center'): + ui.label('SwarmBots Mission Controller').classes( + 'text-h2 mt-10').style('color: #bd94ea') + # ui.label('ROS 2 Demonstrator 326').classes('text-h4 my-2') + with ui.tabs().classes('w-1/2 justify-center').props('h2') as tabs: + for tab in TABS: + ui.tab(tab).classes('w-1/2 text-center').style('font-size: 20px;') + + with ui.tab_panels(tabs, value=TABS[1]): + with ui.tab_panel(TABS[0]): + # with ui.card().classes('mt-10 mb-1 w-96 h-96').style('width: 64vw; position: relative'): + with ui.row().classes('text-center'): + ui.label('') + ui.image('assets/swarmbots-graphic.png').classes('mt-10 mb-1 w-96 h-96').style('width: 50vw; position: relative') + + with ui.tab_panel(TABS[1]): + with ui.card().classes('mt-10 mb-1 w-96 h-56').style('width: 60vw; position: relative'): + with ui.row().classes('text-center'): + ui.label("").classes("text-h6 text-muted") + with ui.row(): + ui.button('Start Simulator', color='#9312fa', on_click=lambda: start_ros2_launch(LAUNCH[0])).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 items-center") + ui.button('Start Formation', color='#9312fa', on_click=lambda: start_ros2_launch(LAUNCH[1])).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 items-center") + + with ui.card().classes('mt-10 mb-1 w-96 h-56').style('width: 60vw; position: relative'): + with ui.row().classes('text-center'): + ui.label("").classes("text-h6 text-muted") + with ui.row(): + ui.button('Start Navigation', color='#9312fa', on_click=lambda: start_ros2_launch(LAUNCH[2])).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 items-center") + ui.button('Reset Robots', color='#9312fa', on_click=lambda: start_ros2_launch(LAUNCH[3])).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 items-center") + + with ui.card().classes('mt-10 mb-1 w-96 h-56').style('width: 60vw; position: relative'): + with ui.row().classes('text-center'): + ui.label("").classes("text-h6 text-muted") + with ui.row(): + ui.button('Stop Simulator', color='#cb5153', on_click=stop_ros2_launch).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 absolute-center") + + + with ui.tab_panel(TABS[2]): + ui.label("Select the property observer").classes( + "text-h4 my-2 text-center").style('color: #9312fa') + with ui.card().classes('mt-10 mb-1 w-96 h-56').style('width: 60vw; position: relative'): + with ui.row().classes('text-center'): + ui.label("").classes("text-h6 text-muted") + with ui.row(): + ui.button('Formation', color='#9312fa', on_click=lambda: start_ros2_launch(OBSERVERS[0])).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 justify-center") + + ui.button('Localization', color='#9312fa', on_click=lambda: start_ros2_launch(OBSERVERS[1])).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 justify-center") + + ui.button('Mileage', color='#9312fa', on_click=lambda: start_ros2_launch(OBSERVERS[3])).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 justify-center") + + ui.button('Power usage', color='#9312fa', on_click=lambda: start_ros2_launch(OBSERVERS[2])).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 justify-center") + + with ui.card().classes('mt-10 mb-1 w-96 h-56').style('width: 60vw; position: relative'): + with ui.row().classes('text-center'): + ui.label("").classes("text-h6 text-muted") + with ui.row(): + ui.button('Stop', color='#cb5153', on_click=stop_ros2_launch).style('color: white; font-size: 20px; padding: 20px 20px; border-radius: 50px;').classes("my-10 absolute-center") + + # with ui.tab_panel(TABS[3]): + # ui.label('Documentation').classes('text-h4 my-2 text-center').style('color: #25957b') + # markdown_content = read_markdown_file("multirobot_mission_control/static/docs.md") + # ui.markdown(markdown_content) + + + + +ui.run() + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..25d275b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +nicegui +uvicorn \ No newline at end of file diff --git a/static/docs.md b/static/docs.md new file mode 100644 index 0000000..54cf3f5 --- /dev/null +++ b/static/docs.md @@ -0,0 +1,18 @@ +# Multi Robot Formation for SwarmBot + +## 1. Bringup the multirobot simulation, Localization and Pathplanning +```` +ros2 launch multirobot_bringup multirobot_bringup.launch.xml +```` +## 2. Send pallet pose from rviz2 +```` +ros2 launch multirobot_formation formation_control.launch.py +```` +Number of agents vary from 1 to N, ``default value:=4`` + +## 3. To perform Localization error experiments +Run the launch files in 1 and 2 and then run the mock_test node. +``` +ros2 run multirobot_formation mock_test +``` +**Note:**- In case the mock test does not start, please provide a goal in the rviz. \ No newline at end of file