To access devices, you need to write or use a physics server for your robot code. This tutorial will show you how to create your own using the roboscope-ipc library.
You can add it to a new project with this command:
cargo add --git https://github.com/lewisfm/vex-simulation roboscope-ipcRoboScope communicates between processes using several iceoryx2 services which you can access via the SimServices struct. Connect your physics simulator program to a running robot program by passing in the name of your physics simulator and a config:
use roboscope_ipc::{
Config, SimServices,
snapshot::{DeviceReadings, DistanceSnapshot},
};
fn main() -> anyhow::Result<()> {
let sim = SimServices::join(Some("Example Physics Sim"), &Config::default())?;
}Next, register a physics simulator callback:
let mut readings = DeviceReadings::default();
sim.publish_device_readings(|_cmds| {
readings
})?;Your callback will be polled at 10Hz by any running robot programs to obtain the latest device state. The values you return in readings are authoritative; for example, if you add a DistanceSnapshot in index 0 (i.e. Port 1), then the robot program will see that there is a distance sensor connected on that port with the readings you've specified.
let mut readings = DeviceReadings::default();
sim.publish_device_readings(|_cmds| {
readings.snapshots[0] = DistanceSnapshot {
distance: 300,
..Default::default()
}
.into();
readings
})?;If you want devices' readings to change over time, you just need to return different values from your callback. For example, the following implementation will simulate a distance sensor that oscillates between 0 and 1000:
let mut readings = DeviceReadings::default();
let mut x = -500.0;
let mut vx = 0.0;
sim.publish_device_readings(|_cmds| {
vx -= x * 0.0001;
x += vx;
readings.snapshots[0] = DistanceSnapshot {
distance: (x + 500.0) as u32,
..Default::default()
}
.into();
readings
})?;Robot programs might periodically issue device commands, which you can use to decide what happens in the physics simulation. For example, a program might want to apply PWM control to a motor, which you can keep track of:
let mut readings = DeviceReadings::default();
let mut pwm = 0;
let mut x = 0;
sim.publish_device_readings(|cmds| {
if let Some(cmds) = cmds
&& let DeviceCommand::Motor(motor) = &cmds[0]
&& motor.mode == MotorControlMode::Pwm
{
pwm = motor.pwm;
}
// More voltage output = more movement speed
x += pwm / 10;
readings.snapshots[0] = DistanceSnapshot {
distance: x.unsigned_abs(),
..Default::default()
}
.into();
readings
})?;Where possible, RoboScope will abstract away device configuration so that the inputs to your physics simulator are simpler: your physics simulator doesn't need to handle motor reversal, zero positions, or alternative encoder units.