Impl fns on printer

This commit is contained in:
Frederik Menke 2024-01-01 01:24:23 +01:00
parent 8f8d2ffaa2
commit eaab62ab88
3 changed files with 136 additions and 53 deletions

View file

@ -1,5 +1,4 @@
use crate::gamepad::Gamepad; use crate::gamepad::Gamepad;
use crate::printer::gcode::{G0Command, G91Command};
use crate::printer::Printer; use crate::printer::Printer;
use euclid::{vec3, Vector3D}; use euclid::{vec3, Vector3D};
use futures::never::Never; use futures::never::Never;
@ -34,8 +33,8 @@ pub type PrinterVec = Vector3D<f64, PrinterUnits>;
/// Jog the gantry by pumping loads of gcode into the printer board /// Jog the gantry by pumping loads of gcode into the printer board
pub async fn jog(gamepad: Arc<Gamepad>, mut printer: Printer) -> Never { pub async fn jog(gamepad: Arc<Gamepad>, mut printer: Printer) -> Never {
printer.send_gcode(G91Command).await.unwrap(); printer.use_relative_movements().await.unwrap();
println!("Sent G91Command"); println!("Using relative movements");
loop { loop {
let (setpoint_x, setpoint_y, setpoint_z) = gamepad.speed_setpoint(); let (setpoint_x, setpoint_y, setpoint_z) = gamepad.speed_setpoint();
@ -49,15 +48,8 @@ pub async fn jog(gamepad: Arc<Gamepad>, mut printer: Printer) -> Never {
continue; continue;
} }
let velocity = distance.length() / (TIME_PER_MOVEMENT.as_secs_f64() / 60.0); let velocity = distance.length() / (TIME_PER_MOVEMENT.as_secs_f64() / 60.0);
let command = G0Command {
x: distance.x.into(),
y: distance.y.into(),
z: distance.z.into(),
e: None,
velocity: velocity.into(),
};
printer printer
.send_gcode(command) .move_relative(distance.x, distance.y, distance.z, velocity.into())
.await .await
.expect("Failed to send movement command!"); .expect("Failed to send movement command!");
@ -66,10 +58,12 @@ pub async fn jog(gamepad: Arc<Gamepad>, mut printer: Printer) -> Never {
let fill_level = printer.maximum_capacity() - printer.remaining_capacity(); let fill_level = printer.maximum_capacity() - printer.remaining_capacity();
println!("remaining capacity: {}", printer.remaining_capacity()); println!("remaining capacity: {}", printer.remaining_capacity());
println!("fill level: {}", fill_level); println!("fill level: {}", fill_level);
if fill_level > TARGET_BUFER_FILL_LEVEL { match fill_level.cmp(&TARGET_BUFER_FILL_LEVEL) {
sleep(LONG_COMMAND_DELAY).await; std::cmp::Ordering::Equal => {
} else if fill_level == TARGET_BUFER_FILL_LEVEL { sleep(LONG_COMMAND_DELAY / SHORT_COMMAND_DELAY_DIVIDER).await
sleep(LONG_COMMAND_DELAY / SHORT_COMMAND_DELAY_DIVIDER).await; }
std::cmp::Ordering::Greater => sleep(LONG_COMMAND_DELAY).await,
_ => {}
} }
} }
} }

View file

