Skip to content

Commit 7994db5

Browse files
authored
Merge pull request #711 from Amglega/noetic-devel
Added code for ROS2 gazebo migration
2 parents 5f849ec + ca4add5 commit 7994db5

File tree

10 files changed

+277
-60
lines changed

10 files changed

+277
-60
lines changed

behavior_metrics/brains/brains_handler.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import subprocess
44
import os
55
import traceback
6-
6+
from utils.logger import logger
77
from abc import abstractmethod
88
from albumentations import (
99
Compose, Normalize, RandomRain, RandomBrightness, RandomShadow, RandomSnow, RandomFog, RandomSunFlare, Affine
@@ -38,15 +38,14 @@ def load_brain(self, path, model=None):
3838
robot_type = path_split[-2]
3939
module_name = path_split[-1][:-3] # removing .py extension
4040

41-
# import_name = 'brains.' + framework + '.' + robot_type + '.' + module_name
4241

4342
if len(path_split) == 4:
44-
framework = path_split[2]
45-
import_name = 'brains.' + robot_type + '.' + framework + '.' + module_name
43+
import_name = 'brains.' + framework + '.' + robot_type + '.' + module_name
4644
else:
4745
import_name = 'brains.' + robot_type + '.' + module_name
48-
print(import_name)
4946

47+
logger.info("import_name:" + import_name)
48+
5049
if robot_type == 'CARLA':
5150
module = importlib.import_module(import_name)
5251
Brain = getattr(module, 'Brain')
@@ -61,6 +60,8 @@ def load_brain(self, path, model=None):
6160
if import_name in sys.modules: # for reloading sake
6261
del sys.modules[import_name]
6362
module = importlib.import_module(import_name)
63+
Brain = getattr(module, 'Brain')
64+
print('Brain: ', Brain)
6465
if robot_type == 'drone':
6566
self.active_brain = Brain(handler=self, config=self.config)
6667
else:

behavior_metrics/configs/CARLA/default_carla_ros2.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Behaviors:
5252
World: configs/CARLA/CARLA_launch_files/town_01_anticlockwise.launch.py
5353
RandomSpawnPoint: False
5454
Dataset:
55-
In: '/tmp/my_bag/'
55+
In: '/tmp/my_bag'
5656
Out: ''
5757
Stats:
5858
Out: './'
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Behaviors:
2+
Robot:
3+
Sensors:
4+
Cameras:
5+
Camera_0:
6+
Name: 'camera_0'
7+
Topic: '/cam_f1_left/image_raw'
8+
Pose3D:
9+
Pose3D_0:
10+
Name: 'pose3d_0'
11+
Topic: '/odom'
12+
Actuators:
13+
Motors:
14+
Motors_0:
15+
Name: 'motors_0'
16+
Topic: '/cmd_vel'
17+
MaxV: 3
18+
MaxW: 0.3
19+
20+
BrainPath: 'brains/gazebo/f1/brain_f1_dummy.py'
21+
PilotTimeCycle: 50
22+
Parameters:
23+
ImageTranform: ''
24+
Type: 'f1'
25+
Simulation:
26+
World: configs/gazebo/gazebo_launch_files/simple_circuit.launch.py
27+
Dataset:
28+
In: '/tmp/my_bag'
29+
Out: ''
30+
Stats:
31+
Out: './'
32+
PerfectLap: './perfect_bags/lap-simple-circuit.bag'
33+
Layout:
34+
Frame_0:
35+
Name: frame_0
36+
Geometry: [1, 1, 2, 2]
37+
Data: rgbimage
38+
Frame_1:
39+
Name: frame_1
40+
Geometry: [0, 1, 1, 1]
41+
Data: rgbimage
42+
Frame_2:
43+
Name: frame_2
44+
Geometry: [0, 2, 1, 1]
45+
Data: rgbimage
46+
Frame_3:
47+
Name: frame_3
48+
Geometry: [0, 3, 3, 1]
49+
Data: rgbimage
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import os
2+
from launch import LaunchDescription
3+
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
4+
from launch.conditions import IfCondition, UnlessCondition
5+
from launch.launch_description_sources import PythonLaunchDescriptionSource
6+
from launch.substitutions import Command, LaunchConfiguration, PythonExpression
7+
from launch_ros.actions import Node
8+
from launch_ros.substitutions import FindPackageShare
9+
10+
def generate_launch_description():
11+
12+
# Set the path to the Gazebo ROS package
13+
pkg_gazebo_ros = FindPackageShare(package='gazebo_ros').find('gazebo_ros')
14+
15+
# Set the path to this package.
16+
pkg_share = FindPackageShare(package='f1_cars').find('f1_cars')
17+
18+
# Set the path to the world file
19+
world_file_name = 'simple_circuit.world'
20+
world_path = os.path.join(pkg_share, 'worlds', world_file_name)
21+
22+
# Set the path to the SDF model files.
23+
gazebo_models_path = os.path.join(pkg_share, 'models')
24+
os.environ["GAZEBO_MODEL_PATH"] = gazebo_models_path
25+
26+
########### YOU DO NOT NEED TO CHANGE ANYTHING BELOW THIS LINE ##############
27+
# Launch configuration variables specific to simulation
28+
headless = LaunchConfiguration('headless')
29+
use_sim_time = LaunchConfiguration('use_sim_time')
30+
use_simulator = LaunchConfiguration('use_simulator')
31+
world = LaunchConfiguration('world')
32+
33+
declare_simulator_cmd = DeclareLaunchArgument(
34+
name='headless',
35+
default_value='False',
36+
description='Whether to execute gzclient')
37+
38+
declare_use_sim_time_cmd = DeclareLaunchArgument(
39+
name='use_sim_time',
40+
default_value='true',
41+
description='Use simulation (Gazebo) clock if true')
42+
43+
declare_use_simulator_cmd = DeclareLaunchArgument(
44+
name='use_simulator',
45+
default_value='True',
46+
description='Whether to start the simulator')
47+
48+
declare_world_cmd = DeclareLaunchArgument(
49+
name='world',
50+
default_value=world_path,
51+
description='Full path to the world model file to load')
52+
53+
# Specify the actions
54+
55+
# Start Gazebo server
56+
start_gazebo_server_cmd = IncludeLaunchDescription(
57+
PythonLaunchDescriptionSource(os.path.join(pkg_gazebo_ros, 'launch', 'gzserver.launch.py')),
58+
condition=IfCondition(use_simulator),
59+
launch_arguments={'world': world}.items())
60+
61+
# Start Gazebo client
62+
start_gazebo_client_cmd = IncludeLaunchDescription(
63+
PythonLaunchDescriptionSource(os.path.join(pkg_gazebo_ros, 'launch', 'gzclient.launch.py')),
64+
condition=IfCondition(PythonExpression([use_simulator, ' and not ', headless])))
65+
66+
# Create the launch description and populate
67+
ld = LaunchDescription()
68+
69+
# Declare the launch options
70+
ld.add_action(declare_simulator_cmd)
71+
ld.add_action(declare_use_sim_time_cmd)
72+
ld.add_action(declare_use_simulator_cmd)
73+
ld.add_action(declare_world_cmd)
74+
75+
# Add any actions
76+
ld.add_action(start_gazebo_server_cmd)
77+
ld.add_action(start_gazebo_client_cmd)
78+
79+
return ld

behavior_metrics/driver_gazebo.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,13 @@ def check_args(argv):
7979
Colors.OKBLUE, Colors.ENDC))
8080

