Skip to content

Commit 85b775a

Browse files
committed
Merge branch 'humble-devel' into testing
2 parents 1b54d5a + 965f115 commit 85b775a

15 files changed

+1151
-576
lines changed

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ The `Manager` class is the core of RAM, orchestrating operations and managing tr
3030
- `idle`: The initial state, waiting for a connection.
3131
- `connected`: Connected and ready to initiate processes.
3232
- `world_ready`: The world environment is set up and ready.
33-
- `visualization_ready`: Visualization tools are prepared and ready.
33+
- `tools_ready`: Tools are prepared and ready.
3434
- `application_running`: A robotic application is actively running.
3535
- `paused`: The application is paused.
3636
- **Transitions**:
3737
- `connect`: Moves from `idle` to `connected`.
3838
- `launch_world`: Initiates the world setup from `connected`.
39-
- `prepare_visualization`: Prepares the visualization tools in `world_ready`.
40-
- `run_application`: Starts the application in `visualization_ready` or `paused`.
39+
- `prepare_tools`: Prepares the tools in `world_ready`.
40+
- `run_application`: Starts the application in `tools_ready` or `paused`.
4141
- `pause`: Pauses the running application.
4242
- `resume`: Resumes a paused application.
43-
- `terminate`: Stops the application and goes back to `visualization_ready`.
43+
- `terminate`: Stops the application and goes back to `tools_ready`.
4444
- `stop`: Completely stops the application.
4545
- `disconnect`: Disconnects from the current session and returns to `idle`.
4646
- **Stateless Transitions**:
@@ -54,7 +54,7 @@ The `Manager` class is the core of RAM, orchestrating operations and managing tr
5454

5555
- `on_connect(self, event)`: Manages the transition to the 'connected' state.
5656
- `on_launch_world(self, event)`: Prepares and launches the robotic world.
57-
- `on_prepare_visualization(self, event)`: Sets up visualization tools.
57+
- `on_prepare_tools(self, event)`: Sets up tools.
5858
- `on_run_application(self, event)`: Executes the robotic application.
5959
- `on_pause(self, msg)`: Pauses the running application.
6060
- `on_resume(self, msg)`: Resumes the paused application.
@@ -84,13 +84,13 @@ The `Manager` class is the core of RAM, orchestrating operations and managing tr
8484
4. **Termination and Cleanup**: `Manager` can instruct `LauncherWorld` to terminate the world environment through its `terminate` method. `LauncherWorld` ensures a clean and orderly shutdown of all modules and resources involved in the world setup.
8585
5. **Error Handling and Logging**: `Manager` handles exceptions and errors that may arise during the world setup or termination processes, ensuring robust operation.
8686

87-
#### Interaction Between `Manager` and `LauncherVisualization`
87+
#### Interaction Between `Manager` and `LauncherTools`
8888

89-
1. **Visualization Setup**: `Manager` initializes `LauncherVisualization` with a specific visualization configuration, which can include types like `console`, `gazebo_gra`, `gazebo_rae`, etc.
90-
2. **Module Launching for Visualization**: `LauncherVisualization` dynamically launches visualization modules based on the configuration provided by `Manager`.
91-
3. **State Management and Synchronization**: Upon successful setup of the visualization tools, `Manager` can update its state (e.g., to `visualization_ready`) to reflect the readiness of the visualization environment.
92-
4. **Termination of Visualization Tools**: `Manager` can instruct `LauncherVisualization` to terminate the current visualization setup using its `terminate` method.
93-
5. **Error Handling and Logging**: `Manager` is equipped to manage exceptions and errors that might occur during the setup or termination of visualization tools.
89+
1. **Visualization Setup**: `Manager` initializes `LauncherTools` with a specific tools configuration, which can include tools like `console`, `simulator`, `web_gui`, etc.
90+
2. **Module Launching for Tools**: `LauncherTools` dynamically launches tools modules based on the configuration provided by `Manager`.
91+
3. **State Management and Synchronization**: Upon successful setup of the tools, `Manager` can update its state (e.g., to `tools_ready`) to reflect the readiness of the tools.
92+
4. **Termination of Tools**: `Manager` can instruct `LauncherTools` to terminate the current tools setup using its `terminate` method.
93+
5. **Error Handling and Logging**: `Manager` is equipped to manage exceptions and errors that might occur during the setup or termination of the tools.
9494

9595
#### Interaction Between `Manager` and `application_process`
9696

@@ -100,7 +100,7 @@ The `Manager` class is the core of RAM, orchestrating operations and managing tr
100100
4. **Error Handling and Logging**: `Manager` is responsible for handling any errors or exceptions that occur during the execution of the `application_process`.
101101
5. **State Synchronization**: The state of the `application_process` is closely synchronized with the state machine in `Manager`.
102102

103-
#### Interaction Between `Manager` and `Server` (Specific to RoboticsAcademy Applications)
103+
#### Interaction Between `Manager` and `Server` (Specific to RoboticsAcademy Applications) (Now inside tool web_gui)
104104

