Skip to main content

fsds_rs/
client.rs

1//! This module contains the FSDSClient struct which is used to interact with
2//! the FSDS server.
3//!
4//! The FSDSClient struct provides all the API methods available to interact
5//! with the simulator.
6
7use msgpack_rpc::{Client, Value};
8use tokio::net::TcpStream;
9use tokio_util::compat::TokioAsyncReadCompatExt;
10
11use crate::types::{CarControls, ImageRequest, ImageType};
12
13pub struct FSDSClient {
14    client: Client,
15}
16
17impl FSDSClient {
18    pub async fn init(addr: Option<&str>, _timeout_value: Option<u64>) -> anyhow::Result<Self> {
19        let addr = addr.unwrap_or("127.0.0.1:41451");
20
21        // Create a client with the specified timeout if needed.
22        let stream = TcpStream::connect(&addr).await?;
23
24        let client = Client::new(stream.compat());
25
26        Ok(FSDSClient { client })
27    }
28
29    /// Reset the vehicle to its original starting state.
30    ///
31    /// Note that you must call `enable_api_control` again after the call to
32    /// reset.
33    pub async fn reset(&mut self) -> Result<Value, anyhow::Error> {
34        self.client
35            .request("reset", &[])
36            .await
37            .map_err(|e| anyhow::anyhow!(e))
38    }
39
40    /// If connection is established then this call will return Ok(_) otherwise
41    /// it will be blocked until timeout.
42    pub async fn ping(&mut self) -> Result<Value, anyhow::Error> {
43        self.client
44            .request("ping", &[])
45            .await
46            .map_err(|e| anyhow::anyhow!(e))
47    }
48
49    /// Enables API control for vehicle corresponding to vehicle_name.
50    pub async fn enable_api_control(&mut self, vehicle_name: &str) -> Result<Value, anyhow::Error> {
51        self.client
52            .request("enableApiControl", &[true.into(), vehicle_name.into()])
53            .await
54            .map_err(|e| anyhow::anyhow!(e))
55    }
56
57    /// Disable API control for vehicle corresponding to vehicle_name.
58    pub async fn disable_api_control(
59        &mut self,
60        vehicle_name: &str,
61    ) -> Result<Value, anyhow::Error> {
62        self.client
63            .request("enableApiControl", &[false.into(), vehicle_name.into()])
64            .await
65            .map_err(|e| anyhow::anyhow!(e))
66    }
67
68    /// Returns true if API control is established.
69    ///
70    /// If false (which is default) then API calls would be ignored. After a
71    /// successful call to `enableApiControl`, `isApiControlEnabled` should
72    /// return true.
73    pub async fn is_api_control_enabled(
74        &mut self,
75        vehicle_name: &str,
76    ) -> Result<Value, anyhow::Error> {
77        self.client
78            .request("isApiControlEnabled", &[vehicle_name.into()])
79            .await
80            .map_err(|e| anyhow::anyhow!(e))
81    }
82
83    /// Get a single image.
84    ///
85    /// Returns bytes of png format image which can be dumped into a binary file
86    /// to create .png image.
87    ///
88    /// See https://microsoft.github.io/AirSim/image_apis/ for details.
89    pub async fn sim_get_image(
90        &mut self,
91        camera_name: &str,
92        image_type: ImageType,
93        vehicle_name: &str,
94    ) -> Result<Value, anyhow::Error> {
95        self.client
96            .request(
97                "simGetImage",
98                &[camera_name.into(), image_type.into(), vehicle_name.into()],
99            )
100            .await
101            .map_err(|e| anyhow::anyhow!(e))
102    }
103
104    /// Get multiple images.
105    ///
106    /// See https://microsoft.github.io/AirSim/image_apis/ for details and
107    /// examples.
108    pub async fn sim_get_images(
109        &mut self,
110        requests: &[ImageRequest],
111        vehicle_name: &str,
112    ) -> Result<Value, anyhow::Error> {
113        self.client
114            .request(
115                "simGetImages",
116                &[
117                    Value::Array(requests.iter().map(|r| r.clone().into()).collect()),
118                    vehicle_name.into(),
119                ],
120            )
121            .await
122            .map_err(|e| anyhow::anyhow!(e))
123    }
124
125    /// Get Ground truth kinematics of the vehicle.
126    pub async fn sim_get_ground_truth_kinematics(
127        &mut self,
128        vehicle_name: &str,
129    ) -> Result<Value, anyhow::Error> {
130        self.client
131            .request("simGetGroundTruthKinematics", &[vehicle_name.into()])
132            .await
133            .map_err(|e| anyhow::anyhow!(e))
134    }
135
136    pub async fn set_car_controls(&mut self, controls: CarControls, vehicle_name: &str) {
137        self.client
138            .request("setCarControls", &[controls.into(), vehicle_name.into()]);
139    }
140
141    pub async fn get_car_state(&mut self, vehicle_name: &str) -> Result<Value, anyhow::Error> {
142        self.client
143            .request("getCarState", &[vehicle_name.into()])
144            .await
145            .map_err(|e| anyhow::anyhow!(e))
146    }
147}