Skip to content

Commit 9431ced

Browse files
authored
DDS Backend (#1)
1 parent dd39d2b commit 9431ced

32 files changed

Lines changed: 1458 additions & 6644 deletions

Cargo.lock

Lines changed: 512 additions & 2683 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ members = ["booster_sdk", "booster_sdk_py"]
33
resolver = "2"
44

55
[workspace.package]
6-
version = "0.1.0-alpha.1"
6+
version = "0.1.0-alpha.4"
77
edition = "2024"
88
authors = ["Team whIRLwind"]
99
license = "MIT OR Apache-2.0"
@@ -24,13 +24,12 @@ pedantic = { level = "warn", priority = -1 }
2424
booster_sdk = { path = "booster_sdk" }
2525

2626
tokio = { version = "1.42", features = ["full"] }
27-
zenoh = { version = "1.0", features = ["unstable"] }
27+
rustdds = "0.11.8"
2828
serde = { version = "1.0", features = ["derive"] }
2929
serde_json = "1.0"
3030
thiserror = "1.0"
3131
tracing = "0.1"
3232
uuid = { version = "1.11", features = ["v4", "serde"] }
3333
typed-builder = "0.23.0"
34-
glam = { version = "0.29", features = ["serde"] }
3534
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
3635
pyo3 = { version = "0.27.1", features = ["extension-module"] }

README.md

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ A Rust SDK for controlling Booster robots based on [Booster Robotics C++ SDK](ht
1111
## 🚧 Project Status
1212

1313
This library is currently in early development. The core architecture and types are defined, but none of it has been tested on
14-
an actual robot yet. Specifically, the `dds` module's Zenoh communication layer is untested.
14+
an actual robot yet. The DDS transport layer is implemented using RustDDS.
1515

1616
## API Examples
1717

1818
### High-Level Locomotion Control
1919

2020
```rust
21-
use booster_sdk::client::B1LocoClient;
21+
use booster_sdk::client::BoosterClient;
2222
use booster_sdk::types::{RobotMode, Hand};
2323

2424
#[tokio::main]
2525
async fn main() -> Result<(), Box<dyn std::error::Error>> {
2626
// Initialize and create client
27-
let client = B1LocoClient::new().await?;
27+
let client = BoosterClient::new()?;
2828

2929
// Change to walking mode
3030
client.change_mode(RobotMode::Walking).await?;
@@ -33,7 +33,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3333
client.move_robot(0.5, 0.0, 0.0).await?;
3434

3535
// Wave hand
36-
client.wave_hand(Hand::Right).await?;
36+
// Publish gripper commands if needed (DDS topic-based control)
37+
client.publish_gripper_command(&booster_sdk::client::GripperCommand::open(Hand::Right))?;
3738

3839
// Lie down when done
3940
client.lie_down().await?;
@@ -63,30 +64,28 @@ This will create a wheel file in `booster_sdk_py/dist/` that can be installed wi
6364

6465
### Python API Example
6566

67+
Note: Python bindings are intentionally minimal and expose a subset of the Rust API.
68+
6669
```python
67-
from booster_sdk import B1LocoClient, RobotMode, Hand
70+
from booster_sdk import BoosterClient, GripperCommand, Hand, RobotMode
6871

69-
# Initialize client with optional timeout
70-
client = B1LocoClient(timeout_secs=5.0)
72+
client = BoosterClient()
7173

7274
# Change to walking mode
7375
client.change_mode(RobotMode.WALKING)
7476

7577
# Move forward
7678
client.move_robot(0.5, 0.0, 0.0)
7779

78-
# Wave hand
79-
client.wave_hand(Hand.RIGHT)
80-
81-
# Lie down when done
82-
client.lie_down()
80+
# Open right gripper
81+
client.publish_gripper_command(GripperCommand.open(Hand.RIGHT))
8382
```
8483

85-
The Python bindings expose the same high-level API as the Rust SDK, including robot mode control, locomotion, hand/gripper control, and coordinate frame transformations.
84+
The Python bindings currently cover basic mode changes, locomotion, and gripper control.
8685

8786
# DDS Setup
8887

89-
Setting up the DDS communication layer to work with Booster robots involves configuring Zenoh. Please refer to the [DDS Setup Guide](docs/dds_setup.md) for detailed instructions.
88+
The Rust SDK communicates directly over DDS (RustDDS). Please refer to the [DDS Setup Guide](docs/dds_setup.md) for detailed instructions.
9089

9190
## Contributing
9291

booster_sdk/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ repository.workspace = true
99

1010
[dependencies]
1111
tokio = { workspace = true }
12-
zenoh = { workspace = true }
1312
serde = { workspace = true }
1413
serde_json = { workspace = true }
1514
thiserror = { workspace = true }
1615
tracing = { workspace = true }
1716
uuid = { workspace = true }
1817
typed-builder = { workspace = true }
19-
glam = { workspace = true }
18+
rustdds = { workspace = true }
2019

2120
[dev-dependencies]
2221
tracing-subscriber = { workspace = true }

booster_sdk/examples/gripper_control.rs

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//!
55
//! Run with: cargo run --example `gripper_control`
66
7-
use booster_sdk::client::{B1LocoClient, commands::GripperCommand};
7+
use booster_sdk::client::{BoosterClient, commands::GripperCommand};
88
use booster_sdk::types::{Hand, RobotMode};
99

1010
#[tokio::main]
@@ -14,7 +14,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
1414

1515
tracing::info!("Starting gripper control example");
1616

17-
let client = B1LocoClient::new().await?;
17+
let client = BoosterClient::new()?;
1818

1919
// Ensure robot is in correct mode
2020
tracing::info!("Preparing robot...");
@@ -23,40 +23,28 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
2323

2424
// Open both grippers
2525
tracing::info!("Opening both grippers");
26-
client
27-
.control_gripper(&GripperCommand::open(Hand::Left))
28-
.await?;
29-
client
30-
.control_gripper(&GripperCommand::open(Hand::Right))
31-
.await?;
26+
client.publish_gripper_command(&GripperCommand::open(Hand::Left))?;
27+
client.publish_gripper_command(&GripperCommand::open(Hand::Right))?;
3228
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
3329

3430
// Close left gripper
3531
tracing::info!("Closing left gripper");
36-
client
37-
.control_gripper(&GripperCommand::close(Hand::Left))
38-
.await?;
32+
client.publish_gripper_command(&GripperCommand::close(Hand::Left))?;
3933
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
4034

4135
// Open left gripper again
4236
tracing::info!("Opening left gripper");
43-
client
44-
.control_gripper(&GripperCommand::open(Hand::Left))
45-
.await?;
37+
client.publish_gripper_command(&GripperCommand::open(Hand::Left))?;
4638
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
4739

4840
// Force-based grasp with right hand
4941
tracing::info!("Grasping with right hand (force control)");
50-
client
51-
.control_gripper(&GripperCommand::grasp(Hand::Right, 600))
52-
.await?;
42+
client.publish_gripper_command(&GripperCommand::grasp(Hand::Right, 600))?;
5343
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
5444

5545
// Release
5646
tracing::info!("Releasing grasp");
57-
client
58-
.control_gripper(&GripperCommand::open(Hand::Right))
59-
.await?;
47+
client.publish_gripper_command(&GripperCommand::open(Hand::Right))?;
6048

6149
tracing::info!("Example completed successfully");
6250

booster_sdk/examples/locomotion_control.rs

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//! High-level locomotion control example
22
//!
3-
//! This example demonstrates basic locomotion control using the `B1LocoClient`.
3+
//! This example demonstrates basic locomotion control using the `BoosterClient`.
44
//!
55
//! Run with: cargo run --example `locomotion_control`
66
7-
use booster_sdk::client::{B1LocoClient, commands::MoveCommand};
8-
use booster_sdk::types::{Hand, RobotMode};
7+
use booster_sdk::client::BoosterClient;
8+
use booster_sdk::types::RobotMode;
99
use tokio::time::Duration;
1010

1111
#[tokio::main]
@@ -16,13 +16,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
1616
tracing::info!("Starting locomotion control example");
1717

1818
// Create client with 2-second timeout
19-
let client = B1LocoClient::with_timeout(Duration::from_millis(2000)).await?;
20-
21-
// Get current mode
22-
match client.get_mode().await {
23-
Ok(mode) => tracing::info!("Current mode: {:?}", mode),
24-
Err(e) => tracing::error!("Failed to get mode: {}", e),
25-
}
19+
let client = BoosterClient::new()?;
2620

2721
// Change to walking mode
2822
tracing::info!("Changing to walking mode...");
@@ -32,42 +26,22 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3226
// Wait a moment for mode transition
3327
tokio::time::sleep(Duration::from_secs(2)).await;
3428

35-
// Move forward
36-
tracing::info!("Moving forward at 0.3 m/s for 3 seconds");
37-
client.move_robot(0.3, 0.0, 0.0).await?;
29+
tracing::info!("Moving forward at 0.5 m/s for 3 seconds");
30+
client.move_robot(0.5, 0.0, 0.0).await?;
3831
tokio::time::sleep(Duration::from_secs(3)).await;
3932

40-
// Stop
4133
tracing::info!("Stopping");
42-
client.stop().await?;
34+
client.move_robot(0.0, 0.0, 0.0).await?;
4335
tokio::time::sleep(Duration::from_secs(1)).await;
4436

45-
// Turn in place
4637
tracing::info!("Turning left for 2 seconds");
47-
let turn_cmd = MoveCommand::turn(0.5);
48-
client.move_with_command(&turn_cmd).await?;
38+
client.move_robot(0.0, 0.0, 0.6).await?;
4939
tokio::time::sleep(Duration::from_secs(2)).await;
5040

51-
// Stop again
5241
tracing::info!("Stopping");
53-
client.stop().await?;
42+
client.move_robot(0.0, 0.0, 0.0).await?;
5443
tokio::time::sleep(Duration::from_secs(1)).await;
5544

56-
// Wave hand
57-
tracing::info!("Waving right hand");
58-
client.wave_hand(Hand::Right).await?;
59-
tokio::time::sleep(Duration::from_secs(3)).await;
60-
61-
// Rotate head
62-
tracing::info!("Looking around");
63-
client.rotate_head(0.2, 0.5).await?;
64-
tokio::time::sleep(Duration::from_secs(2)).await;
65-
client.rotate_head(0.0, 0.0).await?; // Center head
66-
67-
// Lie down
68-
tracing::info!("Lying down");
69-
client.lie_down().await?;
70-
7145
tracing::info!("Example completed successfully");
7246

7347
Ok(())
Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,43 @@
1-
//! High-level look around example
1+
//! Motion state subscription example
22
//!
3-
//! This example demonstrates basic look around behavior using the `B1LocoClient`.
3+
//! This example subscribes to the motion state topic over DDS.
44
//!
55
//! Run with: cargo run --example `look_around`
66
7-
use booster_sdk::client::B1LocoClient;
7+
use booster_sdk::client::BoosterClient;
88
use tokio::time::Duration;
99

1010
#[tokio::main]
1111
async fn main() -> Result<(), Box<dyn std::error::Error>> {
1212
// Initialize logging
1313
tracing_subscriber::fmt().with_env_filter("info").init();
1414

15-
tracing::info!("Starting look around example");
16-
17-
// Create client with 2-second timeout
18-
let client = B1LocoClient::with_timeout(Duration::from_millis(2000)).await?;
19-
20-
// Get current mode
21-
match client.get_mode().await {
22-
Ok(mode) => tracing::info!("Current mode: {:?}", mode),
23-
Err(e) => tracing::error!("Failed to get mode: {}", e),
24-
}
25-
26-
// Rotate head
27-
tracing::info!("Looking around");
28-
29-
// scan from left to right with a sine wave
30-
let steps = 4000;
31-
for i in 0..=steps {
32-
let angle = (i as f32 / steps as f32) * std::f32::consts::TAU;
33-
let head_yaw = (6.0 * angle).cos() * 1.0;
34-
let head_pitch = (6.0 * angle).sin() * 0.4;
35-
client.rotate_head(head_pitch, head_yaw).await?;
36-
tokio::time::sleep(Duration::from_millis(10)).await;
15+
tracing::info!("Starting motion state subscription example");
16+
17+
let client = BoosterClient::new()?;
18+
let mut motion_state = client.subscribe_motion_state()?;
19+
20+
let timeout = tokio::time::sleep(Duration::from_secs(10));
21+
tokio::pin!(timeout);
22+
23+
loop {
24+
tokio::select! {
25+
_ = &mut timeout => {
26+
tracing::info!("Finished listening for motion state updates");
27+
break;
28+
}
29+
sample = motion_state.recv() => {
30+
if let Some(state) = sample {
31+
tracing::info!(
32+
"Motion state: current={}, target={}, transitioning={}",
33+
state.current_mode,
34+
state.target_mode,
35+
state.is_transitioning
36+
);
37+
}
38+
}
39+
}
3740
}
3841

39-
// set head back to center
40-
tracing::info!("Centering head");
41-
client.rotate_head(0.0, 0.0).await?;
42-
4342
Ok(())
4443
}

0 commit comments

Comments
 (0)