Skip to content

Commit 04bd261

Browse files
committed
introduced new exercise_wrapper for teleoperable person
Signed-off-by: Blanca <blancasoriaru@gmail.com>
1 parent 6a968eb commit 04bd261

1 file changed

Lines changed: 166 additions & 0 deletions

File tree

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import json
2+
import logging
3+
import os.path
4+
import subprocess
5+
import sys
6+
import threading
7+
import time
8+
from threading import Thread
9+
10+
from src.manager.libs.applications.compatibility.client import Client
11+
from src.manager.libs.process_utils import stop_process_and_children
12+
from src.manager.ram_logging.log_manager import LogManager
13+
from src.manager.manager.application.robotics_python_application_interface import IRoboticsPythonApplication
14+
from src.manager.manager.lint.linter import Lint
15+
16+
class CompatibilityExerciseWrapperTeleopRos2(IRoboticsPythonApplication):
17+
def __init__(self, exercise_command, gui_command, teleop_command, update_callback):
18+
super().__init__(update_callback)
19+
20+
home_dir = os.path.expanduser('~')
21+
self.running = False
22+
self.linter = Lint()
23+
self.brain_ready_event = threading.Event()
24+
# TODO: review hardcoded values
25+
process_ready, self.exercise_server = self._run_exercise_server(f"python3 {exercise_command}",
26+
f'{home_dir}/ws_code.log',
27+
'websocket_code=ready')
28+
if process_ready:
29+
LogManager.logger.info(
30+
f"Exercise code {exercise_command} launched")
31+
time.sleep(1)
32+
self.exercise_connection = Client(
33+
'ws://127.0.0.1:1905', 'exercise', self.server_message)
34+
self.exercise_connection.start()
35+
else:
36+
self.exercise_server.kill()
37+
raise RuntimeError(f"Exercise {exercise_command} could not be run")
38+
39+
process_ready, self.gui_server = self._run_exercise_server(f"python3 {gui_command}", f'{home_dir}/ws_gui.log',
40+
'websocket_gui=ready')
41+
if process_ready:
42+
LogManager.logger.info(f"Exercise gui {gui_command} launched")
43+
time.sleep(1)
44+
self.gui_connection = Client(
45+
'ws://127.0.0.1:2303', 'gui', self.server_message)
46+
self.gui_connection.start()
47+
else:
48+
self.gui_server.kill()
49+
raise RuntimeError(f"Exercise GUI {gui_command} could not be run")
50+
51+
# Websocket server for person teleoperator
52+
process_ready, self.teleop_server = self._run_exercise_server(f"python3 {teleop_command}", f'{home_dir}/ws_teleop.log',
53+
'websocket_teleop=ready')
54+
55+
self.running = True
56+
57+
self.start_send_freq_thread()
58+
59+
60+
def send_freq(self, exercise_connection, is_alive):
61+
"""Send the frequency of the brain and gui to the exercise server"""
62+
while is_alive():
63+
exercise_connection.send(
64+
"""#freq{"brain": 20, "gui": 10, "rtf": 100}""")
65+
time.sleep(1)
66+
67+
def start_send_freq_thread(self):
68+
"""Start a thread to send the frequency of the brain and gui to the exercise server"""
69+
daemon = Thread(target=lambda: self.send_freq(self.exercise_connection,
70+
lambda: self.is_alive), daemon=False, name='Monitor frequencies')
71+
daemon.start()
72+
73+
def _run_exercise_server(self, cmd, log_file, load_string, timeout: int = 5):
74+
process = subprocess.Popen(f"{cmd}", shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT,
75+
bufsize=1024, universal_newlines=True)
76+
77+
process_ready = False
78+
while not process_ready:
79+
try:
80+
f = open(log_file, "r")
81+
if f.readline() == load_string:
82+
process_ready = True
83+
f.close()
84+
time.sleep(0.2)
85+
except Exception as e:
86+
LogManager.logger.debug(
87+
f"waiting for server string '{load_string}'...")
88+
time.sleep(0.2)
89+
90+
return process_ready, process
91+
92+
def server_message(self, name, message):
93+
if name == "gui": # message received from GUI server
94+
LogManager.logger.debug(
95+
f"Message received from gui: {message[:30]}")
96+
self._process_gui_message(message)
97+
elif name == "exercise": # message received from EXERCISE server
98+
if message.startswith("#exec"):
99+
self.brain_ready_event.set()
100+
LogManager.logger.info(
101+
f"Message received from exercise: {message[:30]}")
102+
self._process_exercise_message(message)
103+
104+
def _process_gui_message(self, message):
105+
payload = json.loads(message[4:])
106+
self.update_callback(payload)
107+
self.gui_connection.send("#ack")
108+
109+
def _process_exercise_message(self, message):
110+
comand = message[:5]
111+
if (message==comand):
112+
payload = comand
113+
else:
114+
payload = json.loads(message[5:])
115+
self.update_callback(payload)
116+
self.exercise_connection.send("#ack")
117+
118+
def call_service(self, service, service_type):
119+
command = f"ros2 service call {service} {service_type}"
120+
subprocess.call(f"{command}", shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT, bufsize=1024,
121+
universal_newlines=True)
122+
123+
def run(self):
124+
self.call_service("/unpause_physics","std_srvs/srv/Empty")
125+
self.exercise_connection.send("#play")
126+
127+
def stop(self):
128+
self.call_service("/pause_physics","std_srvs/srv/Empty")
129+
self.call_service("/reset_world","std_srvs/srv/Empty")
130+
self.exercise_connection.send("#rest")
131+
132+
def resume(self):
133+
self.call_service("/unpause_physics","std_srvs/srv/Empty")
134+
self.exercise_connection.send("#play")
135+
136+
def pause(self):
137+
self.call_service("/pause_physics","std_srvs/srv/Empty")
138+
self.exercise_connection.send("#stop")
139+
140+
def restart(self):
141+
# pause_cmd = "ros2 service call /restart_simulation std_srvs/srv/Empty"
142+
# subprocess.call(f"{pause_cmd}", shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT, bufsize=1024,
143+
# universal_newlines=True)
144+
pass
145+
146+
@property
147+
def is_alive(self):
148+
return self.running
149+
150+
def load_code(self, code: str):
151+
errors = self.linter.evaluate_code(code)
152+
if errors == "":
153+
self.brain_ready_event.clear()
154+
self.exercise_connection.send(f"#code {code}")
155+
self.brain_ready_event.wait()
156+
else:
157+
raise Exception(errors)
158+
159+
def terminate(self):
160+
self.running = False
161+
self.exercise_connection.stop()
162+
self.gui_connection.stop()
163+
164+
stop_process_and_children(self.exercise_server)
165+
stop_process_and_children(self.gui_server)
166+
stop_process_and_children(self.teleop_server)

0 commit comments

Comments
 (0)