From b5c341b413d63d45f2b342213c7d9401c6c9eb33 Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Mon, 4 Nov 2024 23:13:07 +0100 Subject: [PATCH] initial --- .cargo/config.toml | 3 + .gitignore | 1 + Cargo.lock | 290 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 10 ++ run-on-pi.sh | 15 +++ src/main.rs | 88 ++++++++++++++ src/motor.rs | 65 ++++++++++ 7 files changed, 472 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100755 run-on-pi.sh create mode 100644 src/main.rs create mode 100644 src/motor.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..43b94f5 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ + +[target.arm-unknown-linux-gnueabihf] +linker = "arm-none-linux-gnueabihf-gcc" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3f4098b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,290 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "3.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69c5a7f9997be616e47f0577ee38c91decb33392c5be4866494f34cdf329a9aa" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "ctrlc" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" +dependencies = [ + "nix", + "winapi", +] + +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" + +[[package]] +name = "hashbrown" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "motor" +version = "0.1.0" +dependencies = [ + "clap", + "ctrlc", + "wiringpi", +] + +[[package]] +name = "nix" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f17df307904acd05aa8e32e97bb20f2a0df1728bbc2d771ae8f9a90463441e9" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "os_str_bytes" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wiringpi" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e065de8885b0ae1e1928eb3bf905c7d0a0a28ceab823852e9ffe123a126f3d" +dependencies = [ + "cc", + "glob", + "libc", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4d8d477 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "motor" +version = "0.1.0" +description = "raspberry pi stepper motor controller" +edition = "2021" + +[dependencies] +clap = { version = "3.2.10", features = ["derive"] } +ctrlc = "3.2.2" +wiringpi = "0.2.4" diff --git a/run-on-pi.sh b/run-on-pi.sh new file mode 100755 index 0000000..6d73b54 --- /dev/null +++ b/run-on-pi.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +NAME="$(pwd | rg "/[^/]*\$" -o | replace "/" "")" + +echo "Running $NAME" + +set -x +set -r + +cargo build -vvv --target arm-unknown-linux-gnueabihf $@ + +scp "target/arm-unknown-linux-gnueabihf/release/$NAME" zenit.lan:. +ssh zenit.lan "./$NAME" + + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5bb1d46 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,88 @@ +mod motor; + +use crate::motor::{Motor, MotorConfig, MotorPinMappings, MotorPins}; +use clap::{Parser, Subcommand}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::Duration; + +#[derive(Parser)] +struct Opt { + #[clap(subcommand)] + command: Command, +} + +#[derive(Subcommand)] +enum Command { + /// Reset motor pins, making sure the motor is off + Reset, + + /// Turn the motor + Turn { + /// The direction to turn + #[clap(subcommand)] + direction: Direction, + + /// The number of full stepper motor steps to turn, if not specified the motor will turn + /// forever + #[clap(long, short)] + steps: Option, + + /// The time in milliseconds between each tick of the stepper motor + #[clap(long, short, default_value = "7")] + motor_sleep_time: u64, + }, +} + +#[derive(Clone, Copy, Subcommand)] +pub enum Direction { + Left, + Right, +} + +fn main() { + let opt = Opt::parse(); + let exit = Box::leak(Box::new(AtomicBool::new(false))); + + ctrlc::set_handler(|| { + exit.store(true, Ordering::Release); + }) + .expect("Error setting Ctrl-C handler"); + + let pi = wiringpi::setup(); + + const PIN_MAPPINGS: MotorPinMappings = [0, 2, 3, 4]; + + match &opt.command { + Command::Reset => { + let _ = MotorPins::new(&pi, PIN_MAPPINGS); + } + Command::Turn { + direction, + steps, + motor_sleep_time, + } => { + let motor_config = MotorConfig { + pin_mappings: PIN_MAPPINGS, + sleep_time: Duration::from_millis(*motor_sleep_time), + }; + + let mut motor = Motor::new(&pi, &motor_config); + for i in 0.. { + if exit.load(Ordering::Acquire) { + break; + } + + motor.spin_step(*direction); + if i % 100 == 0 { + println!("{i}"); + } + + if let Some(steps) = steps { + if i >= *steps { + break; + } + } + } + } + } +} diff --git a/src/motor.rs b/src/motor.rs new file mode 100644 index 0000000..dcbc1c9 --- /dev/null +++ b/src/motor.rs @@ -0,0 +1,65 @@ +use crate::Direction; +use std::thread::sleep; +use std::time::Duration; +use wiringpi::pin::{self, OutputPin, Value::*}; +use wiringpi::WiringPi; + +pub struct Motor { + pins: MotorPins, + sleep_time: Duration, +} + +pub struct MotorConfig { + pub pin_mappings: [u16; 4], + pub sleep_time: Duration, +} + +pub struct MotorPins { + pins: [OutputPin; 4], +} + +pub type MotorPinMappings = [u16; 4]; + +impl MotorPins { + pub fn new(wiringpi: &WiringPi, pin_mappings: MotorPinMappings) -> Self { + MotorPins { + pins: pin_mappings.map(|id| wiringpi.output_pin(id)), + } + } + + pub fn set(&mut self, values: [pin::Value; 4]) { + for (pin, &value) in self.pins.iter_mut().zip(values.iter()) { + pin.digital_write(value); + } + } +} + +impl Motor { + pub fn new(wiringpi: &WiringPi, config: &MotorConfig) -> Self { + let pins = MotorPins::new(wiringpi, config.pin_mappings); + Motor { + sleep_time: config.sleep_time, + pins, + } + } + + pub fn spin_step(&mut self, direction: Direction) { + let mut pin_states = [High, Low, Low, Low]; + + for _ in 0..pin_states.len() { + self.pins.set(pin_states); + match direction { + Direction::Right => pin_states.rotate_right(1), + Direction::Left => pin_states.rotate_left(1), + } + sleep(self.sleep_time); + } + } +} + +impl Drop for MotorPins { + fn drop(&mut self) { + eprintln!("Resetting motor"); + self.set([Low, Low, Low, Low]) + } +}