Skip to content

Commit 28354a1

Browse files
authored
Merge pull request #191 from JdeRobot/add-visualization-config
Add visualization config
2 parents ed6abae + 98f80ec commit 28354a1

9 files changed

Lines changed: 118 additions & 16 deletions

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ The `Manager` class is the core of RAM, orchestrating operations and managing tr
3939
- `terminate`: Stops the application and goes back to `visualization_ready`.
4040
- `stop`: Completely stops the application.
4141
- `disconnect`: Disconnects from the current session and returns to `idle`.
42+
- **Stateless Transitions**:
43+
- `style_check`: Triggers on_style_check.
44+
- `code_analysis`: Triggers on_code_analysis.
45+
- `code_format`: Triggers on_code_format.
46+
- `code_autocomplete`: Triggers on_code_autocomplete.
4247

4348
### Key Methods
4449

@@ -50,6 +55,10 @@ The `Manager` class is the core of RAM, orchestrating operations and managing tr
5055
- `on_resume(self, msg)`: Resumes the paused application.
5156
- `on_terminate(self, event)`: Terminates the running application.
5257
- `on_disconnect(self, event)`: Handles disconnection and cleanup.
58+
- `on_style_check(self, event)`: Check the style of the user code.
59+
- `on_code_analysis(self, event)`: Analyzes the style and format of the user code using pylint.
60+
- `on_code_format(self, event)`: Formats the user code using black.
61+
- `on_code_autocomplete(self, event)`: Searches for all available code completions using Jedi.
5362
- **Exception Handling**: Details how specific errors are managed in each method.
5463

5564
### Interactions with Other Components

manager/manager/launcher/launcher_console.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class LauncherConsole(ILauncher):
1515
threads: List[Any] = []
1616
console_vnc: Any = Vnc_server()
1717

18-
def run(self, callback):
18+
def run(self, config_file, callback):
1919
DRI_PATH = self.get_dri_path()
2020
ACCELERATION_ENABLED = False
2121

manager/manager/launcher/launcher_gazebo_view.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class LauncherGazeboView(ILauncher):
2222
threads: List[Any] = []
2323
gz_vnc: Any = Vnc_server()
2424

25-
def run(self, callback):
25+
def run(self, config_file, callback):
2626
DRI_PATH = self.get_dri_path()
2727
ACCELERATION_ENABLED = self.check_device(DRI_PATH)
2828

manager/manager/launcher/launcher_gzsim_view.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,28 @@ class LauncherGzsimView(ILauncher):
2222
threads: List[Any] = []
2323
gz_vnc: Any = Vnc_server()
2424

25-
def run(self, callback):
25+
def run(self, config_file, callback):
2626
DRI_PATH = self.get_dri_path()
2727
ACCELERATION_ENABLED = self.check_device(DRI_PATH)
2828

29+
if config_file is None:
30+
config_file = "/opt/jderobot/Launchers/visualization/default.config"
31+
2932
# Configure browser screen width and height for gz GUI
30-
gzclient_config_cmds = f"sed -i 's/<width>.*<\/width>/<width>{self.width}<\/width>/; s/<height>.*<\/height>/<height>{self.height}<\/height>/' /opt/jderobot/Launchers/sim_config/gui.config;"
33+
gzclient_config_cmds = f"sed -i 's/<width>.*<\/width>/<width>{self.width}<\/width>/; s/<height>.*<\/height>/<height>{self.height}<\/height>/' {config_file};"
3134

3235
if ACCELERATION_ENABLED:
3336
# Starts xserver, x11vnc and novnc
3437
self.gz_vnc.start_vnc_gpu(
3538
self.display, self.internal_port, self.external_port, DRI_PATH
3639
)
3740
# Write display config and start gzclient
38-
gzclient_cmd = f"export DISPLAY={self.display}; {gzclient_config_cmds} export VGL_DISPLAY={DRI_PATH}; vglrun gz sim -g -v4 --gui-config /opt/jderobot/Launchers/sim_config/gui.config"
41+
gzclient_cmd = f"export DISPLAY={self.display}; {gzclient_config_cmds} export VGL_DISPLAY={DRI_PATH}; vglrun gz sim -g -v4 --gui-config {config_file}"
3942
else:
4043
# Starts xserver, x11vnc and novnc
4144
self.gz_vnc.start_vnc(self.display, self.internal_port, self.external_port)
4245
# Write display config and start gzclient
43-
gzclient_cmd = f"export DISPLAY={self.display}; {gzclient_config_cmds} gz sim -g -v4 --gui-config /opt/jderobot/Launchers/sim_config/gui.config"
46+
gzclient_cmd = f"export DISPLAY={self.display}; {gzclient_config_cmds} gz sim -g -v4 --gui-config {config_file}"
4447

