Search code examples
pythonstepper

Move a stepper motor to an exact position


My setup: An Arduino that reads numbers from serial(steps), then it moves the stepper motor that many steps. It uses a4988 driver, a 12 volt power supply, 1.5 amp Nema 17. All of that is fine, my issue is on the Python side.

In Python, I have tried to create a function in a variety of ways. I used tkinter to get the mouse position on the screen, it moves in the x axis rotating the stepper. The stepper has a flashlight just to shine it at anything I point at with my mouse.

Say there is a camera below the stepper, if I move my mouse over to an object it would move there, within a tolerance of 5 steps either way. +5, -5 The function I have tried to create should work like this.

while True:
#I change direction by writing 400, clockwise, or 401, anti clockwise to serial.
    step(10)#move only 10 steps
    step(10)#it should do nothing as it has already moved 10 steps.
    step(15)#it should move 5 steps as it has moved 10 already
    step(5)#change direction and move back 10 steps
I am somewhat decent at python(or so I think)
here is my most promising code so far:
#I have direction changes done by writing a 400 for clockwise or 401 for anti clockwise to serial.
import tkinter as tk
import serial
ser = serial.Serial("COM8", 9600)
root = tk.Tk()
wi = root.winfo_screenwidth() / 2
width = root.winfo_screenwidth()
hi = root.winfo_screenheight() / 2
height = root.winfo_screenheight()
sere = '\r\n'
sender = sere.encode('utf_8')
pps = height / 200 
# p.p.s pixels per step divide that by the same thing to get correct.
#how many pixels are for 1 step
print(pps)
#number of pixels difference divided by pps to get steps, then round for ease of use
past = 0
print(height, width, wi) # height divided by pps should always = max steps in my case 200
def send(steps):
        global past
        global current
        sere = '\r\n'
        current = steps
        neg = past - 5
        pos = past + 5
        if current != past:
                if current > pos or current < neg:
                        if steps > 1:
                                sender = sere.encode('utf_8')
                                e = str(steps).encode('utf_8')
                                ser.write(e + sender)
        past = steps
while True:
        pos = root.winfo_pointerx() - wi
        steps = round(pos / pps)
        print(pos, steps) # shows cursor position
#direction code is not in here as I have no need for it atm.For one simple reason, IT DOESN'T WORK!

Please explain answers if possible, I am a long time lurker, and only made a account just now for this.Thank you all for any assistance. Edit: The question is how to make a function that moves a stepper motor to a certain number of steps.If you command it to do 10 steps twice, it only moves 10 steps. step(10) stepper moves 10 steps, do it again the motor does nothing as it is already at 10 steps. If I do step(15) it would only move another 5 as it is at 10 steps. Edit2 Clarification: By function I mean

def step(steps):
    #logic that makes it work


Solution

  • For anyone else who has this problem and people seem to not help a ton, heres my new code to drive it,

    past = 0
    sender = sere.encode('utf_8')
    dir1 = str(400).encode('utf_8')
    dir2 = str(401).encode('utf_8')
    def send(steps):
            global past
            global current
            global sender
            global dir1
            global dir2
            global stepstaken
            sere = '\r\n'
            current = steps
            neg = past - 5 # tolerance both are unused atm
            pos = past + 5 # tolerance
            needed = current - past
            print(needed, steps)
            if current != past:
                    if needed > 0:
                            serialsteps = str(needed).encode('utf_8')
                            ser.write(dir1 + sender)
                            ser.write(serialsteps + sender)
                    if needed < 0:
                            needed = needed * -1
                            serialstepss = str(needed).encode('utf_8')
                            ser.write(dir2 + sender)
                            ser.write(serialstepss + sender)
            past = steps
    

    Here is my full code for mouse to stepper motor,

    import tkinter as tk
    root = tk.Tk()
    import serial
    import struct
    import time
    stepstaken = 0
    ardunioport = "COM" + str(input("Ardunio Port Number:")) # port number only
    ser = serial.Serial(ardunioport, 9600)
    wi = root.winfo_screenwidth() / 2
    width = root.winfo_screenwidth()
    hi = root.winfo_screenheight() / 2
    height = root.winfo_screenheight()
    sere = '\r\n' #still don't understand why but it does not work without this.
    sender = sere.encode('utf_8')
    pps = width / 200 #how many pixels are in 1 step
    past = 0
    sender = sere.encode('utf_8')
    dir1 = str(400).encode('utf_8')
    dir2 = str(401).encode('utf_8')
    def send(steps):
            global past
            global current
            global sender
            global dir1
            global dir2
            global stepstaken
            #need overcome overstepping
            sere = '\r\n'
            current = steps
            neg = past - 5 # tolerance 
            pos = past + 5 # tolerance
            needed = current - past
            print(needed, steps)
            if current != past:
                    if needed > 0:
                            serialsteps = str(needed).encode('utf_8')
                            ser.write(dir1 + sender)
                            ser.write(serialsteps + sender)
                    if needed < 0:
                            needed = needed * -1
                            serialstepss = str(needed).encode('utf_8')
                            ser.write(dir2 + sender)
                            ser.write(serialstepss + sender)
            past = steps
    
    while True:
            pos = root.winfo_pointerx() - wi
            steps = round(pos / pps)
            #print("Mouse Position " + str(pos) + " Steps Needed" + str(steps)) # shows cursor position
            send(steps)        
    

    For me it goes to a Arduino, the Arduino is not programmed to accept negative numbers. Instead it removes the - sign, multiply negative by negative = positive. It sends the opposite direction code/number then the steps needed to get there. Good luck everyone. This code works for me, no promise it will work for you.If it does not I am sorry.