Compare commits

...

10 commits

Author SHA1 Message Date
Frederik Menke 5954377a89 Depend on build for run 2024-01-13 22:45:36 +01:00
Frederik Menke bc39b14fef Use rsync again 2024-01-13 22:42:12 +01:00
Frederik Menke dd76ad51ad Kill red if still running 2024-01-13 22:35:29 +01:00
Frederik Menke 1e0484cdcd Run cross-compiled binary 2024-01-09 00:39:52 +01:00
Frederik Menke 5795d0f0bd Use pre-build instead of Dockerfile 2024-01-08 23:07:30 +01:00
Frederik Menke b5129ff3e6 Cross compile using cargo-cross 2024-01-08 22:34:49 +01:00
Frederik Menke 36fddc99c8 Add scaffolding for video aimation
Using motion-canvas requires a whole bunch of crap
2024-01-06 23:56:21 +01:00
Frederik Menke b79aaca74d Remove TODOs 2024-01-01 13:29:53 +01:00
Frederik Menke d3da56b3e5 Fix warnings 2024-01-01 13:22:26 +01:00
Frederik Menke b47a27cb86 Jog using absolute movements 2024-01-01 13:05:11 +01:00
18 changed files with 1488 additions and 90 deletions

View file

@ -0,0 +1,15 @@
# Generated files
node_modules
output
dist
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
{
"name": "gcode_animation",
"private": true,
"version": "0.0.0",
"scripts": {
"start": "vite",
"serve": "vite",
"build": "tsc && vite build"
},
"dependencies": {
"@motion-canvas/core": "^3.12.1",
"@motion-canvas/2d": "^3.12.4",
"@motion-canvas/ffmpeg": "^1.1.0"
},
"devDependencies": {
"@motion-canvas/ui": "^3.12.4",
"@motion-canvas/vite-plugin": "^3.12.3",
"typescript": "^5.2.2",
"vite": "^4.0.0"
}
}

View file

@ -0,0 +1 @@
/// <reference types="@motion-canvas/core/project" />

View file

@ -0,0 +1,32 @@
{
"version": 0,
"shared": {
"background": null,
"range": [
0,
null
],
"size": {
"x": 1920,
"y": 1080
},
"audioOffset": 0
},
"preview": {
"fps": 30,
"resolutionScale": 1
},
"rendering": {
"fps": 60,
"resolutionScale": 1,
"colorSpace": "srgb",
"exporter": {
"name": "@motion-canvas/core/image-sequence",
"options": {
"fileType": "image/png",
"quality": 100,
"groupByScene": false
}
}
}
}

View file

@ -0,0 +1,7 @@
import {makeProject} from '@motion-canvas/core';
import example from './scenes/example?scene';
export default makeProject({
scenes: [example],
});

View file

@ -0,0 +1,5 @@
{
"version": 0,
"timeEvents": [],
"seed": 1794886323
}

View file

@ -0,0 +1,22 @@
import { makeScene2D, Circle } from '@motion-canvas/2d';
import { all, createRef } from '@motion-canvas/core';
export default makeScene2D(function*(view) {
const myCircle = createRef<Circle>();
view.add(
<Circle
ref={myCircle}
// try changing these properties:
x={-300}
width={140}
height={140}
fill="#e13238"
/>,
);
yield* all(
myCircle().position.x(300, 1).to(-300, 1),
myCircle().fill('#e6a700', 1).to('#e13238', 1),
);
});

View file

@ -0,0 +1,4 @@
{
"extends": "@motion-canvas/2d/tsconfig.project.json",
"include": ["src"]
}

View file

@ -0,0 +1,10 @@
import {defineConfig} from 'vite';
import motionCanvas from '@motion-canvas/vite-plugin';
import ffmpeg from '@motion-canvas/ffmpeg';
export default defineConfig({
plugins: [
motionCanvas(),
ffmpeg(),
],
});

4
red/Cross.toml Normal file
View file

@ -0,0 +1,4 @@
[target.armv7-unknown-linux-gnueabihf]
pre-build = [
"dpkg --add-architecture armhf && apt-get update && apt-get install --assume-yes apt-utils libudev-dev:armhf",
]

View file

@ -1,12 +1,12 @@
url := "olimex@muele.local"
build:
cargo build --target=armv7-unknown-linux-gnueabihf
cross build --target=armv7-unknown-linux-gnueabihf
rrun:
#scp -r ./src {{url}}:red/
rsync -rvu --filter=':- .gitignore' ../red {{url}}:
ssh {{url}} "cd red; RUST_BACKTRACE=1 /home/olimex/.cargo/bin/cargo run;"
run: build
ssh {{url}} "killall red" || echo "Failed to kill process. Maybe it's not running"
rsync -vu ./target/armv7-unknown-linux-gnueabihf/debug/red {{url}}:
ssh {{url}} "RUST_BACKTRACE=1 ./red"
rdown:
ssh {{url}} "sudo /usr/sbin/poweroff"

