Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

more fixes #28

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 4 additions & 37 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,47 +1,14 @@
# Makefile

define HELP_MESSAGE
actuator

# Installing

1. Create a new Conda environment: `conda create --name actuator python=3.11`
2. Activate the environment: `conda activate actuator`
3. Install the package: `make install-dev`

# Running Tests

1. Run autoformatting: `make format`
2. Run static checks: `make static-checks`
3. Run unit tests: `make test`

endef
export HELP_MESSAGE

all:
@echo "$$HELP_MESSAGE"
.PHONY: all

# ------------------------ #
# Build #
# ------------------------ #

install-and-run:
install:
cargo run --bin stub_gen
@touch setup.py
@uv pip install -e '.[dev]'
@python -m actuator.cli
.PHONY: install-and-run

build-rust:
@RUST_BACKTRACE=1 cargo build -p lib
.PHONY: build-rust

build-stubs:
@RUST_BACKTRACE=1 cargo run --bin stub_gen -p lib --verbose
.PHONY: build-stubs

clean:
rm -rf build dist *.so **/*.so **/*.pyi **/*.pyc **/*.pyd **/*.pyo **/__pycache__ *.egg-info .eggs/ .ruff_cache/
.PHONY: clean
.PHONY: build

# ------------------------ #
# Static Checks #
Expand Down
22 changes: 8 additions & 14 deletions actuator/rust/bindings/bindings.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,17 @@ class PyRobstrideMotors:
def send_starts(self) -> None:
...

def send_motor_controls(self, motor_controls:typing.Mapping[int, PyRobstrideMotorControlParams]) -> dict[int, PyRobstrideMotorFeedback]:
...

def get_latest_feedback(self) -> dict[int, PyRobstrideMotorFeedback]:
...

def get_latest_feedback_for(self, motor_id:int) -> PyRobstrideMotorFeedback:
def send_motor_controls(self, motor_controls:typing.Mapping[int, PyRobstrideMotorControlParams], serial:bool) -> dict[int, PyRobstrideMotorFeedback]:
...

def __repr__(self) -> str:
...


class PyRobstrideMotorsSupervisor:
total_commands: int
actual_update_rate: float
serial: bool
def __new__(cls,port_name,motor_infos,verbose = ...,min_update_rate = ...,target_update_rate = ...): ...
def set_position(self, motor_id:int, position:float) -> float:
...
Expand Down Expand Up @@ -102,22 +99,19 @@ class PyRobstrideMotorsSupervisor:
def set_params(self, motor_id:int, params:PyRobstrideMotorControlParams) -> None:
...

def get_total_commands(self, motor_id:int) -> int:
...

def get_failed_commands(self, motor_id:int) -> int:
def failed_commands_for(self, motor_id:int) -> int:
...

def reset_command_counters(self) -> None:
...

def set_min_update_rate(self, rate:float) -> None:
def min_update_rate(self, rate:float) -> None:
...

def set_target_update_rate(self, rate:float) -> None:
def max_update_rate(self, rate:float) -> None:
...

def get_actual_update_rate(self) -> float:
def toggle_serial(self) -> bool:
...


64 changes: 24 additions & 40 deletions actuator/rust/bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,38 +65,23 @@ impl PyRobstrideMotors {
fn send_motor_controls(
&mut self,
motor_controls: HashMap<u8, PyRobstrideMotorControlParams>,
serial: bool,
) -> PyResult<HashMap<u8, PyRobstrideMotorFeedback>> {
let motor_controls: HashMap<u8, RobstrideMotorControlParams> = motor_controls
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect();

self.inner
.send_motor_controls(&motor_controls)
.send_motor_controls(&motor_controls, serial)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?
.into_iter()
.map(|(k, v)| Ok((k, v.into())))
.collect()
}

fn get_latest_feedback(&self) -> HashMap<u8, PyRobstrideMotorFeedback> {
self.inner
.get_latest_feedback()
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect()
}

fn get_latest_feedback_for(&self, motor_id: u8) -> PyResult<PyRobstrideMotorFeedback> {
self.inner
.get_latest_feedback_for(motor_id)
.map(|feedback| feedback.clone().into())
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))
}

fn __repr__(&self) -> PyResult<String> {
let motor_count = self.inner.get_latest_feedback().len();
Ok(format!("PyRobstrideMotors(motor_count={})", motor_count))
Ok(format!("PyRobstrideMotors"))
}
}