8181
args = parser.parse_args()
82+
# get ROS version from environment variable
83+
ros_version = os.environ.get('ROS_VERSION', '2') # Default is ROS 2
84+
if ros_version not in ['1', '2']:
85+
logger.error('Invalid ROS_VERSION environment variable. Must be "1" or "2". Killing program...')
86+
sys.exit(-1)
8287

83-
config_data = {'config': None, 'gui': None, 'tui': None, 'script': None, 'random': False}
88+
config_data = {'config': None, 'gui': None, 'tui': None, 'script': None, 'random': False, 'ros_version': int(ros_version)}
8489
if args.config:
8590
config_data['config'] = []
8691
for config_file in args.config:
@@ -104,6 +109,31 @@ def check_args(argv):
104109
return config_data
105110

106111

112+
def init_node(ros_version):
113+
"""
114+
Initializes the ROS node based on the selected version.
115+
116+
Arguments:
117+
ros_version (str): The ROS version ("ros1" or "ros2").
118+
119+
Returns:
120+
For ROS1: returns None (as rospy manages the node globally).
121+
For ROS2: returns the created node.
122+
"""
123+
if ros_version == 1:
124+
import rospy
125+
rospy.init_node('my_ros1_node')
126+
return None # rospy maneja la instancia globalmente
127+
elif ros_version == 2:
128+
import rclpy
129+
rclpy.init()
130+
node = rclpy.create_node('my_ros2_node')
131+
logger.info('ROS2 node initialized')
132+
return node
133+
else:
134+
logger.error(f"Unsupported ROS version: {ros_version}")
135+
sys.exit(-1)
136+
107137
def conf_window(configuration):
108138
"""Gui windows for configuring the app. If not configuration file specified when launched, this windows appears,
109139
otherwise, main_win is called.
@@ -132,7 +162,7 @@ def conf_window(configuration):
132162
pass
133163

134164

135-
def main_win(configuration, controller):
165+
def main_win(configuration, controller, node):
136166
"""shows the Qt main window of the application
137167
138168
Arguments:
@@ -146,7 +176,7 @@ def main_win(configuration, controller):
146176
app = QApplication(sys.argv)
147177
main_window = ParentWindow()
148178