105105
1. **Dedicated WebSocket Server for GUI Updates**: `Server` is used exclusively for RoboticsAcademy applications that require real-time interaction with a web-based GUI.
106106
2. **Client Communication for GUI Module**: For RoboticsAcademy applications with a GUI module, `Server` handles incoming and outgoing messages.
@@ -120,10 +120,10 @@ The `Manager` class is the core of RAM, orchestrating operations and managing tr
120120
- Once connected, the client can request RAM to launch a robotic world by sending a `launch_world` command.
121121
- RAM transitions to the `world_ready` state after successfully setting up the world environment.
122122

123-
3. **Setting Up Visualization**:
123+
3. **Setting Up Tools**:
124124

125-
- After the world is ready, the client requests RAM to prepare the visualization tools with a `prepare_visualization` command.
126-
- RAM transitions to the `visualization_ready` state, indicating that visualization tools are set up and ready.
125+
- After the world is ready, the client requests RAM to prepare the tools with a `prepare_tools` command.
126+
- RAM transitions to the `tools_ready` state, indicating that the tools are set up and ready.
127127

128128
4. **Running an Application**:
129129

@@ -138,7 +138,7 @@ The `Manager` class is the core of RAM, orchestrating operations and managing tr
138138
6. **Stopping the Application**:
139139

140140
- Finally, the client can send a `stop` command to halt the application.
141-
- RAM stops the application and transitions back to the `visualization_ready` state, ready for new commands.
141+
- RAM stops the application and transitions back to the `tools_ready` state, ready for new commands.
142142

143143
7. **Disconnecting**:
144144
- Once all tasks are completed, the client can disconnect from RAM, which then returns to the `idle` state, ready for a new session.

manager/libs/launch_world_model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99

1010
class ConfigurationModel(BaseModel):
11-
"""Pydantic model for robotics application world and launch file configuration."""
11+
"""Pydantic model for robotics application world type and launch file config."""
1212

13-
world: str
13+
type: str
1414
launch_file_path: str
1515

1616

manager/manager/docker_thread/docker_thread.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import subprocess
55
import os
66
import signal
7+
import sys
78

89

910
class DockerThread(threading.Thread):

manager/manager/launcher/launcher_console.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class LauncherConsole(ILauncher):
1212
internal_port: int
1313
external_port: int
1414
running: bool = False
15+
acceptsMsgs: bool = False
1516
threads: List[Any] = []
1617
console_vnc: Any = Vnc_server()
1718

@@ -38,6 +39,15 @@ def run(self, config_file, callback):
3839

3940
self.running = True
4041

42+
def pause(self):
43+
pass
44+
45+
def unpause(self):
46+
pass
47+
48+
def reset(self):
49+
pass
50+
4151
def is_running(self):
4252
return self.running
4353

manager/manager/launcher/launcher_gazebo_view.py renamed to manager/manager/launcher/launcher_gazebo.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from manager.manager.launcher.launcher_interface import ILauncher
23
from manager.manager.docker_thread.docker_thread import DockerThread
34
from manager.manager.vnc.vnc_server import Vnc_server
@@ -12,13 +13,26 @@
1213
from typing import List, Any
1314

1415

15-
class LauncherGazeboView(ILauncher):
16+
def call_service(service, service_type, request_data="{}"):
17+
command = f"ros2 service call {service} {service_type} '{request_data}'"
18+
subprocess.call(
19+
f"{command}",
20+
shell=True,
21+
stdout=sys.stdout,
22+
stderr=subprocess.STDOUT,
23+
bufsize=1024,
24+
universal_newlines=True,
25+
)
26+
27+
28+
class LauncherGazebo(ILauncher):
1629
display: str
1730
internal_port: int
1831
external_port: int
1932
height: int
2033
width: int
2134
running: bool = False
35+
acceptsMsgs: bool = False
2236
threads: List[Any] = []
2337
gz_vnc: Any = Vnc_server()
2438

@@ -51,6 +65,15 @@ def run(self, config_file, callback):
5165

5266
self.running = True
5367

68+
def pause(self):
69+
call_service("/pause_physics", "std_srvs/srv/Empty")
70+
71+
def unpause(self):
72+
call_service("/unpause_physics", "std_srvs/srv/Empty")
73+
74+
def reset(self):
75+
call_service("/reset_world", "std_srvs/srv/Empty")
76+
5477
def is_running(self):
5578
return self.running
5679

manager/manager/launcher/launcher_gzsim_view.py renamed to manager/manager/launcher/launcher_gzsim.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from manager.manager.launcher.launcher_interface import ILauncher
23
from manager.manager.docker_thread.docker_thread import DockerThread
34
from manager.manager.vnc.vnc_server import Vnc_server
@@ -10,9 +11,48 @@
1011
import os
1112
import stat
1213
from typing import List, Any
14+
from manager.ram_logging.log_manager import LogManager
1315

1416

