Hello people
I recently made a laser engraver that connects to a python program using pyserial to control the machine itself. The python program takes an image, takes the average rgb values of a pixel and maps it from 0-255 to 0-99 to keep the string later sends to the arduino fairly short. The arduino goes through this string and changes the pwm output depending on the values in the received string, and if it receives the letter "n" it starts a new line and reverses direction.
The issue I'm having is that after the first line is printed there is no direction change or new line started, instead the machine keeps going straight up by exactly the same length as another row. I'm sensing that there is a very simple fix to this, but I can't seem to find it.
Grateful for any help, and don't make fun of my coding too much!
Python code:
import numpy as np
from PIL import Image
import sys
from math import ceil
import serial
from time import sleep
max_string_length = 250 # how many values in the string, not actual string length
image_path = 'path'
im = Image.open(image_path).convert('RGB')
im = im.transpose(Image.Transpose.ROTATE_270)
im.show()
na = np.array(im).tolist()
def wait():
while True:
# print('before')
received = ser.readline().decode().strip()
# print('after')
print(received)
if received == 'ok' or received == 'k':
print('breaking')
break
print('stuck')
def print_progress_bar(iteration, total, label, length=50):
percent = round(100 * iteration / total, 1)
filled_length = int(length * iteration / total)
bar = '█' * filled_length + '-' * (length - filled_length)
sys.stdout.write(f'\r|{bar}| {percent}% {label}')
sys.stdout.flush()
its = 1
new = 0
for ind, row in enumerate(na):
print_progress_bar(its, len(na), 'converting to grayscale')
for ind2, pixel in enumerate(row):
for color in pixel:
new += color
value = str(int(99 - ((new / 3 * 99) / 255)))
if len(value) < 2:
value = '0'+value
na[ind][ind2] = value
new = 0
its += 1
its = 1
for index, row in enumerate(na):
print_progress_bar(its, len(na), 'reversing rows')
if index % 2 != 0:
na[index].reverse()
its += 1
if len(na[0]) % max_string_length == 0:
string_amount = int(len(na[0]) / max_string_length)
string_length = max_string_length
else:
string_amount = int(len(na[0]) / max_string_length) + 1
string_length = max_string_length
new = []
for i in range(len(na)):
new.append([])
its = 1
for index, row in enumerate(na):
print_progress_bar(its, len(na), 'generating strings')
row_length = len(row)
# print(string_length)
if row_length % string_length == 0:
for i in range(row_length // string_length):
new[index].append(row[i*string_length:(i+1)*string_length])
else:
for i in range(ceil(row_length / string_length)):
new[index].append(row[i*string_length:(i+1)*string_length])
if row_length > string_length:
new[index].append(row[(i+1)*string_length:])
its += 1
its = 1
for index, row in enumerate(new):
print_progress_bar(its, len(new), 'joining strings')
for index2, values in enumerate(row):
new[index][index2] = ''.join(values)
its += 1
its = 1
for index, row in enumerate(new):
print_progress_bar(its, len(new), 'cleaning up')
if '' in row:
# print(row)
# print(index)
del new[index][-1]
its += 1
sys.stdout.write('\r ')
if input('print? ') == 'y':
ser = serial.Serial(port='COM3', baudrate=57600)
sleep(2)
ser.write('e'.encode())
print('e')
wait()
sleep(2)
for row in new:
for string in row:
ser.write(string.encode())
print(string)
wait()
ser.write('n'.encode())
print('n')
wait()
ser.write('o'.encode())
print('o')
wait()
arduino sketch:
String received;
int x_step = 10;
int y_step = 9;
int x_dir1 = 7;
int x_dir2 = 6;
int y_dir = 8;
int laser = 11;
int en = 5;
int m0 = 2;
int m1 = 3;
int m2 = 4;
int i;
int direction = 1;
unsigned int c;
int steps_per_pixel = 12;
void setup() {
// put your setup code here, to run once:
pinMode(x_step, OUTPUT);
pinMode(y_step, OUTPUT);
pinMode(x_dir1, OUTPUT);
pinMode(x_dir2, OUTPUT);
pinMode(y_dir, OUTPUT);
pinMode(en, OUTPUT);
pinMode(laser, OUTPUT);
set_res(16);
Serial.setTimeout(20);
Serial.begin(57600);
// Serial.println("ready");
}
void loop() {
// put your main code here, to run repeatedly:
if (Serial.available() > 0) {
received = Serial.readStringUntil('\n');
received.trim();
if (received == "e") {
digitalWrite(en, HIGH);
Serial.println("ok");
}
if (received == "o") {
digitalWrite(en, LOW);
Serial.println("ok");
}
if (received == "n") {
direction *= -1;
move("x", "+", steps_per_pixel);
delay(300);
Serial.println("ok");
}
if (received != "n") {
for (c=0; c<received.length(); c+=2) {
// Serial.println(received.substring(c, c+2));
set_laser_strength(received.substring(c, c+2).toInt());
if (direction > 0) {
move("y", "+", steps_per_pixel);
}
if (direction < 0) {
move("y", "-", steps_per_pixel);
}
}
set_laser_strength(0);
Serial.println("ok");
}
}
}
void move(String xy, String dir, int steps) {
if (xy == "x") {
if (dir == "+") {
digitalWrite(x_dir1, LOW);
digitalWrite(x_dir2, HIGH);
}
if (dir == "-") {
digitalWrite(x_dir1, HIGH);
digitalWrite(x_dir2, LOW);
}
for (i=0; i<steps; i++) {
digitalWrite(x_step, HIGH);
delayMicroseconds(250);
digitalWrite(x_step, LOW);
delayMicroseconds(250);
}
}
if (xy == "y") {
if (dir == "+") {
digitalWrite(y_dir, LOW);
}
if (dir == "-") {
digitalWrite(y_dir, HIGH);
}
for (i=0; i<steps; i++) {
digitalWrite(y_step, HIGH);
delayMicroseconds(250);
digitalWrite(y_step, LOW);
delayMicroseconds(250);
}
}
}
void set_res(int res) {
if (res == 1){
digitalWrite(m0, LOW);
digitalWrite(m1, LOW);
digitalWrite(m2, LOW);
}
if (res == 2){
digitalWrite(m0, HIGH);
digitalWrite(m1, LOW);
digitalWrite(m2, LOW);
}
if (res == 4){
digitalWrite(m0, LOW);
digitalWrite(m1, HIGH);
digitalWrite(m2, LOW);
}
if (res == 8){
digitalWrite(m0, HIGH);
digitalWrite(m1, HIGH);
digitalWrite(m2, LOW);
}
if (res == 16){
digitalWrite(m0, LOW);
digitalWrite(m1, LOW);
digitalWrite(m2, HIGH);
}
}
void set_laser_strength(int strength) {
strength = map(strength, 0, 99, 0, 255);
analogWrite(laser, strength);
}