Skip to content

Commit

Permalink
more fixes (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
codekansas authored Oct 14, 2024
1 parent 6656e3c commit 4eacca2
Show file tree
Hide file tree
Showing 7 changed files with 444 additions and 324 deletions.
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

0 comments on commit 4eacca2

Please sign in to comment.