15-
class LauncherGzsimView(ILauncher):
17+
def call_gzservice(service, reqtype, reptype, timeout, req):
18+
command = f"gz service -s {service} --reqtype {reqtype} --reptype {reptype} --timeout {timeout} --req '{req}'"
19+
subprocess.call(
20+
f"{command}",
21+
shell=True,
22+
stdout=sys.stdout,
23+
stderr=subprocess.STDOUT,
24+
bufsize=1024,
25+
universal_newlines=True,
26+
)
27+
28+
29+
def call_service(service, service_type, request_data="{}"):
30+
command = f"ros2 service call {service} {service_type} '{request_data}'"
31+
subprocess.call(
32+
f"{command}",
33+
shell=True,
34+
stdout=sys.stdout,
35+
stderr=subprocess.STDOUT,
36+
bufsize=1024,
37+
universal_newlines=True,
38+
)
39+
40+
41+
def is_ros_service_available(service_name):
42+
try:
43+
result = subprocess.run(
44+
["ros2", "service", "list", "--include-hidden-services"],
45+
capture_output=True,
46+
text=True,
47+
check=True,
48+
)
49+
return service_name in result.stdout
50+
except subprocess.CalledProcessError as e:
51+
LogManager.logger.exception(f"Error checking service availability: {e}")
52+
return False
53+
54+
55+
class LauncherGzsim(ILauncher):
1656
display: str
1757
internal_port: int
1858
external_port: int
@@ -73,6 +113,41 @@ def terminate(self):
73113
def died(self):
74114
pass
75115

116+
def pause(self):
117+
call_gzservice(
118+
"$(gz service -l | grep '^/world/\w*/control$')",
119+
"gz.msgs.WorldControl",
120+
"gz.msgs.Boolean",
121+
"3000",
122+
"pause: true",
123+
)
124+
125+
def unpause(self):
126+
call_gzservice(
127+
"$(gz service -l | grep '^/world/\w*/control$')",
128+
"gz.msgs.WorldControl",
129+
"gz.msgs.Boolean",
130+
"3000",
131+
"pause: false",
132+
)
133+
134+
def reset(self):
135+
if is_ros_service_available("/drone0/platform/state_machine/_reset"):
136+
call_service(
137+
"/drone0/platform/state_machine/_reset",
138+
"std_srvs/srv/Trigger",
139+
"{}",
140+
)
141+
call_gzservice(
142+
"$(gz service -l | grep '^/world/\w*/control$')",
143+
"gz.msgs.WorldControl",
144+
"gz.msgs.Boolean",
145+
"3000",
146+
"reset: {all: true}",
147+
)
148+
if is_ros_service_available("/drone0/controller/_reset"):
149+
call_service("/drone0/controller/_reset", "std_srvs/srv/Trigger", "{}")
150+
76151
def get_dri_path(self):
77152
directory_path = "/dev/dri"
78153
dri_path = ""

manager/manager/launcher/launcher_robot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
class LauncherRobot(BaseModel):
7171
"""Class for managing robot launchers in different simulation worlds."""
7272

73-
world: str
73+
type: str
7474
launch_file_path: str
7575
module: str = ".".join(__name__.split(".")[:-1])
7676
ros_version: int = get_ros_version()
@@ -81,7 +81,7 @@ def run(self, start_pose=None):
8181
"""Run the robot launcher with an optional start pose."""
8282
if start_pose is not None:
8383
self.start_pose = start_pose
84-
for module in worlds[self.world][str(self.ros_version)]:
84+
for module in worlds[self.type][str(self.ros_version)]:
8585
module["launch_file"] = self.launch_file_path
8686
launcher = self.launch_module(module)
8787
self.launchers.append(launcher)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from manager.libs.applications.compatibility.server import Server
2+
from manager.ram_logging.log_manager import LogManager
3+
from manager.comms.new_consumer import ManagerConsumer
4+
from typing import Optional
5+
from manager.libs.applications.compatibility.file_watchdog import FileWatchdog
6+
7+
8+
class LauncherStateMonitor:
9+
file: str
10+
consumer: ManagerConsumer
11+
running: bool = False
12+
acceptsMsgs: bool = True
13+
14+
def __init__(self, type, module, file, consumer):
15+
self.file = file
16+
self.consumer = consumer
17+
self.server = FileWatchdog("/tmp/tree_state", self.update)
18+
19+
def update(self, data):
20+
LogManager.logger.debug(f"Sending update to client")
21+
if self.consumer is not None:
22+
self.consumer.send_message({"update": data}, command="update")
23+
24+
def run(self, config_file, callback):
25+
self.server.start()
26+
self.running = True
27+
28+
def get_msg(self, data):
29+
self.server.send(data)
30+
31+
def is_running(self):
32+
return self.running
33+
34+
def terminate(self):
35+
self.server.stop()
36+
self.running = False
37+
38+
def pause(self):
39+
pass
40+
41+
def unpause(self):
42+
pass
43+
44+
def reset(self):
45+
pass
46+
47+
def died(self):
48+
pass
49+
50+
def from_config(cls, config):
51+
obj = cls(**config)
52+
return obj

0 commit comments

Comments
 (0)