How to connect copper-rs to webots? #388
Replies: 1 comment
-
It is pretty easy, we have a very user friendly API to hook up Copper to simulations: The process:
See below for the full source but for example: default::SimStep::Balpos(CuTaskCallbackState::Process(_, output)) Means that Copper is querying the simulation for the "balpos" source (ie. an encoder) to know what to do when the "process" step is called and gives you "output" as the message to construct out of the simulation state. Then follows a bunch of glue code to read the state from the sim and build this output. I believe this is called a positional sensor in webots for this specific example, you would need to call this API: https://cyberbotics.com/doc/reference/positionsensor and match the outputs. then the last critical bit of the callback is returning SimOverride::ExecutedBySim It signals to Copper to NOT execute the actual driver. Usually you just specify what needs to be handled by the sim, then default everything else to the actual code from your robot (handled by the copper runtime) hence: _ => SimOverride::ExecuteByRuntime, I hope that helps! // Sync the copper clock to the simulated physics clock.
robot_clock
.clock
.set_value(physics_time.elapsed().as_nanos() as u64);
let mut sim_callback = move |step: default::SimStep| -> SimOverride {
match step {
default::SimStep::Balpos(CuTaskCallbackState::Process(_, output)) => {
// so here we jump when the balpos source (the adc giving the rod position) is called
// we get the physical state of the work and inject back to copper what would the sensor read
let bindings = query_set.p1();
let rod_transform = bindings.single().expect("Failed to get rod transform");
let (_roll, _pitch, yaw) = rod_transform.rotation.to_euler(EulerRot::YXZ);
let mut angle_radians = yaw - std::f32::consts::FRAC_PI_2; // Offset by 90 degrees -> 0 is lying on the left.
if angle_radians < 0.0 {
angle_radians += 2.0 * std::f32::consts::PI;
}
// Convert the angle from radians to the actual adc value from the sensor
let analog_value = (angle_radians / (2.0 * std::f32::consts::PI) * 4096.0) as u16;
output.set_payload(ADSReadingPayload { analog_value });
output.metadata.tov = robot_clock.clock.now().into();
SimOverride::ExecutedBySim
}
default::SimStep::Balpos(_) => SimOverride::ExecutedBySim,
default::SimStep::Railpos(CuTaskCallbackState::Process(_, output)) => {
// Here same thing for the rail encoder.
let bindings = query_set.p0();
let (cart_transform, _) = bindings.single().expect("Failed to get cart transform");
let ticks = (cart_transform.translation.x * 2000.0) as i32;
output.set_payload(EncoderPayload { ticks });
output.metadata.tov = robot_clock.clock.now().into();
SimOverride::ExecutedBySim
}
default::SimStep::Railpos(_) => SimOverride::ExecutedBySim,
default::SimStep::Motor(CuTaskCallbackState::Process(input, output)) => {
// And now when copper wants to use the motor
// we apply a force in the simulation.
let mut bindings = query_set.p0();
let (_, mut cart_force) = bindings.single_mut().expect("Failed to get cart force");
let maybe_motor_actuation = input.payload();
if let Some(motor_actuation) = maybe_motor_actuation {
if motor_actuation.power.is_nan() {
cart_force.apply_force(Vector::ZERO);
return SimOverride::ExecutedBySim;
}
let force_magnitude = motor_actuation.power * 2.0;
let new_force = Vector::new(force_magnitude, 0.0, 0.0);
cart_force.apply_force(new_force);
output
.metadata
.set_status(format!("Applied force: {force_magnitude}"));
SimOverride::ExecutedBySim
} else {
cart_force.apply_force(Vector::ZERO);
SimOverride::Errored("Safety Mode.".into())
}
}
default::SimStep::Motor(_) => SimOverride::ExecutedBySim,
_ => SimOverride::ExecuteByRuntime,
}
};
copper_ctx
.copper_app
.run_one_iteration(&mut sim_callback)
.expect("Failed to run application."); |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi!
I'm new to the robotics world, but I would love to create my own robot.
Your crate seems like the perfect solution for me, who loves Rust and wants to manage everything with it, but since I don't have any components yet, I would like to first create a virtual robot. The virtual emulator I found is simple enough for a weekend hobbyist like me, it's
Webots
.So, returning to my main question, and sorry if it may not be relevant or doesn't make sense, do you see any way I can interact with the
webots
from the copper-rs?A real
copper-rs <--> webots
example would be ideal, but some guidelines would also be acceptable.Thanks a lot!
Beta Was this translation helpful? Give feedback.
All reactions