Configure Sensors for the robot#
Robots can carry sensors for environment perception. IR-SIM provides a 2D LiDAR (lidar2d) and a simplified 2D FMCW LiDAR (fmcw_lidar2d, with per-beam radial velocity), plus an optional field-of-view (FOV) region; all are attached per object in the YAML file. This page shows how to configure them and tune noise.
LiDAR Configuration Parameters#
The YAML configuration file and Python Script below shows an example of a robot with a 2D LiDAR sensor:
import irsim
env = irsim.make()
for i in range(1000):
env.step()
env.render(0.05)
if env.done():
break
env.end()
YAML file (same name as the python script):
world:
height: 10
width: 10
robot:
- kinematics: {name: 'diff'} # omni, diff, acker
shape: {name: 'circle', radius: 0.2} # radius
goal: [9, 9, 0]
sensors:
- name: 'lidar2d'
range_min: 0
range_max: 5
angle_range: 3.14
number: 200
noise: False
alpha: 0.3
obstacle:
- shape: {name: 'circle', radius: 1.0} # radius
state: [5, 5, 0]
- shape: {name: 'rectangle', length: 1.5, width: 1.2} # length, width
state: [6, 5, 1]
- shape: {name: 'linestring', vertices: [[10, 5], [4, 0], [6, 7]]} # vertices
state: [0, 0, 0]
Tip
Update order
The environment updates sensors after all objects have moved in a step. This avoids temporal skew in readings. If you control objects manually, either pass sensor_step=True to ObjectBase.step(...) or call obj.sensor_step() after updating object states.
Important Parameters Explained#
To configure the 2D LiDAR sensor, the sensor name of lidar2d should be defined in the sensors section of the robot. Key parameters of the LiDAR sensor are explained below:
range_min: The minimum range of the laser beam.
range_max: The maximum range of the laser beam.
angle_range: The angle range of the laser beam.
number: The number of beams.
alpha: The transparency of the laser beam.
A full list of parameters can be found in the YAML Configuration.
Advanced Lidar Configuration with noise#
To add noise to the LiDAR sensor, you can set the noise parameter to True.
import irsim
env = irsim.make()
for i in range(1000):
env.step()
env.render(0.05)
if env.done():
break
env.end()
world:
height: 10
width: 10
robot:
- kinematics: {name: 'diff'} # omni, diff, acker
shape: {name: 'circle', radius: 0.2} # radius
goal: [9, 9, 0]
sensors:
- name: 'lidar2d'
range_min: 0
range_max: 5
angle_range: 3.14 # 4.7123
number: 200
noise: True
std: 0.1
angle_std: 0.2
offset: [0, 0, 0]
alpha: 0.3
obstacle:
- shape: {name: 'circle', radius: 1.0} # radius
state: [5, 5, 0]
- shape: {name: 'rectangle', length: 1.5, width: 1.2} # length, width
state: [6, 5, 1]
- shape: {name: 'linestring', vertices: [[10, 5], [4, 0], [6, 7]]} # vertices
state: [0, 0, 0]
Gaussian noise is added to the LiDAR sensor with the std and angle_std parameters. The std parameter is the standard deviation of the range noise, and the angle_std parameter is the standard deviation of the angle noise.
FMCW LiDAR Configuration Parameters#
IR-SIM also provides a simplified 2D FMCW LiDAR sensor named fmcw_lidar2d. It keeps the same beam geometry as the standard 2D LiDAR, but each valid beam additionally reports a scalar radial_velocity measurement. This makes it useful for demonstrating how Doppler measurements can help interpret dynamic obstacles.
The example below uses a stationary ego sensor with a forward 120-degree field of view and multiple moving obstacles. When plotting is enabled, valid returns are colorized by radial velocity and marked at their endpoints.
import irsim
env = irsim.make("fmcw_lidar_world.yaml")
for step in range(120):
env.step()
scan = env.get_lidar_scan()
valid_count = int(scan["valid"].sum())
valid_indices = scan["valid"].nonzero()[0]
if len(valid_indices) > 0:
beam_idx = max(valid_indices, key=lambda idx: abs(scan["radial_velocity"][idx]))
print(
f"step={step:03d} valid_beams={valid_count:03d} "
f"beam={beam_idx:03d} range={scan['ranges'][beam_idx]:.3f} "
f"radial_velocity={scan['radial_velocity'][beam_idx]:.3f}"
)
else:
print(f"step={step:03d} valid_beams={valid_count:03d} no valid returns")
env.render(0.05, mode="all")
env.end(3)
robot:
- kinematics: {name: 'diff'}
shape: {name: 'circle', radius: 0.2}
state: [2.0, 5.0, 0.0]
goal: [2.0, 5.0, 0.0]
vel_min: [0.0, 0.0]
vel_max: [0.0, 0.0]
behavior: {name: 'dash'}
sensors:
- type: 'fmcw_lidar2d'
range_min: 0.0
range_max: 8.0
angle_range: 2.0944
number: 121
motion_compensate: False
noise: False
plot: # visualization params under `plot:`
velocity_linewidth: 2.0
velocity_marker_size: 45
velocity_color_max: 0.6
Key FMCW-specific parameters are:
motion_compensate: Whether to remove ego-motion from the measured radial velocity.
velocity_noise_std: Standard deviation of Gaussian noise applied to
radial_velocity.
Visualization parameters live under the sensor’s plot: sub-dict (consistent with lidar2d and object plot:); flat top-level keys are still accepted for backward compatibility:
velocity_color: Whether to colorize valid beams by radial velocity during plotting.
velocity_color_max: Velocity magnitude where the plotting color saturates.
The returned scan keeps the standard LiDAR angle metadata and adds:
radial_velocity: Scalar radial velocity for each beam.
valid: Whether the beam has a valid return within
range_max.
The complete runnable example is available under usage/22fmcw_lidar_world/.
FOV Configuration Parameters#
The YAML configuration file and Python Script below shows an example of objects within the field of view (FOV). The FOV is defined by the fov (float) and fov_radius (float) parameters in the object configuration. Each object has a FOV that can detect the robot within the FOV by the function fov_detect_object().
import irsim
env = irsim.make()
for i in range(200):
env.step()
for obs in env.obstacle_list:
if obs.fov_detect_object(env.robot):
print(f'The robot is in the FOV of the {obs.name}. The parameters of this obstacle are: state [x, y, theta]: {obs.state.flatten()}, velocity [linear, angular]: {obs.velocity.flatten()}, fov in radian: {obs.fov}.')
env.render(figure_kwargs={'dpi': 100})
env.end()
world:
height: 50
width: 50
step_time: 0.1
sample_time: 0.1
offset: [0, 0]
collision_mode: 'stop'
control_mode: 'auto'
robot:
- kinematics: {name: 'diff'} # omni, diff, acker
shape: {name: 'circle', radius: 0.4}
state: [10, 10, 0, 0]
goal: [45, 45, 0]
goal_threshold: 0.4
vel_max: [3, 1]
vel_min: [-3, -1]
behavior: {name: 'dash', wander: True, range_low: [15, 15, -3.14], range_high: [35, 35, 3.14]}
plot:
show_goal: True
show_trajectory: True
obstacle:
- number: 10
distribution: {name: 'random', range_low: [10, 10, -3.14], range_high: [40, 40, 3.14]}
kinematics: {name: 'diff'}
behavior: {name: 'rvo', vxmax: 1.5, vymax: 1.5, acce: 1.0, factor: 2.0, mode: 'vo', wander: True, range_low: [15, 15, -3.14], range_high: [35, 35, 3.14], target_roles: 'all'}
vel_max: [3, 3.14]
vel_min: [-3, -3.14]
shape:
- {name: 'circle', radius: 0.5} # radius
fov: 1.57
fov_radius: 5.0
plot:
show_fov: True
show_arrow: True
arrow_length: 0.8