crazyflie_lib/subsystems/
commander.rs

1//! # Low level setpoint subsystem
2//!
3//! This subsystem allows to send low-level setpoint. The setpoints are described as low-level in the sense that they
4//! are setting the instant target state. As such they likely need to be send very often to have the crazyflie
5//! follow the wanted flight profile.
6//!
7//! The Crazyflie has a couple of safety mechanisms that one needs to be aware of in order to send setpoints:
8//!  - When using the [Commander::setpoint_rpyt()] function, a setpoint with thrust=0 must be sent once to unlock the thrust
9//!  - There is a priority for setpoints in the Crazyflie, this allows app and other internal subsystem like the high-level
10//!    commander to set setpoints in parallel, only the higher priority setpoint is taken into account.
11//!  - In no setpoint are received for 1 seconds, the Crazyflie will reset roll/pitch/yawrate to 0/0/0 and after 2 seconds
12//!    will fallback fallback to a lower-priority setpoint which in most case will cut the motors.
13//!
14//! The following example code would drive the motors in a ramp and then stop:
15//! ``` no_run
16//! # use tokio::time::{sleep, Duration};
17//! # async fn ramp(crazyflie: crazyflie_lib::Crazyflie) -> Result<(), Box<dyn std::error::Error>> {
18//! // Unlock the commander
19//! crazyflie.commander.setpoint_rpyt(0.0, 0.0, 0.0, 0).await?;
20//!
21//! // Ramp!
22//! for thrust in (0..20_000).step_by(1_000) {
23//!     crazyflie.commander.setpoint_rpyt(0.0, 0.0, 0.0, thrust).await?;
24//!     sleep(Duration::from_millis(100)).await;
25//! }
26//!
27//! // Stop the motors
28//! crazyflie.commander.setpoint_rpyt(0.0, 0.0, 0.0, 0).await?;
29//! # Ok(())
30//! # }
31//! ```
32
33use crazyflie_link::Packet;
34use flume::Sender;
35
36use crate::{Error, Result};
37
38use crate::crazyflie::COMMANDER_PORT;
39
40const RPYT_CHANNEL: u8 = 0;
41
42const _GENERIC_SETPOINT_CHANNEL: u8 = 0;
43const _GENERIC_CMD_CHANNEL: u8 = 1;
44
45/// # Low level setpoint subsystem
46///
47/// This struct implements methods to send low level setpoints to the Crazyflie.
48/// See the [commander module documentation](crate::subsystems::commander) for more context and information.
49#[derive(Debug)]
50pub struct Commander {
51    uplink: Sender<Packet>,
52}
53
54impl Commander {
55    pub(crate) fn new(uplink: Sender<Packet>) -> Commander {
56        Commander { uplink }
57    }
58}
59
60/// # Legacy RPY+ setpoint
61///
62/// This setpoint was originally the only one present in the Crazyflie and has been (ab)used to
63/// implement the early position control and other assisted and semi-autonomous mode.
64impl Commander {
65    /// Set the Roll Pitch Yaw Thrust setpoint
66    ///
67    /// When not modified by [parameters](crate::subsystems::param::Param), the meaning of the argument are:
68    ///  - **Roll/Pitch** are in degree and represent the absolute angle
69    ///  - **Yaw** is in degree per seconds and represents the rotation rate
70    ///  - **Thrust** is a 16 bit value where 0 maps to 0% thrust and 65535 to 100% thrust
71    ///
72    /// The thrust is blocked by default. The setpoint needs to be set once with thrust = 0 to unlock
73    /// the thrust for example:
74    /// ``` no_run
75    /// # fn spin(cf: crazyflie_lib::Crazyflie) {
76    /// cf.commander.setpoint_rpyt(0.0, 0.0, 0.0, 0);      // Unlocks the thrust
77    /// cf.commander.setpoint_rpyt(0.0, 0.0, 0.0, 1000);   // Thrust set to 1000
78    /// # }
79    /// ```
80    pub async fn setpoint_rpyt(&self, roll: f32, pitch: f32, yaw: f32, thrust: u16) -> Result<()> {
81        let mut payload = Vec::new();
82        payload.append(&mut roll.to_le_bytes().to_vec());
83        payload.append(&mut pitch.to_le_bytes().to_vec());
84        payload.append(&mut yaw.to_le_bytes().to_vec());
85        payload.append(&mut thrust.to_le_bytes().to_vec());
86
87        let pk = Packet::new(COMMANDER_PORT, RPYT_CHANNEL, payload);
88
89        self.uplink
90            .send_async(pk)
91            .await
92            .map_err(|_| Error::Disconnected)?;
93
94        Ok(())
95    }
96}
97
98/// # Generic setpoints
99///
100/// These setpoints are implemented in such a way that they are easy to add in the Crazyflie firmware
101/// and in libs like this one. So if you have a use-case not covered by any of the existing setpoint
102/// do not hesitate to implement and contribute your dream setpoint :-).
103impl Commander {}