View file

@ -8,7 +8,7 @@ use std::sync::Arc;
use std::sync::Mutex;
use std::thread::sleep;
use std::time::Duration;
use tokio::sync::{mpsc, oneshot};
use tokio::sync::mpsc;
#[derive(Debug)]
pub enum Axis {
@ -42,7 +42,6 @@ pub enum GamepadEvent {
/// ```
pub struct Gamepad {
speed_setpoint: Mutex<(f32, f32, f32)>,
terminator: oneshot::Sender<()>,
}
impl Gamepad {
@ -50,21 +49,24 @@ impl Gamepad {
///
/// The tasks are terminated on drop.
pub async fn new() -> Result<Arc<Self>, gilrs::Error> {
let (terminate_tx, mut terminate_rx) = oneshot::channel();
let (gamepad_tx, gamepad_rx) = mpsc::channel(8);
let res = Arc::new(Gamepad {
speed_setpoint: Mutex::new((0.0, 0.0, 0.0)),
terminator: terminate_tx,
});
tokio::task::spawn_blocking(move || {
let mut gilrs = Gilrs::new().unwrap();
for (_id, gamepad) in gilrs.gamepads() {
println!("{} is {:?}", gamepad.name(), gamepad.power_info());
}
while let Err(oneshot::error::TryRecvError::Empty) = terminate_rx.try_recv() {
loop {
sleep(Duration::from_millis(1));
if let Some(event) = gilrs.next_event() {
Self::map_event(event).map(|event| gamepad_tx.blocking_send(event));
if let Some(internal_event) = Self::map_event(event) {
if gamepad_tx.blocking_send(internal_event).is_err() {
// receiver dropped
break;
}
}
}
}
});

View file

@ -33,8 +33,8 @@ pub type PrinterVec = Vector3D<f64, PrinterUnits>;
/// Jog the gantry by pumping loads of gcode into the printer board
pub async fn jog(gamepad: Arc<Gamepad>, mut printer: Printer) -> Never {
printer.use_relative_movements().await.unwrap();
println!("Using relative movements");
printer.use_absolute_movements().await.unwrap();
println!("Using absolute movements");
loop {
let (setpoint_x, setpoint_y, setpoint_z) = gamepad.speed_setpoint();
@ -48,11 +48,21 @@ pub async fn jog(gamepad: Arc<Gamepad>, mut printer: Printer) -> Never {
continue;
}
let velocity = distance.length() / (TIME_PER_MOVEMENT.as_secs_f64() / 60.0);
let old_postion = printer.state.position;
printer
.move_relative(distance.x, distance.y, distance.z, velocity.into())
.move_absolute(
old_postion.x + distance.x,
old_postion.y + distance.y,
old_postion.z + distance.z,
velocity.into(),
)
.await
.expect("Failed to send movement command!");
println!(
"New position {pos:?}",
pos = printer.printer_state().position
);
// Wait for one command time if buffer is overfull, wait for half that time if buffer is
// filled *just* right.
let fill_level = printer.maximum_capacity() - printer.remaining_capacity();

View file

@ -1,3 +1,4 @@
pub mod gamepad;
pub mod jogger;
pub mod printer;
pub mod spindle;

View file

@ -1,38 +1,11 @@
#![warn(rust_2018_idioms)]
use futures::never::Never;
use i2c_linux::I2c;
use red::gamepad;
use red::jogger;
use red::printer::Printer;
use std::path::Path;
use std::time::Duration;
use tokio_serial::SerialPortInfo;
const DEFAULT_TTY: &str = "/dev/ttyUSB0";
const I2C_ADDRESS_EXTENDER: u8 = 25;
const I2C_REGISTER_SPINDLE_SPEED: u8 = 0;
// available i2c functionality on the device as reported from
// the i2c library
// TENBIT_ADDR
// SMBUS_PEC
// SMBUS_QUICK
// SMBUS_READ_BYTE
// SMBUS_WRITE_BYTE
// SMBUS_READ_BYTE_DATA
// SMBUS_WRITE_BYTE_DATA
// SMBUS_READ_WORD_DATA
// SMBUS_WRITE_WORD_DATA
// SMBUS_PROC_CALL
// SMBUS_WRITE_BLOCK_DATA
// SMBUS_READ_I2C_BLOCK
// SMBUS_WRITE_I2C_BLOCK
// SMBUS_BYTE
// SMBUS_BYTE_DATA
// SMBUS_WORD_DATA
// SMBUS_I2C_BLOCK
// SMBUS_EMUL
#[tokio::main]
async fn main() -> Never {
println!("Entering App");
@ -54,42 +27,3 @@ async fn main() -> Never {
.unwrap();
jogger::jog(gamepad, printer).await
}
async fn write_to_spindle() -> Never {
let mut i2c = I2c::from_path("/dev/i2c-0").unwrap();
let mut value = 0;
println!("functionality: {:?}", i2c.i2c_functionality());
i2c.smbus_set_slave_address(I2C_ADDRESS_EXTENDER.into(), false)
.unwrap();
loop {
value = u16::MAX - value;
match i2c.smbus_write_word_data(I2C_REGISTER_SPINDLE_SPEED, value) {
Ok(()) => println!("Wrote {} successfully", value),
Err(e) => println!("Error writing to device: {}", e),
};
tokio::time::sleep(Duration::from_secs(1)).await;
}
}
async fn write_to_printer() -> Never {
let mut printer = Printer::connect(DEFAULT_TTY).await.unwrap();
printer.auto_home(true, true, true).await.unwrap();
loop {
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
printer.move_relative(50.0, 50.0, 5.0, None).await.unwrap();
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
printer.move_relative(25.0, 25.0, 5.0, None).await.unwrap();
}
}
async fn jog() -> Never {
let jogger = gamepad::Gamepad::new().await.unwrap();
loop {
tokio::time::sleep(Duration::from_secs(2)).await;
let setpoint = jogger.speed_setpoint();
println!(
"speed setpoint: {} {} {}",
setpoint.0, setpoint.1, setpoint.2
);
}
}

View file

@ -39,9 +39,9 @@ pub enum PrinterError {
#[derive(Debug, Clone, Copy)]
pub struct PrinterPosition {
x: f64,
y: f64,
z: f64,
pub x: f64,
pub y: f64,
pub z: f64,
}
pub enum MovementMode {
@ -50,8 +50,8 @@ pub enum MovementMode {
}
pub struct State {
position: PrinterPosition,
movement_mode: MovementMode,
pub position: PrinterPosition,
pub movement_mode: MovementMode,
}
pub struct Printer {
@ -69,7 +69,6 @@ impl Printer {
self.serial_tx.send(command_text.clone()).await.unwrap();
let mut reply = String::with_capacity(RECV_BUFFER_CAPACITY);
loop {
// TODO: add timeout below
let line = self
.serial_rx
.next()
@ -135,8 +134,8 @@ impl Printer {
x: 0.0,
y: 0.0,
z: 0.0,
}, // TODO: Fill this value through sending a command below
movement_mode: MovementMode::AbsoluteMovements, // TODO: Fill this value through sending a command below
},
movement_mode: MovementMode::AbsoluteMovements,
},
last_buffer_capacity: 0, // this is updated on the next call to `send_gcode()`
maximum_buffer_capacity: 0, // this is updated on the next call to `send_gcode()`
@ -163,6 +162,10 @@ impl Printer {
Ok(res)
}
pub fn printer_state(&self) -> &State {
&self.state
}
/// The maximum capacity of the machines GCODE buffer.
pub fn maximum_capacity(&self) -> usize {
self.maximum_buffer_capacity
@ -289,14 +292,14 @@ impl Printer {
x: f64,
y: f64,
z: f64,
velocity: f64,
velocity: Option<f64>,
) -> Result<(), PrinterError> {
let command = G0Command {
x: Some(x),
y: Some(y),
z: Some(z),
e: None, // Machine has no e
velocity: Some(velocity),
velocity,
};
if let MovementMode::RelativeMovements = self.state.movement_mode {
self.use_absolute_movements().await?;

43
red/src/spindle/mod.rs Normal file
View file

@ -0,0 +1,43 @@
use futures::never::Never;
use i2c_linux::I2c;
use std::time::Duration;
const I2C_ADDRESS_EXTENDER: u8 = 25;
const I2C_REGISTER_SPINDLE_SPEED: u8 = 0;
// available i2c functionality on the device as reported from
// the i2c library
// TENBIT_ADDR
// SMBUS_PEC
// SMBUS_QUICK
// SMBUS_READ_BYTE
// SMBUS_WRITE_BYTE
// SMBUS_READ_BYTE_DATA
// SMBUS_WRITE_BYTE_DATA
// SMBUS_READ_WORD_DATA
// SMBUS_WRITE_WORD_DATA
// SMBUS_PROC_CALL
// SMBUS_WRITE_BLOCK_DATA
// SMBUS_READ_I2C_BLOCK
// SMBUS_WRITE_I2C_BLOCK
// SMBUS_BYTE
// SMBUS_BYTE_DATA
// SMBUS_WORD_DATA
// SMBUS_I2C_BLOCK
// SMBUS_EMUL
pub async fn write_to_spindle() -> Never {
let mut i2c = I2c::from_path("/dev/i2c-0").unwrap();
let mut value = 0;
println!("functionality: {:?}", i2c.i2c_functionality());
i2c.smbus_set_slave_address(I2C_ADDRESS_EXTENDER.into(), false)
.unwrap();
loop {
value = u16::MAX - value;
match i2c.smbus_write_word_data(I2C_REGISTER_SPINDLE_SPEED, value) {
Ok(()) => println!("Wrote {} successfully", value),
Err(e) => println!("Error writing to device: {}", e),
};
tokio::time::sleep(Duration::from_secs(1)).await;
}
}