4548
gzclient_thread = DockerThread(gzclient_cmd)
4649
gzclient_thread.start()

manager/manager/launcher/launcher_robot.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"2": [
1919
{
2020
"type": "module",
21-
"module": "ros2_api",
21+
"module": "robot_ros2_api",
2222
"parameters": [],
2323
"launch_file": [],
2424
}
@@ -71,8 +71,11 @@ class LauncherRobot(BaseModel):
7171
module: str = ".".join(__name__.split(".")[:-1])
7272
ros_version: int = get_ros_version()
7373
launchers: Optional[ILauncher] = []
74+
start_pose: Optional[list] = []
7475

75-
def run(self):
76+
def run(self, start_pose = None):
77+
if (start_pose != None):
78+
self.start_pose = start_pose
7679
for module in worlds[self.world][str(self.ros_version)]:
7780
module["launch_file"] = self.launch_file_path
7881
launcher = self.launch_module(module)
@@ -98,7 +101,8 @@ def process_terminated(name, exit_code):
98101
launcher_module = f"{self.module}.launcher_{launcher_module_name}.Launcher{class_from_module(launcher_module_name)}"
99102
launcher_class = get_class(launcher_module)
100103
launcher = launcher_class.from_config(launcher_class, configuration)
101-
launcher.run(process_terminated)
104+
105+
launcher.run(self.start_pose, process_terminated)
102106
return launcher
103107

104108
def launch_command(self, configuration):

manager/manager/launcher/launcher_robot_display_view.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class LauncherRobotDisplayView(ILauncher):
1515
running = False
1616
threads = []
1717

18-
def run(self, callback):
18+
def run(self, config_file, callback):
1919
DRI_PATH = self.get_dri_path()
2020
ACCELERATION_ENABLED = self.check_device(DRI_PATH)
2121

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import os
2+
from typing import List, Any
3+
import time
4+
import stat
5+
6+
from manager.manager.launcher.launcher_interface import ILauncher, LauncherException
7+
from manager.manager.docker_thread.docker_thread import DockerThread
8+
import subprocess
9+
10+
import logging
11+
12+
13+
class LauncherRobotRos2Api(ILauncher):
14+
type: str
15+
module: str
16+
launch_file: str
17+
threads: List[Any] = []
18+
19+
def run(self, robot_pose, callback):
20+
DRI_PATH = self.get_dri_path()
21+
ACCELERATION_ENABLED = self.check_device(DRI_PATH)
22+
23+
logging.getLogger("roslaunch").setLevel(logging.CRITICAL)
24+
25+
xserver_cmd = f"/usr/bin/Xorg -quiet -noreset +extension GLX +extension RANDR +extension RENDER -logfile ./xdummy.log -config ./xorg.conf :0"
26+
xserver_thread = DockerThread(xserver_cmd)
27+
xserver_thread.start()
28+
self.threads.append(xserver_thread)
29+
30+
ROBOT_POSE = f"ROBOT_X={robot_pose[0]} ROBOT_Y={robot_pose[1]} ROBOT_Z={robot_pose[2]} ROBOT_ROLL={robot_pose[3]} ROBOT_PITCH={robot_pose[4]} ROBOT_YAW={robot_pose[5]}"
31+
32+
if ACCELERATION_ENABLED:
33+
exercise_launch_cmd = (
34+
f"export VGL_DISPLAY={DRI_PATH}; vglrun {ROBOT_POSE} ros2 launch {self.launch_file}"
35+
)
36+
else:
37+
exercise_launch_cmd = f"{ROBOT_POSE} ros2 launch {self.launch_file}"
38+
39+
exercise_launch_thread = DockerThread(exercise_launch_cmd)
40+
exercise_launch_thread.start()
41+
42+
def terminate(self):
43+
if self.threads is not None:
44+
for thread in self.threads:
45+
if thread.is_alive():
46+
thread.terminate()
47+
thread.join()
48+
self.threads.remove(thread)
49+
50+
kill_cmd = "pkill -9 -f "
51+
cmd = kill_cmd + "spawn_robot.launch.py"
52+
subprocess.call(
53+
cmd,
54+
shell=True,
55+
stdout=subprocess.PIPE,
56+
bufsize=1024,
57+
universal_newlines=True,
58+
)
59+
60+
kill_cmd = "pkill -9 "
61+
cmd = kill_cmd + "bridg"
62+
subprocess.call(
63+
cmd,
64+
shell=True,
65+
stdout=subprocess.PIPE,
66+
bufsize=1024,
67+
universal_newlines=True,
68+
)
69+
70+
cmd = kill_cmd + "robot_state_publisher"
71+
subprocess.call(
72+
cmd,
73+
shell=True,
74+
stdout=subprocess.PIPE,
75+
bufsize=1024,
76+
universal_newlines=True,
77+
)
78+

manager/manager/launcher/launcher_visualization.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@
184184
class LauncherVisualization(BaseModel):
185185
module: str = ".".join(__name__.split(".")[:-1])
186186
visualization: str
187+
visualization_config_path: str
187188
launchers: Optional[ILauncher] = []
188189

189190
def run(self):
@@ -210,7 +211,7 @@ def process_terminated(name, exit_code):
210211
launcher_module = f"{self.module}.launcher_{launcher_module_name}.Launcher{class_from_module(launcher_module_name)}"
211212
launcher_class = get_class(launcher_module)
212213
launcher = launcher_class.from_config(launcher_class, configuration)
213-
launcher.run(process_terminated)
214+
launcher.run(self.visualization_config_path, process_terminated)
214215
return launcher
215216

216217
def launch_command(self, configuration):

manager/manager/manager.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ def on_launch_world(self, event):
286286

287287
self.robot_launcher = LauncherRobot(**cfg.model_dump())
288288
LogManager.logger.info(str(self.robot_launcher))
289-
self.robot_launcher.run()
289+
self.robot_launcher.run(robot_cfg['start_pose'])
290290
LogManager.logger.info("Launch transition finished")
291291

292292
def prepare_custom_universe(self, cfg_dict):
@@ -313,10 +313,15 @@ def on_prepare_visualization(self, event):
313313

314314
LogManager.logger.info("Visualization transition started")
315315

316-
self.visualization_type = event.kwargs.get("data", {})
316+
cfg_dict = event.kwargs.get("data", {})
317+
self.visualization_type = cfg_dict['type']
318+
config_file = cfg_dict['file']
319+
317320
self.visualization_launcher = LauncherVisualization(
318-
visualization=self.visualization_type
321+
visualization=self.visualization_type,
322+
visualization_config_path = config_file
319323
)
324+
320325
self.visualization_launcher.run()
321326

322327
if self.visualization_type in ["gazebo_rae", "gzsim_rae"]:
@@ -801,6 +806,9 @@ def unpause_sim(self):
801806
self.call_service("/unpause_physics", "std_srvs/srv/Empty")
802807

803808
def reset_sim(self):
809+
if self.robot_launcher:
810+
self.robot_launcher.terminate()
811+
804812
if self.visualization_type in ["gzsim_rae", "bt_studio_gz"]:
805813
if self.is_ros_service_available("/drone0/platform/state_machine/_reset"):
806814
self.call_service("/drone0/platform/state_machine/_reset", "std_srvs/srv/Trigger", "{}")
@@ -809,10 +817,9 @@ def reset_sim(self):
809817
self.call_service("/drone0/controller/_reset", "std_srvs/srv/Trigger", "{}")
810818
else:
811819
self.call_service("/reset_world", "std_srvs/srv/Empty")
812-
820+
813821
if self.robot_launcher:
814822
try:
815-
self.robot_launcher.terminate()
816823
self.robot_launcher.run()
817824
except Exception as e:
818825
LogManager.logger.exception("Exception terminating world launcher")

0 commit comments

Comments
 (0)