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

Hiwonder Reader #16

Merged
merged 13 commits into from
Jan 31, 2025
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
17 changes: 13 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ jobs:
run-base-tests:
timeout-minutes: 10
runs-on: ubuntu-latest
env:
PYO3_PYTHON: /opt/hostedtoolcache/Python/3.11.11/x64/bin/python3.11
PYTHON_INCLUDE_DIR: /opt/hostedtoolcache/Python/3.11.11/x64/include/python3.11
PYTHON_LIB_DIR: /opt/hostedtoolcache/Python/3.11.11/x64/lib
LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.11.11/x64/lib:$LD_LIBRARY_PATH
steps:
- name: Check out repository
uses: actions/checkout@v3
Expand All @@ -32,8 +37,12 @@ jobs:

- name: Install system dependencies
run: |
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install -y libudev-dev pkg-config
sudo apt-get install -y libudev-dev pkg-config python3.11-dev libpython3.11-dev
# Create symlinks to ensure libraries are found
sudo ln -sf /opt/hostedtoolcache/Python/3.11.11/x64/lib/libpython3.11.so /usr/lib/
sudo ln -sf /opt/hostedtoolcache/Python/3.11.11/x64/lib/libpython3.11.so.1.0 /usr/lib/

- name: Restore cache
id: restore-cache
Expand All @@ -42,10 +51,10 @@ jobs:
path: |
${{ env.pythonLocation }}
.mypy_cache/
key: python-requirements-${{ env.pythonLocation }}-${{ github.event.pull_request.base.sha || github.sha }}
key: new-python-requirements-${{ env.pythonLocation }}-${{ github.event.pull_request.base.sha || github.sha }}
restore-keys: |
python-requirements-${{ env.pythonLocation }}
python-requirements-
new-python-requirements-${{ env.pythonLocation }}
new-python-requirements-

- name: Install package
run: |
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ members = [
resolver = "2"

[workspace.package]
version = "0.2.1"
version = "0.2.2"
authors = ["Wesley Maa <wesley@kscale.dev>"]
edition = "2021"
description = "IMU package"
Expand Down
2 changes: 1 addition & 1 deletion imu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ crate-type = ["rlib"]

[dependencies]
hexmove = "0.1.6"
hiwonder = "0.2.0"
hiwonder = "0.2.2"
linux_bno055 = "0.0.6"
socketcan = "3.3.0"
log = "0.4"
2 changes: 1 addition & 1 deletion imu/bindings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ name = "bindings"
crate-type = ["cdylib", "rlib"]

[dependencies]
pyo3 = { version = ">= 0.21.0", features = ["extension-module"] }
pyo3 = { version = ">= 0.21.0", features = ["extension-module", "auto-initialize"] }
pyo3-stub-gen = ">= 0.6.0"

# Other packages in the workspace.
Expand Down
59 changes: 42 additions & 17 deletions imu/bindings/src/hiwonder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use hiwonder::IMU;
use hiwonder::{HiwonderReader, ImuData};
use pyo3::prelude::*;
use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods};
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -36,40 +36,65 @@ impl PyImuData {
}
}

impl From<ImuData> for PyImuData {
fn from(data: ImuData) -> Self {
PyImuData {
accelerometer: data.accelerometer.to_vec(),
gyroscope: data.gyroscope.to_vec(),
angle: data.angle.to_vec(),
quaternion: data.quaternion.to_vec(),
}
}
}

#[gen_stub_pyclass]
#[pyclass(name = "HiwonderImu")]
pub struct PyHiwonderImu {
inner: Arc<Mutex<IMU>>,
inner: Arc<Mutex<HiwonderReader>>,
}

