#can #odrive #motor-control #rust-bindings

rustodrive

使用CAN协议控制多个ODrive的Rust绑定

1个不稳定版本

0.1.0 2022年7月29日

#470并发

MIT 许可证

65KB
1K SLoC

rustodrive 是一个用于通过CAN协议与ODrive通信的客户端库。

它不仅是一个简单的CAN发送/接收器,还提供了许多方便的结构体和方法,并支持多个线程的安全发送和接收,松散遵循命令查询责任分离(CQRS)范式。只有一个线程被允许发送可以修改ODrive状态的命令,而其他线程则有权限请求任何不会改变状态的任何数据。

为什么允许多线程?

有人可能会想知道为什么需要多线程,对于大多数情况,你可以将其视为一个单线程应用程序,并简单地利用可用的方法。但对我们来说,我们需要开发一个GUI,它应该静默地监听来回发送的命令。这也可以用于调试目的,并允许进行非物理测试的过去数据的回放。

库状态

这个库目前处于早期阶段,不支持所有的CAN命令。然而,大部分艰苦的工作已经完成,应该只需将参数传递到我们的对象中(参见 axis.rsodrivegroup.rs 了解还需完成什么)。

在接下来的几个月里,这个库将处于积极开发状态,因为它正在被用于这里的一个整体项目 AMBER @ UConn

当前功能

  • 安全多线程
  • 设置轴状态、读取编码器值、设置控制模式、设置输入速度或位置

我们打算在未来实现剩余的支持的 CAN消息

示例

// main.rs
use rustodrive::{
    canproxy::CANProxy,
    state::{ODriveAxisState::*, ControlMode, InputMode},
    odrivegroup::ODriveGroup,
    threads::ReadWriteCANThread,
};
use signal_hook::{consts::SIGINT, iterator::Signals};
use std::{error::Error};

fn odrive_main(can_read_write: ReadWriteCANThread) {
    // Specify the CAN ids of all odrives connected
    let odrives = ODriveGroup::new(can_read_write, &[0, 1, 2, 3, 4, 5]);
    odrv.all_axes(|ax| ax.set_state(EncoderIndexSearch));

    odrives.all_axes(|ax| ax.set_state(ClosedLoop));
    odrives.all_axes(|ax| ax.motor.set_control_mode(ControlMode::PositionControl, InputMode::PosFilter));
    odrives.all_axes(|ax| ax.motor.set_input_pos(180.0 / 360.0));

    //odrives.all_axes(|ax| ax.motor.set_input_vel(10.0)); // if we had velocity control enabled
}


// This is useful code to stop threads and exit peacefully
fn main() -> Result<(), Box<dyn Error>> {
    let mut can_proxy = CANProxy::new("can0");

    // We register a thread that is capable of reading state, but also modifying it
    // We can also register a thread that can send "read only" commands.
    can_proxy.register_rw("thread 1", odrive_main);
    can_proxy.register_ro("read only thread", |read_only| {})

    // Turn on the thread to process CAN commands from various threads
    let stop_all = can_proxy.begin();

    // Handle ctrl-c to exit
    let mut signals = Signals::new(&[SIGINT])?;
    for sig in signals.forever() {
        println!("\nQuitting the program {:?}", sig);
        break;
    }

    // Use the hook from `can_proxy.begin()` to clean up the registered threads
    stop_all().unwrap();
    println!("all done!");
    Ok(())
}

文档

您可以使用 cargo doc 构建我们的公共文档,或者要包含私有方法文档,请使用 cargo doc --document-private-items。目前,大部分带有示例的文档都在 CANProxyODriveGroup 中。

贡献 & 许可证

我们非常欢迎拉取请求,并且所有工作都在MIT许可证下可用。

依赖项

~2.5MB
~54K SLoC