Stepper motor control: Raspberry pi (GUI) and Arduino

I would like to control a stepper motor using the arduino accelstepper library and the GUI created in Python. I need to control it in a real time: steps, velocity and acceleration if it is possible. I have read a lot of materials on this subject but the more I read the more confused I am. I use the drv8825 driver to control my stepper motor Nema 17 (1.7A). Everything works very well on Arduino but I would like to be able to have a control with GUI via Raspberry pi. What method would be the best in this case - using serial port or firmata or maybe there is some other way. The stepper has to run in a loop forward and backward with very little load. Please see a Python code and arduino for stepper motor. I would also be very grateful for the help with Variables so that these two codes could work together somehow if possible.Thank you for any suggestions.

Python code:

import tkinter as tk
from tkinter import *

class Application(tk.Frame):

def init(self, root, *args, **kwargs):

tk.Frame.init(self, root, *args, **kwargs)

#self.variable_name = variable_name
self.sld1 = Scale(root, from_=0, to=35, orient=‘horizontal’, length=250,
resolution=‘5’, tickinterval=5,
command=lambda value, name=tk.Scale: self.report_change(name, value))
self.sld1.grid(column=0, row=1, rowspan=1, columnspan=1, sticky=‘NSEW’, pady=10, padx=10)
self.Label = tk.Label(root, text=‘Steps’)
self.Label.grid(row=2, column=0, sticky=W, pady=2)

self.sld2 = Scale(root, from_=100, to=1000, orient=‘horizontal’, length=250,
resolution=‘100’, tickinterval=250,
command=lambda value, name=tk.Scale: self.report_change(name, value))
self.sld2.grid(column=0, row=3, rowspan=1, columnspan=1, sticky=‘NSEW’, pady=10, padx=10)
self.Label2 = tk.Label(root, text=‘Velocity’)
self.Label2.grid(row=4, column=0, sticky=W, pady=2)

self.sld3 = Scale(root, from_=100, to=1000, orient=‘horizontal’, length=250,
resolution=‘100’, tickinterval=250,
command=lambda value, name=tk.Scale: self.report_change(name, value))
self.sld3.grid(column=0, row=5, rowspan=1, columnspan=1, sticky=‘NSEW’, pady=10, padx=10)
self.Labe3 = tk.Label(root, text=‘Acceleratiom’)
self.Labe3.grid(row=6, column=0, sticky=W, pady=2)

#self.Label.config(bg="#00ffff")

def action():
global output
global variable
output.insert(Motor_Run, Motor_STOP, variable.get())
variable.grid()

self.quitButton1 = tk.Button(root, text=‘Home’, command=self.quit)
self.quitButton1.grid(row=8, column=0, sticky=W, pady=12, padx=5)
self.quitButton2 = tk.Button(root, text=‘STOP’, command=action)
self.quitButton2.grid(row=8, column=1, sticky=W, padx=5)
self.quitButton3 = tk.Button(root, text=‘Run’, command=action)
self.quitButton3.grid(row=8, column=2, sticky=W, pady=1, padx=1)

self.quitButton3 = tk.Button(self, text=‘Exit’, command=self.quit)

self.quitButton3.grid(row=9, column=2, sticky=W)

def report_change(self, name, value):
print("%s changed to %s" % (name, value))

if name == ‘main’:
root = tk.Tk()
root.geometry(‘365x360’)
root.title(“Stepper Motor Control”)
app = Application(root)
label = tk.Label
root.mainloop()

Arduino, accelstepper:
#include <AccelStepper.h>

// Define pin connections
const int dirPin = 2;
const int stepPin = 3;

// Define motor interface type
#define motorInterfaceType 1

// Creates an instance
AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
// set the maximum speed, acceleration factor,
// initial speed and the target position
myStepper.setMaxSpeed (1000);
myStepper.setAcceleration(1000);
myStepper.setSpeed(100);
myStepper.moveTo(100);
}

