Contact Sensor#
Contact sensors are used to detect and report contact information between two objects (or geometries), including contact point position, contact force, normal vectors, and other detailed data. In robot simulation, contact sensors are commonly used for foot contact detection, grasping force feedback, collision detection, and other application scenarios.
๐ฏ Functionality Description#
Contact sensors monitor contact events between specified geometry pairs or object pairs and return detailed contact information. The sensor can be configured to return different types of data, including contact status, contact force, contact position, normal vectors, etc.
๐ Return Value Format#
contact_data = model.get_sensor_value("contact_sensor_name", data)
# Type: numpy.ndarray[float32]
โ๏ธ MJCF Configuration Parameters#
In MotrixSim, contact sensors support the following MJCF configurations:
Basic Configuration Format#
<sensor>
<contact name="sensor_name"
geom1="geom1_name"
geom2="geom2_name"
data="found force pos normal tangent"
num="4"
reduce="none"
/>
</sensor>
Supported Attributes#
Attribute Name |
Type |
Required |
Default |
Description |
|---|---|---|---|---|
name |
string |
โ |
- |
Unique identifier name for the sensor |
geom1 |
string |
โ |
- |
First geometry name (used with geom2) |
geom2 |
string |
โ |
- |
Second geometry name (used with geom1) |
body1 |
string |
โ |
- |
First body name (used with body2) |
body2 |
string |
โ |
- |
Second body name (used with body1) |
subtree1 |
string |
โ |
- |
First subtree name (used with subtree2) |
subtree2 |
string |
โ |
- |
Second subtree name (used with subtree1) |
site |
string |
โ |
- |
Reference point name |
data |
string |
โ |
โfoundโ |
Data types to return, separated by spaces |
num |
int |
โ |
1 |
Maximum number of contact points to report |
reduce |
string |
โ |
โnoneโ |
Data reduction method |
Target Object Configuration (Four Methods)#
1. Geometry Pair (Recommended)#
<contact name="floor_contact" geom1="bar" geom2="freebox"/>
2. Body Pair#
<contact name="body_contact" body1="body1_name" body2="body2_name"/>
3. Subtree Pair#
<contact name="subtree_contact" subtree1="subtree1_name" subtree2="subtree2_name"/>
4. Site Point#
<contact name="site_contact" site="site_name"/>
Data Types (data attribute)#
The following values can be combined:
Value |
Description |
Data Usage |
|---|---|---|
found |
Contact point count |
1 value |
force |
Contact force projection (normal + 2 tangential) |
3 values per contact point |
torque |
Contact torque |
3 values per contact point |
dist |
Penetration depth |
1 value per contact point |
pos |
Contact point position |
3 values per contact point |
normal |
Normal vector |
3 values per contact point |
tangent |
First tangential vector |
3 values per contact point |
Data Reduction Methods (reduce attribute)#
Value |
Description |
|---|---|
none |
Return all contact points (up to num) |
mindist |
Return only the closest contact point |
maxforce |
Return only the contact point with maximum force |
netforce |
Return the resultant force of all contact points (simplified format) |
๐ Return Array Length and Content Layout#
The length and content layout of the array returned by the contact sensor depend on three key configuration parameters: the data attribute (specifying data types), the num attribute (maximum number of contact points), and the reduce attribute (data reduction method).
Array Length Calculation Formula#
total_size = 1 + max_num_contacts ร values_per_contact
1: The
foundfield, indicating the actual number of contact pointsmax_num_contacts: Maximum number of contact points set by the
numparameter in MJCF configuration (fixed array size)values_per_contact: Number of data values per contact point (depends on
dataconfiguration)
Important: The array size is fixed and unaffected by the actual number of contact points. If there are fewer actual contact points than max_num_contacts, the remaining positions are filled with 0.
Impact of data Attribute on Data Per Contact Point#
Different data type combinations produce different values_per_contact:
data configuration |
Values per contact point |
Data layout (in order) |
|---|---|---|
|
0 |
Contact status only |
|
3 |
[normal force, tangential 0 force, tangential 1 force] |
|
6 |
[3 force components, 3 position coordinates] |
|
9 |
[3 force components, 3 position coordinates, 3 normal vectors] |
|
12 |
[3 force components, 3 position coordinates, 3 normal vectors, 3 tangential vectors 0] |
|
6 |
[3 position coordinates, 3 normal vectors] |
|
6 |
[3 force components, 3 torque components] |
Note: Space occupied by each data type:
found: 1 value (included in all configurations)force: 3 values (normal + 2 tangential force projections)torque: 3 values (contact torque)dist: 1 value (penetration depth)pos: 3 values (contact point position)normal: 3 values (normal vector)tangent: 3 values (first tangential vector)
Impact of reduce Attribute on Contact Point Count#
The reduce attribute determines which contact points are returned and how many:
reduce=โnoneโ (default)#
Behavior: Returns the first
numcontact points that meet matching criteria, in the order they appear in mjData.contactCharacteristics: Fastest option, but may be non-deterministic (collision detection algorithm changes may alter contact point identity and order)
Contact point count: Up to
num, possibly fewer thannum(if fewer actual contact points)
reduce=โmindistโ#
Behavior: Returns the
numcontact points with smallest penetration depth, sorted by depth in ascending orderContact point count: Up to
num, possibly fewer thannum
reduce=โmaxforceโ#
Behavior: Returns the
numcontact points with largest force norm, sorted by force magnitude in descending orderContact point count: Up to
num, possibly fewer thannum
reduce=โnetforceโ#
Behavior: Returns a โsyntheticโ contact point with the following characteristics:
Position: Force-weighted centroid of all matching contact points
Coordinate system: Global coordinate system (normal and tangent lose original semantic meaning)
Forces and torques: Calculated as forces and torques applied at the calculated position, producing the same net effect as all matching contact points
Contact point count: Always exactly 1 (ignores
numsetting)Special note: Due to using the global coordinate system, data interpretation differs from other reduce types
Specific Configuration Examples#
Example 1: Complete Contact Information (reduce=โnoneโ)#
<contact name="full_contact"
geom1="bar" geom2="freebox"
data="found force pos normal tangent"
num="4"
reduce="none"/>
Returned data layout:
contact_data = model.get_sensor_value("full_contact", data)
# Shape: shape = (1 + 4ร12,) = (49,) fixed size (determined by num="4")
# Array size is fixed, insufficient contact points are padded with 0
# Data structure:
contact_data[0] # Actual contact point count (e.g., 2, remaining 2 are padding)
# First contact point (offset = 1, valid data):
contact_data[1:4] # Force components: [normal force, tangential 0 force, tangential 1 force]
contact_data[4:7] # Position: [x, y, z]
contact_data[7:10] # Normal vector: [nx, ny, nz]
contact_data[10:13] # Tangential vector 0: [tx0, ty0, tz0]
# Second contact point (offset = 13, valid data):
contact_data[13:16] # Force components
contact_data[16:19] # Position
contact_data[19:22] # Normal vector
contact_data[22:25] # Tangential vector 0
# Third contact point (offset = 25, padded with 0):
contact_data[25:37] # All zeros (no contact)
# Fourth contact point (offset = 37, padded with 0):
contact_data[37:49] # All zeros (no contact)
Example 2: Simplified Contact Information (reduce=โmaxforceโ)#
<contact name="force_contact"
geom1="bar" geom2="freebox"
data="found force pos"
num="5"
reduce="maxforce"/>
Returned data layout:
contact_data = model.get_sensor_value("force_contact", data)
# Shape: shape = (1 + 5ร6,) = (31,) fixed size (determined by num="5")
# Array size is fixed, returns up to 5 contact points with maximum force, sorted by force in descending order
# Insufficient contact points are padded with 0
contact_data[0] # Actual contact point count (e.g., 3)
# i-th contact point: 6 values per contact point
# Only the first contact_data[0] contact points contain valid data
offset = 1 + i * 6
contact_data[offset + 0:offset + 3] # Force components
contact_data[offset + 3:offset + 6] # Position
# Note: when i >= contact_data[0], the above data are all 0
Example 3: Contact Status Only (Most Simplified)#
<contact name="touch_only"
geom1="bar" geom2="freebox"
data="found"
num="1"/>
Returned data layout:
contact_data = model.get_sensor_value("touch_only", data)
# Shape: shape = (1,) always only 1 value
contact_data[0] # Contact point count (0 = no contact, 1 = has contact)
Example 4: Resultant Force Information (reduce=โnetforceโ)#
<contact name="net_force"
geom1="bar" geom2="freebox"
data="found force pos normal tangent"
num="10"
reduce="netforce"/>
Returned data layout:
contact_data = model.get_sensor_value("net_force", data)
# Shape: shape = (1 + 1ร12,) = (13,) always returns 1 synthetic contact point (ignores num="10")
contact_data[0] # Always 1 (synthetic contact point)
# Synthetic contact point data (global coordinate system):
contact_data[1:4] # Resultant force components
contact_data[4:7] # Force-weighted centroid position
contact_data[7:10] # Normal vector (global coordinate system, semantic changed)
contact_data[10:13] # Tangential vector 0 (global coordinate system, semantic changed)
Important Notes#
Fixed array size: The returned array size is fixed, determined by the
numparameter:shape = (1 + num ร values_per_contact,)Zero padding mechanism: If the actual number of contact points is less than
num, remaining positions are filled with 0, need to usecontact_data[0]to determine valid datafound field reliability: Always use
contact_data[0]to determine the actual number of contact points, do not assume the entire array is validnetforce special handling:
reduce="netforce"has different coordinate system and data interpretation from other types, and always returns 1 contact pointPerformance optimization: For applications that only need contact status, using
data="found"can significantly improve performance
๐ Python Demo#
Below is a complete contact sensor visualization example, showing how to obtain and render contact force data in real-time. This example comes from the site_and_sensor.py file, demonstrating the practical application effects of contact sensors.
Scene Configuration#
First, we define a scene containing a contact sensor:
<contact name="box_floor_contact" geom1="bar" geom2="freebox"
This configuration creates a contact sensor named box_floor_contact that monitors contact between two geometries bar and freebox, returning complete contact information (force, position, normal vector, tangential vector).
Python Code#
Below is the complete contact sensor visualization code:
# tag::contact_sensor_gizmos[]
# Get contact sensor data: [found, then 12 values per contact point]
contact_data = model.get_sensor_value("box_floor_contact", data)
num_contacts = int(contact_data[0])
# Process each contact point
for i in range(num_contacts):
# Each contact has 12 values
offset = 1 + i * 12
# Extract force components (scalars, not vectors!)
force_normal_mag = contact_data[offset + 0] # Normal force magnitude
force_tangent0_mag = contact_data[offset + 1] # Tangent 0 force magnitude
force_tangent1_mag = contact_data[offset + 2] # Tangent 1 force magnitude
# Extract contact position
contact_pos = contact_data[offset + 3 : offset + 6]
# Extract normal vector
normal = contact_data[offset + 6 : offset + 9]
# Extract first tangent vector
tangent0 = contact_data[offset + 9 : offset + 12]
# Compute second tangent vector: tangent1 = normal ร tangent0
tangent1 = np.cross(normal, tangent0)
# Scale force magnitudes for visualization
force_scale = 0.01
# Compute force vectors for visualization
# Normal force vector (green arrow)
normal_force_end = contact_pos + normal * force_normal_mag * force_scale
# Tangent 0 force vector (red arrow)
tangent0_force_end = contact_pos + tangent0 * force_tangent0_mag * force_scale
# Tangent 1 force vector (blue arrow)
tangent1_force_end = contact_pos + tangent1 * force_tangent1_mag * force_scale
# Draw contact point (small white sphere)
render.gizmos.draw_sphere(0.02, contact_pos, color=Color.rgb(1, 1, 1))
# Draw normal force arrow (green - perpendicular to surface)
render.gizmos.draw_arrow(contact_pos, normal_force_end, color=Color.rgb(0, 1, 0))
# Draw tangent 0 force arrow (red - friction direction 0)
render.gizmos.draw_arrow(contact_pos + normal * 0.01, tangent0_force_end, color=Color.rgb(1, 0, 0))
# Draw tangent 1 force arrow (blue - friction direction 1)
render.gizmos.draw_arrow(contact_pos + normal * 0.01, tangent1_force_end, color=Color.rgb(0, 0, 1))
# end::contact_sensor_gizmos[]
Note: Only contact sensor related parts are shown here. The complete example code also includes scene setup, other sensor types, rendering loops, and other content.
Visualization Description#
This example displays the various components of contact force in real-time through color-coded arrows:
White sphere: Contact point position
Green arrow: Normal force (perpendicular to contact surface)
Red arrow: Tangential friction force component 0
Blue arrow: Tangential friction force component 1 (calculated via cross product)
Effect Demonstration#
This video demonstrates the real-time visualization effect of the contact sensor, including:
Contact point detection when objects contact the ground
Real-time calculation and display of contact forces
Visualization of force components in different directions
Dynamic process of force magnitude changing with object motion
๐ Physical Principles#
Contact Coordinate System#
Contact sensors use a local contact coordinate system to report contact data:
Normal vector: Perpendicular to the contact surface, pointing from object 1 to object 2
Tangential vectors (tangent0, tangent1): Form an orthogonal basis within the contact plane
Force projection: Projection values of contact force on the three axes
Contact Force Decomposition#
Total contact force = Normal force + Tangential force (friction)
F_total = F_normal + F_tangent0 + F_tangent1
Normal force: Positive pressure, preventing objects from penetrating each other
Tangential force: Friction, preventing relative sliding between contact surfaces
Contact Detection#
Contact sensors work based on the collision detection system:
Detect spatial overlap between two geometries
Calculate contact point position and normal vector
Calculate contact force based on penetration depth and material properties
Project contact force into local contact coordinate system
โ ๏ธ Important Notes#
Force components are scalars:
force_normal_mag,force_tangent0_mag,force_tangent1_magare force projection values, not complete force vectorsSecond tangential vector: Needs to be calculated via
tangent1 = cross(normal, tangent0)Coordinate system: All data are represented in the local contact coordinate system, not the global coordinate system
Performance considerations: Contact sensor computation is intensive, recommend setting the
numattribute reasonably to limit the number of reported contact pointsConfiguration mutual exclusion:
geom1/geom2,body1/body2,subtree1/subtree2,site- these four configuration methods can only be used one at a time