@ -3,7 +3,6 @@ use futures::never::Never;
use i2c_linux::I2c; use i2c_linux::I2c;
use red::gamepad; use red::gamepad;
use red::jogger; use red::jogger;
use red::printer::gcode::*;
use red::printer::Printer; use red::printer::Printer;
use std::path::Path; use std::path::Path;
use std::time::Duration; use std::time::Duration;
@ -33,6 +32,7 @@ const I2C_REGISTER_SPINDLE_SPEED: u8 = 0;
// SMBUS_WORD_DATA // SMBUS_WORD_DATA
// SMBUS_I2C_BLOCK // SMBUS_I2C_BLOCK
// SMBUS_EMUL // SMBUS_EMUL
#[tokio::main] #[tokio::main]
async fn main() -> Never { async fn main() -> Never {
println!("Entering App"); println!("Entering App");
@ -73,34 +73,12 @@ async fn write_to_spindle() -> Never {
async fn write_to_printer() -> Never { async fn write_to_printer() -> Never {
let mut printer = Printer::connect(DEFAULT_TTY).await.unwrap(); let mut printer = Printer::connect(DEFAULT_TTY).await.unwrap();
printer.send_gcode(M114Command::new()).await.unwrap(); printer.auto_home(true, true, true).await.unwrap();
printer
.send_gcode(G28Command::new(true, true, true))
.await
.unwrap();
loop { loop {
tokio::time::sleep(std::time::Duration::from_secs(5)).await; tokio::time::sleep(std::time::Duration::from_secs(5)).await;
printer printer.move_relative(50.0, 50.0, 5.0, None).await.unwrap();
.send_gcode(G0Command {
x: Some(50.0),
y: Some(50.0),
z: Some(5.0),
e: None,
velocity: None,
})
.await
.unwrap();
tokio::time::sleep(std::time::Duration::from_secs(5)).await; tokio::time::sleep(std::time::Duration::from_secs(5)).await;
printer printer.move_relative(25.0, 25.0, 5.0, None).await.unwrap();
.send_gcode(G0Command {
x: Some(25.0),
y: Some(25.0),
z: Some(5.0),
e: None,
velocity: None,
})
.await
.unwrap();
} }
} }

View file

@ -6,7 +6,7 @@ use futures::sink::SinkExt;
use futures::stream::{SplitSink, SplitStream, StreamExt}; use futures::stream::{SplitSink, SplitStream, StreamExt};
use regex::Regex; use regex::Regex;
use std::time::Duration; use std::time::Duration;
use std::{fmt::Write, io, rc::Rc, str}; use std::{fmt::Write, io, str};
use tokio; use tokio;
use tokio::time::timeout; use tokio::time::timeout;
use tokio_serial::{SerialPortBuilderExt, SerialStream}; use tokio_serial::{SerialPortBuilderExt, SerialStream};
@ -16,7 +16,7 @@ pub use gcode::{GcodeCommand, GcodeReply};
use crate::printer::gcode::{G91Command, M114Command}; use crate::printer::gcode::{G91Command, M114Command};
use self::gcode::GcodeReplyError; use self::gcode::{G0Command, G28Command, G90Command, GcodeReplyError};
/// Recv buffer string will be initialized with this capacity. /// Recv buffer string will be initialized with this capacity.
/// This should fit a simple "OK Pnn Bn" reply for GCODE commands that /// This should fit a simple "OK Pnn Bn" reply for GCODE commands that
@ -40,12 +40,18 @@ pub struct PrinterPosition {
z: f64, z: f64,
} }
pub enum MovementMode {
AbsoluteMovements,
RelativeMovements,
}
pub struct State { pub struct State {
position: (f64, f64, f64, f64), position: PrinterPosition,
movement_mode: MovementMode,
} }
pub struct Printer { pub struct Printer {
pub state: Rc<State>, pub state: State,
serial_tx: SplitSink<Framed<SerialStream, LineCodec>, String>, serial_tx: SplitSink<Framed<SerialStream, LineCodec>, String>,
serial_rx: SplitStream<Framed<SerialStream, LineCodec>>, serial_rx: SplitStream<Framed<SerialStream, LineCodec>>,
last_buffer_capacity: usize, last_buffer_capacity: usize,
@ -54,10 +60,7 @@ pub struct Printer {
impl Printer { impl Printer {
/// Send gcode to the printer and parse its reply /// Send gcode to the printer and parse its reply
pub async fn send_gcode<T: GcodeCommand>( async fn send_gcode<T: GcodeCommand>(&mut self, command: T) -> Result<T::Reply, PrinterError> {
&mut self,
command: T,
) -> Result<T::Reply, PrinterError> {
let command_text = format!("{}\n", command.command()); let command_text = format!("{}\n", command.command());
self.serial_tx.send(command_text.clone()).await.unwrap(); self.serial_tx.send(command_text.clone()).await.unwrap();
let mut reply = String::with_capacity(RECV_BUFFER_CAPACITY); let mut reply = String::with_capacity(RECV_BUFFER_CAPACITY);
@ -94,7 +97,7 @@ impl Printer {
.expect("Unable to set serial port exclusive to false"); .expect("Unable to set serial port exclusive to false");
let connection = LineCodec.framed(port); let connection = LineCodec.framed(port);
let (mut serial_tx, mut serial_rx) = connection.split(); let (serial_tx, mut serial_rx) = connection.split();
// The printer will send some info after connecting for the first time. We need to wait for this // The printer will send some info after connecting for the first time. We need to wait for this
// to be received as it will otherwise stop responding for some reason: // to be received as it will otherwise stop responding for some reason:
@ -126,9 +129,14 @@ impl Printer {
let mut res = Printer { let mut res = Printer {
serial_rx, serial_rx,
serial_tx, serial_tx,
state: Rc::new(State { state: State {
position: (0.0, 0.0, 0.0, 0.0), position: PrinterPosition {
}), 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
},
last_buffer_capacity: 0, // this is updated on the next call to `send_gcode()` 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()` maximum_buffer_capacity: 0, // this is updated on the next call to `send_gcode()`
}; };
@ -171,6 +179,109 @@ impl Printer {
.parse() .parse()
.map_err(|_| make_err()) .map_err(|_| make_err())
} }
pub async fn use_absolute_movements(&mut self) -> Result<(), PrinterError> {
self.state.movement_mode = MovementMode::AbsoluteMovements;
self.send_gcode(G90Command).await
}
pub async fn use_relative_movements(&mut self) -> Result<(), PrinterError> {
self.state.movement_mode = MovementMode::RelativeMovements;
self.send_gcode(G91Command).await
}
/// Home the printer using the hardware endstops
///
/// # Arguments
/// * `x, y, z` - Whether the axis should be homed. Axis that are set to `false` will not be
/// homed.
pub async fn auto_home(&mut self, x: bool, y: bool, z: bool) -> Result<(), PrinterError> {
let res = self.send_gcode(G28Command::new(x, y, z)).await?;
self.state.position = PrinterPosition {
x: 0.0,
y: 0.0,
z: 0.0,
};
Ok(res)
}
/// Move the printer by a specific distance
///
/// If the printer is set to absolute movement mode, this function will switch it to relative
/// movement mode, perform the move, and then reset to absolute movement mode.
/// As this will introduce considerable overhead, consider calling
/// `self.use_relative_movements()` before doing multiple relative movements.
///
/// # Arguments
/// * `x, y, z` - Position offset in printer units (mm)
/// * `velocity` - Velocity that the printer should move at (mm/min)
pub async fn move_relative(
&mut self,
x: f64,
y: f64,
z: 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,
};
let reply = if let MovementMode::AbsoluteMovements = self.state.movement_mode {
self.use_relative_movements().await?;
let res = self.send_gcode(command).await;
self.use_absolute_movements().await?;
res
} else {
self.send_gcode(command).await
}?;
self.state.position.x += x;
self.state.position.y += y;
self.state.position.z += z;
Ok(reply)
}
/// Move the printer to a specific position
///
/// If the printer is set to relative movement mode, this function will switch it to absolute
/// movement mode, perform the move, and then reset to relative movement mode.
/// As this will introduce considerable overhead, consider calling
/// `self.use_absolute_movements()` before doing multiple absolute movements.
///
/// * `x, y, z` - New position in printer units (mm)
/// * `velocity` - Velocity that the printer should move at (mm/min)
pub async fn move_absolute(
&mut self,
x: f64,
y: f64,
z: f64,
velocity: f64,
) -> Result<(), PrinterError> {
let command = G0Command {
x: Some(x),
y: Some(y),
z: Some(z),
e: None, // Machine has no e
velocity: Some(velocity),
};
let reply = if let MovementMode::RelativeMovements = self.state.movement_mode {
self.use_absolute_movements().await?;
let res = self.send_gcode(command).await;
self.use_relative_movements().await?;
res
} else {
self.send_gcode(command).await
}?;
self.state.position.x = x;
self.state.position.y = y;
self.state.position.z = z;
Ok(reply)
}
} }
struct LineCodec; struct LineCodec;