#[gen_stub_pymethods]
#[pymethods]
impl PyHiwonderImu {
#[new]
fn new(interface: String, baud_rate: u32) -> PyResult<Self> {
let imu = IMU::new(&interface, baud_rate)
let reader = HiwonderReader::new(&interface, baud_rate)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
Ok(PyHiwonderImu {
inner: Arc::new(Mutex::new(imu)),
inner: Arc::new(Mutex::new(reader)),
})
}

fn read_data(&mut self) -> PyResult<Option<PyObject>> {
let mut imu = self
fn get_data(&self) -> PyResult<PyImuData> {
let reader = self
.inner
.lock()
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
let data = reader
.get_data()
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
Ok(PyImuData::from(data))
}

match imu.read_data() {
Ok(Some((accel, gyro, angle, quat))) => Python::with_gil(|py| {
let data =
PyImuData::new(accel.to_vec(), gyro.to_vec(), angle.to_vec(), quat.to_vec());
Ok(Some(Py::new(py, data)?.into_py(py)))
}),
Ok(None) => Ok(None),
Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(
e.to_string(),
)),
}
fn reset(&self) -> PyResult<()> {
let reader = self
.inner
.lock()
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
reader
.reset()
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
Ok(())
}

fn stop(&self) -> PyResult<()> {
let reader = self
.inner
.lock()
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
reader
.stop()
.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?;
Ok(())
}
}
2 changes: 1 addition & 1 deletion imu/hiwonder/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "hiwonder"
version = "0.2.1"
version = "0.2.3"
readme = "README.md"
description = "Interface for interacting with Hiwonder IMUs"
edition = "2021"
Expand Down
84 changes: 24 additions & 60 deletions imu/hiwonder/src/bin/read_hiwonder.rs
Original file line number Diff line number Diff line change
@@ -1,79 +1,43 @@
use hiwonder::{ImuFrequency, IMU};
use hiwonder::{ImuFrequency, HiwonderReader};
use std::io;

//* run by `cargo run --bin log` */
#[derive(Debug)]
struct IMUData {
acc_x: f32,
acc_y: f32,
acc_z: f32,
gyro_x: f32,
gyro_y: f32,
gyro_z: f32,
angle_x: f32,
angle_y: f32,
angle_z: f32,
quaternion_x: f32,
quaternion_y: f32,
quaternion_z: f32,
quaternion_w: f32,
}

impl From<([f32; 3], [f32; 3], [f32; 3], [f32; 4])> for IMUData {
fn from((acc, gyro, angle, quaternion): ([f32; 3], [f32; 3], [f32; 3], [f32; 4])) -> Self {
IMUData {
acc_x: acc[0],
acc_y: acc[1],
acc_z: acc[2],
gyro_x: gyro[0],
gyro_y: gyro[1],
gyro_z: gyro[2],
angle_x: angle[0],
angle_y: angle[1],
angle_z: angle[2],
quaternion_x: quaternion[0],
quaternion_y: quaternion[1],
quaternion_z: quaternion[2],
quaternion_w: quaternion[3],
}
}
}
use std::thread;
use std::time::Duration;

fn main() -> io::Result<()> {
let mut imu =
IMU::new("/dev/ttyUSB0", 9600).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let reader =
HiwonderReader::new("/dev/ttyUSB0", 9600).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

match imu.set_frequency(ImuFrequency::Hz20) {
match reader.set_frequency(ImuFrequency::Hz200) {
Ok(_) => println!("Set frequency to 200hz"),
Err(e) => println!("Failed to set frequency: {}", e),
}

loop {
match imu.read_data() {
Ok(Some(data)) => {
let data = IMUData::from(data);
match reader.get_data() {
Ok(data) => {
println!(
"acc: x: {: >10.3} y: {: >10.3} z: {: >10.3}\n\
gyro: x: {: >10.3} y: {: >10.3} z: {: >10.3}\n\
angle: x: {: >10.3} y: {: >10.3} z: {: >10.3}\n\
quaternion: x: {: >10.3} y: {: >10.3} z: {: >10.3} w: {: >10.3}",
data.acc_x,
data.acc_y,
data.acc_z,
data.gyro_x,
data.gyro_y,
data.gyro_z,
data.angle_x,
data.angle_y,
data.angle_z,
data.quaternion_x,
data.quaternion_y,
data.quaternion_z,
data.quaternion_w
data.accelerometer[0],
data.accelerometer[1],
data.accelerometer[2],
data.gyroscope[0],
data.gyroscope[1],
data.gyroscope[2],
data.angle[0],
data.angle[1],
data.angle[2],
data.quaternion[0],
data.quaternion[1],
data.quaternion[2],
data.quaternion[3],
);
}
Ok(None) => (), // No complete data available yet
Err(e) => eprintln!("Error reading from serial port: {}", e),
Err(e) => eprintln!("Error reading from IMU: {}", e),
}

thread::sleep(Duration::from_millis(10));
}
}
Loading
Loading