void loop() {
// Change direction once the motor reaches target position
if (myStepper.distanceToGo() == 0)
myStepper.moveTo(-myStepper.currentPosition());

// Move the motor one step
myStepper.run();

}

What do you mean by "realtime"?

Apply changes without stopping the motor

Get GRBL, send GCODE over serial.

Can I use this GUI with GRBL? That would be grate

What GUI is “this”?

written in tkinter - Python

Maybe.

thanks for suggestion

from tkinter import *

:o YIKES

You could send the G-Code over serial (as mentioned previously) using the pip-installable Python package pySerialTransfer. Then you could use the compatible Arduino library SerialTransfer.h to automatically parse the serial data.

Power_Broker:
You could send the G-Code over serial (as mentioned previously) using the pip-installable Python package pySerialTransfer.

Looking (briefly) at the code in the Original Post I think GCode is just a distraction in this case.

IMHO the OP should decide what values need to be sent to the Arduino and use your package to send them. I assume there is no problem integrating your Python library into a TKInter program.

On the other hand, if GRBL is the correct solution on the Arduino then the OP should just use one of the many off-the-shelf PC GUI programs that can interface with GRBL.

…R

I did some research about GRBL, but the problem of is to work in a loop. My Python code is now working correctly ( just not sure about this part:def send(*args):
I will try to control stepper by the GUI, we’ll see what comes out. However, I now have another problem with the adaptation of the accelstepper library program on the arduino and serial port to make them work. Any help is appreciated, thanks.

import serial
import tkinter as tk
from tkinter import *


class Application(tk.Frame):
    def __init__(self, root, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)
        self.sld1 = Scale(root, from_=0, to=35, orient='horizontal', length=250,
                             resolution='5', tickinterval=5,
                             command=lambda value, name='S': self.report_change(name, value))
        self.sld1.grid(column=0, row=1, rowspan=1, columnspan=1, sticky='NSEW', pady=10, padx=10)
        self.Label = tk.Label(root, text='Steps')
        self.Label.grid(row=2, column=0, sticky=W, pady=2)
        self.sld2 = Scale(root, from_=100, to=1000, orient='horizontal', length=250,
                             resolution='100', tickinterval=250,
                             command=lambda value, name='V': self.report_change(name, value))
        self.sld2.grid(column=0, row=3, rowspan=1, columnspan=1, sticky='NSEW', pady=10, padx=10)
        self.Label2 = tk.Label(root, text='Velocity')
        self.Label2.grid(row=4, column=0, sticky=W, pady=2)
        self.sld3 = Scale(root, from_=100, to=1000, orient='horizontal', length=250,
                             resolution='100', tickinterval=250,
                             command=lambda value, name='A': self.report_change(name, value))
        self.sld3.grid(column=0, row=5, rowspan=1, columnspan=1, sticky='NSEW', pady=10, padx=10)
        self.Labe3 = tk.Label(root, text='Acceleratiom')
        self.Labe3.grid(row=6, column=0, sticky=W, pady=2)

        def action(cmnd):
            global output
            global variable
            print("command, steps, velo, accel = ",cmnd,s,v,a)

        self.Button1 = tk.Button(root, text='Quit', command=self.quit)
        self.Button1.grid(row=8, column=0, sticky=W, pady=6, padx=5)
        self.Button2 = tk.Button(root, text='STOP', command=lambda cmnd ="Motor_Stop": action(cmnd))
        self.Button2.grid(row=8, column=1, sticky=W, padx=5)
        self.Button3 = tk.Button(root, text='Run', command= lambda cmnd ="Motor_Start": action(cmnd))
        self.Button3.grid(row=8, column=2, sticky=W, pady=1, padx=1)

    def report_change(self, name, value):
        global s
        global a
        global v
        print("%s changed to %s" % (name, value))
        if name=='S':
          s = value
        if name=='V':
          v = value
        if name=='A':
          a = value

s =0
v =0
a =0

    def send(*args):
        try:
            data = S.get() + V.get() + A.get()
            global pos
            pos.set(pos.get() + int(degree.get()))
            print(data)
            ser = serial.Serial('COM4', 9600)
            time.sleep(2)
            ser.write(data.encode())
            time.sleep(5)

             btn.config(state=DISABLED)
             while True:
         myData = ''
                if (ser.inWaiting() > 0):
                myData = ser.readline()
                print(myData.decode())
                if (myData == ""):
                break

              msg = ser.readline()
             if msg == "Done!":
                 #btn.config(state=NORMAL)
                 break
             pass
        ser.close()
        except ValueError:
        pass



if __name__ == '__main__':
    root = tk.Tk()
    root.geometry('400x360')
    root.title("Stepper Motor Control")
    app = Application(root)
    label = tk.Label
    root.mainloop()

This is my Arduino code:

#include <AccelStepper.h>

String readString; //main captured String
String S; //data String
String V;
String A;


int ind1; // , locations
int ind2;
int ind3;

 
void setup() {
  Serial.begin(9600);
  Serial.println("serial limit"); // so I can keep track of what is loaded
}

void loop() {


  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == '*') {
      //do stuff
      
      Serial.println();
      Serial.print("captured String is : ");
      Serial.println(readString); //prints string to serial port out
      
      ind1 = readString.indexOf(',');  //finds location of first ,
      S = readString.substring(0, ind1);   //captures first data String
      ind2 = readString.indexOf(',', ind1+1 );   //finds location of second ,
      V = readString.substring(ind1+1, ind2+1);   //captures second data String
      ind3 = readString.indexOf(',', ind2+1 );
      A = readString.substring(ind2+1, ind3+1);
      ind4 = readString.indexOf(',', ind3+1 );
      altidude = readString.substring(ind3+1); //captures remain part of data after last ,

      Serial.print("steps = ");
      Serial.println(steps);
      Serial.print("velocity = ");
      Serial.println(velocity);
      Serial.print("acceleration = ");
      Serial.println(acceleration);
      Serial.print("altidude = ");
      Serial.println(altidude);
      Serial.println();
      Serial.println();
      
      readString=""; //clears variable for new input
      steps="";
      velocity="";
      acceleration="";
      altidude="";
    }  
    else {    
      readString += c; //makes the string readString
    }
  }
}


