Skip to content

Commit c069d1e

Browse files
committed
updated collision logger to use gemstacks logger
1 parent d581ca8 commit c069d1e

4 files changed

Lines changed: 59 additions & 73 deletions

File tree

GEMstack/knowledge/defaults/computation_graph.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,6 @@ components:
7373
- signaling:
7474
inputs: [intent]
7575
outputs:
76-
- collision_logger:
76+
- gazebo_collision_logger:
7777
inputs: []
78-
outputs:
78+
outputs:

GEMstack/onboard/execution/entrypoint.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ def caution_callback(k,variant):
121121
# Add collision logger to other_components if in gazebo simulation and collision logging is enabled
122122
if mode == 'simulation' and settings.get('run.collision_logging', False) and name == 'drive':
123123
from ..other.gazebo_collision_logger import GazeboCollisionLogger
124-
other_components['collision_logger'] = mission_executor.make_component(
124+
other_components['gazebo_collision_logger'] = mission_executor.make_component(
125125
{'type': 'GazeboCollisionLogger', 'module': 'gazebo_collision_logger'},
126-
'collision_logger',
126+
'gazebo_collision_logger',
127127
'GEMstack.onboard.other',
128128
{'vehicle_interface': vehicle_interface}
129129
)
@@ -153,6 +153,10 @@ def caution_callback(k,variant):
153153
mission_executor.log_vehicle_interface(log_vehicle_interface)
154154
#determine whether to log components
155155
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')
156160
mission_executor.log_components(log_components)
157161
#determine whether to log state
158162
log_state_attributes = log_settings.get('state',[])
Lines changed: 37 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,24 @@
1-
from ...utils import settings
21
from ..component import Component
32
import rospy
43
from gazebo_msgs.msg import ContactsState
5-
from datetime import datetime
6-
import os
4+
from collections import deque
5+
import time
76

87
class GazeboCollisionLogger(Component):
9-
"""Component that logs collision data from Gazebo simulation."""
8+
"""Logs collision data from Gazebo simulation."""
109

1110
def __init__(self, vehicle_interface):
1211
super().__init__()
1312
self.vehicle_interface = vehicle_interface
14-
self.log_file = None
15-
self.initialized = False
13+
self.collision_messages = deque(maxlen=100)
14+
self.last_collision_time = None
15+
self.last_collision_pair = None
16+
1617

1718
def initialize(self):
18-
"""Initialize the collision logger component."""
19-
if not self.initialized:
20-
# Get log folder from settings
21-
log_settings = settings.get('run.log', {})
22-
topfolder = log_settings.get('folder', 'logs')
23-
prefix = log_settings.get('prefix', '')
24-
suffix = log_settings.get('suffix', datetime.now().strftime('%Y-%m-%d_%H-%M-%S'))
25-
logfolder = os.path.join(topfolder, prefix + suffix)
26-
27-
# Create collision log file
28-
self.log_file = os.path.join(logfolder, 'collision_log.txt')
29-
os.makedirs(os.path.dirname(self.log_file), exist_ok=True)
30-
31-
# Subscribe to contact sensor topic
32-
rospy.Subscriber('/contact_sensor', ContactsState, self.contact_callback)
33-
34-
self.initialized = True
35-
rospy.loginfo("Collision logger initialized. Logging to: %s", self.log_file)
36-
rospy.loginfo("Waiting for collision events...")
19+
"""Initialize the collision logger."""
20+
self.contact_sub = rospy.Subscriber('/contact_sensor', ContactsState, self.contact_callback)
21+
rospy.loginfo("Gazebo collision logger initialized")
3722

3823
def simplify_collision_name(self, name):
3924
"""Simplify collision names to be more readable."""
@@ -49,60 +34,43 @@ def simplify_collision_name(self, name):
4934

5035
def contact_callback(self, msg):
5136
"""Callback for processing collision messages."""
52-
if not msg.states: # If no contacts
37+
if not msg.states:
5338
return
5439

55-
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
56-
57-
# Create a dictionary to store unique collisions
58-
unique_collisions = {}
40+
current_time = time.time()
5941

6042
# Process all collision states
6143
for state in msg.states:
62-
collision_key = tuple(sorted([state.collision1_name, state.collision2_name]))
63-
if collision_key not in unique_collisions or state.depths[0] > unique_collisions[collision_key].depths[0]:
64-
unique_collisions[collision_key] = state
65-
66-
# Log collision information
67-
rospy.loginfo("\n=== Collision Detected at %s ===", timestamp)
68-
69-
with open(self.log_file, 'a') as f:
70-
f.write(f"\n=== Collision Detected at {timestamp} ===\n")
44+
collision1 = self.simplify_collision_name(state.collision1_name)
45+
collision2 = self.simplify_collision_name(state.collision2_name)
7146

72-
for i, (collision_key, state) in enumerate(unique_collisions.items(), 1):
73-
collision1 = self.simplify_collision_name(state.collision1_name)
74-
collision2 = self.simplify_collision_name(state.collision2_name)
75-
76-
# Reorder collisions to put vehicle parts first
77-
if "vehicle" in collision2:
78-
collision1, collision2 = collision2, collision1
79-
80-
# Log collision details
81-
rospy.loginfo("\nContact %d:", i)
82-
rospy.loginfo("Collision between: %s and %s", collision1, collision2)
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
8357

8458
pos = state.contact_positions[0]
85-
pos_str = f"Contact Position: x={pos.x:.3f}, y={pos.y:.3f}, z={pos.z:.3f}"
86-
rospy.loginfo(pos_str)
87-
8859
normal = state.contact_normals[0]
89-
normal_str = f"Contact Normal: x={normal.x:.3f}, y={normal.y:.3f}, z={normal.z:.3f}"
90-
rospy.loginfo(normal_str)
9160

92-
depth_str = f"Contact Depth: {state.depths[0]:.3f}"
93-
rospy.loginfo(depth_str)
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+
)
9468

95-
# Write to file
96-
f.write(f"\nContact {i}:\n")
97-
f.write(f"Collision between: {collision1} and {collision2}\n")
98-
f.write(f"{pos_str}\n")
99-
f.write(f"{normal_str}\n")
100-
f.write(f"{depth_str}\n")
101-
f.write("-" * 50 + "\n")
102-
103-
f.write("\n")
104-
rospy.loginfo("-" * 50)
69+
self.collision_messages.append(message)
70+
self.last_collision_time = current_time
71+
self.last_collision_pair = collision_pair
10572

10673
def update(self):
107-
"""Update method required by Component base class."""
108-
pass # All work is done in the ROS callback
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
---

0 commit comments

Comments
 (0)