149-
views_controller = ViewsController(main_window, configuration, controller)
179+
views_controller = ViewsController(main_window, configuration, controller, node)
150180
views_controller.show_main_view(True)
151181

152182
main_window.show()
@@ -161,11 +191,13 @@ def main():
161191

162192
# Check and generate configuration
163193
config_data = check_args(sys.argv)
194+
node = init_node(config_data['ros_version']) # Initialize the ROS node shared by all the application
195+
164196
for config in config_data['config']:
165197
app_configuration = Config(config)
166198

167199
# Create controller of model-view
168-
controller = ControllerGazebo()
200+
controller = ControllerGazebo(node)
169201

170202
# If there's no config, configure the app through the GUI
171203
if app_configuration.empty and config_data['gui']:
@@ -194,14 +226,15 @@ def main():
194226

195227
if not config_data['script']:
196228
# Launch control
197-
pilot = PilotGazebo(app_configuration, controller, app_configuration.brain_path)
229+
230+
pilot = PilotGazebo(node, app_configuration, controller, app_configuration.brain_path)
198231
pilot.daemon = True
199232
pilot.start()
200233
logger.info('Executing app')
201234

202235
# If GUI specified, launch it. Otherwise don't
203236
if config_data['gui']:
204-
main_win(app_configuration, controller)
237+
main_win(app_configuration, controller,node)
205238
else:
206239
pilot.join()
207240

behavior_metrics/pilot_carla.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
__license__ = 'GPLv3'
4343

4444

45-
46-
4745
class PilotCarla(threading.Thread):
4846
"""This class handles the robot and its brain.
4947

behavior_metrics/pilot_gazebo.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
this program. If not, see <http://www.gnu.org/licenses/>.
1313
"""
1414

15+
import os
16+
import threading
1517
import threading
1618
import time
1719