// Define pin connections
const int dirPin = 2;
const int stepPin = 3;

// Define motor interface type
#define motorInterfaceType 1

// Creates an instance
AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
  // set the maximum speed, acceleration factor,
  // initial speed and the target position
  myStepper.setMaxSpeed (1000);
  myStepper.setAcceleration(1000);
  myStepper.setSpeed(100);
  myStepper.moveTo(100);
}
                                  
void loop() {
  // Change direction once the motor reaches target position
  if (myStepper.distanceToGo() == 0) 
    myStepper.moveTo(-myStepper.currentPosition());

  // Move the motor one step
  myStepper.run();
  

    
}

Nop, that’s not the problem. e.g.: you want to move an axis while a key is pressed:

key down → send g1 x999999 f100
key up → send +

That’s crude but works.

zwieblum: Nop, that's not the problem. e.g.: you want to move an axis while a key is pressed:

Which Reply are you responding to?

The code in Reply #11 is not using GCode

...R

adam12135: However, I now have another problem with the adaptation of the accelstepper library program on the arduino and serial port to make them work.

You have not told what the problem is.

What does your program actually do, and what do you want it to do that is different?

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

These links may help Simple Python - Arduino demo Serial Input Basics - simple reliable non-blocking ways to receive data.

And if you are not interested in learning how to send and receive serial data have a look at the library mentioned in Reply #9. It can be used to send any type of data, not just GCode.

...R

OP, did you read my first reply?

I reply to the first line of post #11: "I did some research about GRBL, but the problem of is to work in a loop. "

Power_Broker: OP, did you read my first reply?

Your Reply #9 mentions GCode and I suspect that is just confusing matters. I mentioned in Reply #14 that your library can be used for any type of data.

...R