Expand Down Expand Up @@ -214,12 +199,11 @@ struct PyRobstrideMotorsSupervisor {
#[pymethods]
impl PyRobstrideMotorsSupervisor {
#[new]
#[pyo3(signature = (port_name, motor_infos, verbose = false, min_update_rate = 10.0, target_update_rate = 50.0))]
#[pyo3(signature = (port_name, motor_infos, verbose = false, target_update_rate = 50.0))]
fn new(
port_name: String,
motor_infos: HashMap<u8, String>,
verbose: bool,
min_update_rate: f64,
target_update_rate: f64,
) -> PyResult<Self> {
let motor_infos = motor_infos
Expand All @@ -230,14 +214,9 @@ impl PyRobstrideMotorsSupervisor {
})
.collect::<PyResult<HashMap<u8, RobstrideMotorType>>>()?;

let controller = RobstrideMotorsSupervisor::new(
&port_name,
&motor_infos,
verbose,
min_update_rate,
target_update_rate,
)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
let controller =
RobstrideMotorsSupervisor::new(&port_name, &motor_infos, verbose, target_update_rate)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;

Ok(PyRobstrideMotorsSupervisor { inner: controller })
}
Expand Down Expand Up @@ -348,13 +327,12 @@ impl PyRobstrideMotorsSupervisor {
Ok(())
}

fn get_total_commands(&self, motor_id: u8) -> PyResult<u64> {
self.inner
.get_total_commands(motor_id)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))
#[getter]
fn total_commands(&self) -> PyResult<u64> {
Ok(self.inner.get_total_commands())
}

fn get_failed_commands(&self, motor_id: u8) -> PyResult<u64> {
fn failed_commands_for(&self, motor_id: u8) -> PyResult<u64> {
self.inner
.get_failed_commands(motor_id)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))
Expand All @@ -365,18 +343,24 @@ impl PyRobstrideMotorsSupervisor {
Ok(())
}

fn set_min_update_rate(&self, rate: f64) -> PyResult<()> {
self.inner.set_min_update_rate(rate);
#[setter]
fn max_update_rate(&self, rate: f64) -> PyResult<()> {
self.inner.set_max_update_rate(rate);
Ok(())
}

fn set_target_update_rate(&self, rate: f64) -> PyResult<()> {
self.inner.set_target_update_rate(rate);
Ok(())
#[getter]
fn actual_update_rate(&self) -> PyResult<f64> {
Ok(self.inner.get_actual_update_rate())
}

fn get_actual_update_rate(&self) -> PyResult<f64> {
Ok(self.inner.get_actual_update_rate())
fn toggle_serial(&self) -> PyResult<bool> {
Ok(self.inner.toggle_serial())
}

#[getter]
fn serial(&self) -> PyResult<bool> {
Ok(self.inner.get_serial())
}
}

Expand Down
1 change: 1 addition & 0 deletions actuator/rust/robstride/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ serialport = "4.5.1"
ctrlc = "3.4.5"
lazy_static = "1.4.0"
spin_sleep = "1.2.1"
nix = "0.26.2"
clap = { version = "4.3", features = ["derive"] }
47 changes: 37 additions & 10 deletions actuator/rust/robstride/src/bin/supervisor.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
use clap::Parser;
use robstride::{motor_type_from_str, MotorType, MotorsSupervisor};
use std::collections::HashMap;
use std::f32::consts::PI;
use std::io::{self, Write};
use std::time::{Duration, Instant};

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg(short, long, help = "Enable verbose output")]
verbose: bool,
#[arg(short, long, help = "Minimum update rate (Hz)", default_value_t = 10.0)]
#[arg(long, help = "Minimum update rate (Hz)", default_value_t = 10.0)]
min_update_rate: f64,
#[arg(short, long, help = "Target update rate (Hz)", default_value_t = 50.0)]
target_update_rate: f64,
#[arg(long, help = "Maximum update rate (Hz)", default_value_t = 1000.0)]
max_update_rate: f64,
}

fn sinusoid(
controller: &MotorsSupervisor,
id: u8,
amplitude: f32,
duration: Duration,
) -> Result<(), Box<dyn std::error::Error>> {
let start = Instant::now();

controller.set_kd(id, 1.0)?;
controller.set_kp(id, 10.0)?;
controller.set_velocity(id, 0.0)?;
controller.set_torque(id, 0.0)?;

while start.elapsed() < duration {
let t = start.elapsed().as_secs_f32();
let pos = amplitude * (2.0 * PI * t).sin();
controller.set_position(id, pos)?;
std::thread::sleep(Duration::from_millis(10));
}

controller.set_position(id, 0.0)?;

Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand Down Expand Up @@ -46,13 +73,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
};
let motor_type = motor_type_from_str(motor_type_input.as_str())?;
let motor_infos: HashMap<u8, MotorType> = HashMap::from([(test_id, motor_type)]);
let controller = MotorsSupervisor::new(
&port_name,
&motor_infos,
args.verbose,
args.min_update_rate,
args.target_update_rate,
)?;
let controller =
MotorsSupervisor::new(&port_name, &motor_infos, args.verbose, args.max_update_rate)?;

println!("Motor Controller Test CLI");
println!("Available commands:");
Expand All @@ -61,6 +83,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" t <torque>");
println!(" kp <kp>");
println!(" kd <kd>");
println!(" sinusoid / s");
println!(" zero / z");
println!(" get_feedback / g");
println!(" pause / w");
Expand Down Expand Up @@ -125,6 +148,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = controller.set_kd(test_id, kd);
println!("Set KD for motor {} to {}", test_id, kd);
}
"sinusoid" | "s" => {
let _ = sinusoid(&controller, test_id, 1.0, Duration::from_secs(1));
println!("Ran motor {} sinusoid test", test_id);
}
"zero" | "z" => {
let _ = controller.add_motor_to_zero(test_id);
println!("Added motor {} to zero list", test_id);
Expand Down
Loading
Loading