Skip to content

Commit a6ae0db

Browse files
authored
Merge pull request #218 from krishauser/gazebo_collision_detection
Gazebo collision detection
2 parents a841b2b + c069d1e commit a6ae0db

6 files changed

Lines changed: 112 additions & 4 deletions

File tree

GEMstack/knowledge/defaults/computation_graph.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ components:
6969
outputs: trajectory
7070
- trajectory_tracking:
7171
inputs: [vehicle, trajectory]
72-
outputs:
72+
outputs:
7373
- signaling:
7474
inputs: [intent]
75-
outputs:
75+
outputs:
76+
- gazebo_collision_logger:
77+
inputs: []
78+
outputs:

GEMstack/onboard/execution/entrypoint.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ def caution_callback(k,variant):
118118
if v is None: continue
119119
other_components[k] = mission_executor.make_component(v,k,'GEMstack.onboard.other', {'vehicle_interface':vehicle_interface})
120120

121+
# Add collision logger to other_components if in gazebo simulation and collision logging is enabled
122+
if mode == 'simulation' and settings.get('run.collision_logging', False) and name == 'drive':
123+
from ..other.gazebo_collision_logger import GazeboCollisionLogger
124+
other_components['gazebo_collision_logger'] = mission_executor.make_component(
125+
{'type': 'GazeboCollisionLogger', 'module': 'gazebo_collision_logger'},
126+
'gazebo_collision_logger',
127+
'GEMstack.onboard.other',
128+
{'vehicle_interface': vehicle_interface}
129+
)
130+
121131
mission_executor.add_pipeline(name,perception_components,planning_components,other_components)
122132

123133
#configure logging
@@ -143,6 +153,10 @@ def caution_callback(k,variant):
143153
mission_executor.log_vehicle_interface(log_vehicle_interface)
144154
#determine whether to log components
145155
log_components = log_settings.get('components',[])
156+
#add gazebo_collision_logger to components if collision logging is enabled
157+
if settings.get('run.collision_logging', False):
158+
if 'gazebo_collision_logger' not in log_components:
159+
log_components.append('gazebo_collision_logger')
146160
mission_executor.log_components(log_components)
147161
#determine whether to log state
148162
log_state_attributes = log_settings.get('state',[])
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from ..component import Component
2+
import rospy
3+
from gazebo_msgs.msg import ContactsState
4+
from collections import deque
5+
import time
6+
7+
class GazeboCollisionLogger(Component):
8+
"""Logs collision data from Gazebo simulation."""
9+
10+
def __init__(self, vehicle_interface):
11+
super().__init__()
12+
self.vehicle_interface = vehicle_interface
13+
self.collision_messages = deque(maxlen=100)
14+
self.last_collision_time = None
15+
self.last_collision_pair = None
16+
17+
18+
def initialize(self):
19+
"""Initialize the collision logger."""
20+
self.contact_sub = rospy.Subscriber('/contact_sensor', ContactsState, self.contact_callback)
21+
rospy.loginfo("Gazebo collision logger initialized")
22+
23+
def simplify_collision_name(self, name):
24+
"""Simplify collision names to be more readable."""
25+
if "base_link" in name:
26+
return "vehicle body"
27+
elif "front_rack" in name:
28+
return "vehicle front bumper"
29+
elif "rear_rack" in name:
30+
return "vehicle rear bumper"
31+
elif "::" in name:
32+
return name.split("::")[0]
33+
return name
34+
35+
def contact_callback(self, msg):
36+
"""Callback for processing collision messages."""
37+
if not msg.states:
38+
return
39+
40+
current_time = time.time()
41+
42+
# Process all collision states
43+
for state in msg.states:
44+
collision1 = self.simplify_collision_name(state.collision1_name)
45+
collision2 = self.simplify_collision_name(state.collision2_name)
46+
47+
# Reorder collisions to put vehicle parts first
48+
if "vehicle" in collision2:
49+
collision1, collision2 = collision2, collision1
50+
51+
collision_pair = tuple(sorted([collision1, collision2]))
52+
53+
# Only log if it's a new collision or enough time has passed
54+
if (self.last_collision_time is None or
55+
current_time - self.last_collision_time > 0.25 or # Different time
56+
collision_pair != self.last_collision_pair): # Different collision pair
57+
58+
pos = state.contact_positions[0]
59+
normal = state.contact_normals[0]
60+
61+
message = (
62+
f"Collision between: {collision1} and {collision2}\n"
63+
f"Contact Position: x={pos.x:.3f}, y={pos.y:.3f}, z={pos.z:.3f}\n"
64+
f"Contact Normal: x={normal.x:.3f}, y={normal.y:.3f}, z={normal.z:.3f}\n"
65+
f"Contact Depth: {state.depths[0]:.3f}\n"
66+
f"{'-' * 50}"
67+
)
68+
69+
self.collision_messages.append(message)
70+
self.last_collision_time = current_time
71+
self.last_collision_pair = collision_pair
72+
73+
def update(self):
74+
"""Output collision messages to the console/log."""
75+
while self.collision_messages:
76+
print(self.collision_messages.popleft())

docs/Gazebo Simulation Documentation.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,18 @@ Follow the instructions in the [POLARIS GEM Simulator](https://github.com/harish
149149

150150
The naming conventions for entities are important as they determine how models are detected and classified. Refer to the [Entity Detection Documentation](gazebo_entity_detection.md) for details on model naming and the detection process.
151151

152+
## Collision Logging in Gazebo
153+
154+
To enable collision logging in your Gazebo simulation, add the following to your launch file's `gazebo` variant:
155+
156+
```yaml
157+
run:
158+
collision_logging: True # Enable collision logging
159+
```
160+
161+
When enabled, the collision logger will:
162+
- Monitor collisions between the vehicle and other objects in the simulation
163+
- Log collision details including colliding objects, contact position, normal, and depth
164+
- Output logs to `GazeboCollisionLogger.stdout.log` in your log directory
165+
152166
---

launch/fixed_route.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ variants:
6666
vehicle_interface:
6767
type: gem_simulator.GEMDoubleIntegratorSimulationInterface
6868
args:
69-
scene: !relative_path '../scenes/xyhead_demo.yaml'
70-
69+
scene: !relative_path '../scenes/xyhead_demo.yaml'
7170
drive:
7271
perception:
7372
state_estimation : OmniscientStateEstimator
@@ -79,6 +78,7 @@ variants:
7978
mode: simulation
8079
vehicle_interface:
8180
type: gem_gazebo.GEMGazeboInterface
81+
collision_logging: True
8282
drive:
8383
perception:
8484
state_estimation: GNSSStateEstimator # Matches your Gazebo GNSS implementation

launch/gazebo_simulation.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ variants:
6868
type: gem_gazebo.GEMGazeboInterface
6969
# args:
7070
# scene: !relative_path '../scenes/gazebo.yaml'
71+
collision_logging: True # Enable collision logging for gazebo simulation
7172

7273
drive:
7374
perception:

0 commit comments

Comments
 (0)