use std::borrow::Borrow;
use crate::msg;
use crate::rosrust_utils::*;
use arci::*;
use nalgebra as na;
use serde::{Deserialize, Serialize};
rosrust::rosmsg_include! {
std_srvs / Empty
}
const AMCL_POSE_TOPIC: &str = "/amcl_pose";
const NO_MOTION_UPDATE_SERVICE: &str = "request_nomotion_update";
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct RosLocalizationClientConfig {
pub request_final_nomotion_update_hack: bool,
}
#[derive(Clone, Debug)]
pub struct RosLocalizationClientBuilder {
request_final_nomotion_update_hack: bool,
}
impl RosLocalizationClientBuilder {
pub fn new() -> Self {
Self {
request_final_nomotion_update_hack: false,
}
}
pub fn request_final_nomotion_update_hack(mut self, val: bool) -> Self {
self.request_final_nomotion_update_hack = val;
self
}
pub fn finalize(self) -> RosLocalizationClient {
RosLocalizationClient::new(self.request_final_nomotion_update_hack)
}
}
impl Default for RosLocalizationClientBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct RosLocalizationClient {
pose_subscriber: SubscriberHandler<msg::geometry_msgs::PoseWithCovarianceStamped>,
nomotion_update_client: Option<rosrust::Client<msg::std_srvs::Empty>>,
}
impl RosLocalizationClient {
pub fn new(request_final_nomotion_update_hack: bool) -> Self {
let pose_subscriber = SubscriberHandler::new(AMCL_POSE_TOPIC, 1);
let nomotion_update_client = if request_final_nomotion_update_hack {
rosrust::wait_for_service(
NO_MOTION_UPDATE_SERVICE,
Some(std::time::Duration::from_secs(10)),
)
.unwrap();
Some(rosrust::client::<msg::std_srvs::Empty>(NO_MOTION_UPDATE_SERVICE).unwrap())
} else {
None
};
Self {
pose_subscriber,
nomotion_update_client,
}
}
pub fn new_from_config(config: RosLocalizationClientConfig) -> Self {
Self::new(config.request_final_nomotion_update_hack)
}
pub fn request_nomotion_update(&self) {
self.nomotion_update_client
.borrow()
.as_ref()
.unwrap()
.req(&msg::std_srvs::EmptyReq {})
.unwrap()
.unwrap();
}
}
impl Localization for RosLocalizationClient {
fn current_pose(&self, _frame_id: &str) -> Result<na::Isometry2<f64>, Error> {
self.pose_subscriber.wait_message(100);
let pose_with_cov_stamped =
self.pose_subscriber
.get()?
.ok_or_else(|| Error::Connection {
message: format!("Failed to get pose from {}", AMCL_POSE_TOPIC),
})?;
let pose: na::Isometry3<f64> = pose_with_cov_stamped.pose.pose.into();
Ok(na::Isometry2::new(
na::Vector2::new(pose.translation.vector[0], pose.translation.vector[1]),
pose.rotation.euler_angles().2,
))
}
}