@@ -55,14 +57,14 @@ class PilotGazebo(threading.Thread):
5557
brains {brains.brains_handler.Brains} -- Brains controller instance
5658
"""
5759

58-
def __init__(self, configuration, controller, brain_path):
60+
def __init__(self, node, configuration, controller, brain_path):
5961
"""Constructor of the pilot class
6062
6163
Arguments:
6264
configuration {utils.configuration.Config} -- Configuration instance of the application
6365
controller {utils.controller.Controller} -- Controller instance of the MVC of the application
6466
"""
65-
67+
self.node = node
6668
self.controller = controller
6769
self.controller.set_pilot(self)
6870
self.configuration = configuration
@@ -107,9 +109,10 @@ def __wait_gazebo(self):
107109
def initialize_robot(self):
108110
"""Initialize robot interfaces (sensors and actuators) and its brain from configuration"""
109111
self.stop_interfaces()
112+
110113
if self.robot_type != 'drone':
111-
self.actuators = Actuators(self.configuration.actuators)
112-
self.sensors = Sensors(self.configuration.sensors)
114+
self.actuators = Actuators(self.configuration.actuators,self.node)
115+
self.sensors = Sensors(self.configuration.sensors,self.node)
113116
if hasattr(self.configuration, 'experiment_model') and type(self.configuration.experiment_model) != list:
114117
self.brains = Brains(self.sensors, self.actuators, self.brain_path, self.controller,
115118
self.configuration.experiment_model, self.configuration.brain_kwargs)
@@ -163,7 +166,7 @@ def run(self):
163166
self.brain_iterations_simulated_time.append(self.ros_clock_time - start_time_ros)
164167
self.execution_completed = True
165168
if ros_version == '2':
166-
self.ros2_node.destroy_subscription(self.clock_subscriber)
169+
self.node.destroy_subscription(self.clock_subscriber)
167170
else:
168171
self.clock_subscriber.unregister()
169172
self.stats_process.terminate()
@@ -290,10 +293,8 @@ def track_stats(self):
290293
time.sleep(1)
291294
poll = self.stats_process.poll()
292295

293-
294296
if ros_version == '2':
295-
self.ros2_node = Node("pilot_gazebo")
296-
self.clock_subscriber = self.ros2_node.create_subscription(Clock, "/clock", self.clock_callback,1)
297+
self.clock_subscriber = self.node.create_subscription(Clock, "/clock", self.clock_callback,1)
297298
else:
298299
self.clock_subscriber = rospy.Subscriber("/clock", Clock, self.clock_callback)
299300

behavior_metrics/ui/gui/views/toolbar.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ def create_brain_gb(self):
487487
brain_label.setMaximumWidth(100)
488488
if self.configuration.brain_path:
489489
current_brain = self.configuration.brain_path.split('/')[-1].split(".")[0] # get brain name without .py
490+
490491
else:
491492
current_brain = ''
492493
self.current_brain_label = QLabel('Current brain: <b><FONT COLOR = lightgreen>' + current_brain + '</b>')
@@ -496,9 +497,15 @@ def create_brain_gb(self):
496497
self.brain_combobox = QComboBox()
497498
self.brain_combobox.setEnabled(True)
498499
environment_subpath = self.configuration.environment + '/' if self.configuration.environment is not None else ""
499-
brains = [file.split(".")[0] for file
500-
in os.listdir(brains_path + environment_subpath + self.configuration.robot_type)
501-
if file.endswith('.py') and file.split(".")[0] != '__init__']
500+
501+
if self.configuration.robot_type == "CARLA":
502+
brains = [file.split(".")[0] for file
503+
in os.listdir(brains_path + environment_subpath + self.configuration.robot_type)
504+
if file.endswith('.py') and file.split(".")[0] != '__init__']
505+
else:
506+
brains = [file.split(".")[0] for file
507+
in os.listdir(brains_path + environment_subpath + '/gazebo/' + self.configuration.robot_type)
508+
if file.endswith('.py') and file.split(".")[0] != '__init__']
502509
self.brain_combobox.addItem('')
503510
self.brain_combobox.addItems(brains)
504511
index = self.brain_combobox.findText(current_brain, Qt.MatchFixedString)

0 commit comments

Comments
 (0)