Untitled

 avatar
unknown
plain_text
5 months ago
6.8 kB
2
Indexable
import sys
import termios
import tty
from time import sleep
from gpiozero import OutputDevice, Button

class StepperMotor:
    def __init__(self, dir_pin, step_pin, limit_switch_pin, steps_per_revolution=200, max_position=None):
        self.dir_pin = OutputDevice(dir_pin)
        self.step_pin = OutputDevice(step_pin)
        self.limit_switch = Button(limit_switch_pin, pull_up=True)  # Pull-up aktiverad om knappen är normalt öppen
        self.steps_per_revolution = steps_per_revolution
        self.position = 0  # Håller koll på positionen i steg
        self.max_position = max_position  # Maximal tillåten position

    def step(self, steps, direction=1, min_delay=0.001, max_delay=0.01, ramp_steps=10):
        """
        Gör stegen med motorn och ändrar hastigheten mellan min och max delay.
        Uppdaterar positionen efter varje steg. Stoppar motorn om max position uppnås.
        :param steps: Antal steg att ta
        :param direction: 1 för framåt, 0 för bakåt
        :param min_delay: Minsta fördröjning mellan pulser (snabbaste hastighet)
        :param max_delay: Största fördröjning mellan pulser (långsammaste hastighet)
        :param ramp_steps: Antal steg som används för att accelerera och decelerera
        """
        # Ställ in riktning
        self.dir_pin.value = direction

        # Accelerations- och deaccelerationsramper
        def calculate_delay(step, total_steps, min_d, max_d, ramp_s):
            if step < ramp_s:  # Accelerera
                return max_d - (step / ramp_s) * (max_d - min_d)
            elif step >= total_steps - ramp_s:  # Decelerera
                return max_d - ((total_steps - step) / ramp_s) * (max_d - min_d)
            else:  # Konstant hastighet
                return min_d

        for current_step in range(steps):
            # Kontrollera om limit-switchen aktiverats eller om max position har nåtts
            if (direction == 1 and self.limit_switch.is_pressed) or (self.position <= 0 and direction == 0):
                print("Limit switch reached or position is 0, stopping motor.")
                break

            if self.max_position is not None:
                if (direction == 0 and self.position >= self.max_position):
                    print(f"Max position of {self.max_position} reached while moving backwards, stopping motor.")
                    break
                elif (direction == 1 and self.position <= 0):
                    print(f"Min position (0) reached while moving forward, stopping motor.")
                    break

            # Beräkna delay baserat på stegets position
            delay = calculate_delay(current_step, steps, min_delay, max_delay, ramp_steps)

            # Skicka pulser
            self.step_pin.on()
            sleep(delay)
            self.step_pin.off()
            sleep(delay)

            # Uppdatera positionen
            if direction == 1:
                self.position -= 1  # Minska position när den går framåt (direction=1)
            else:
                self.position += 1  # Öka position när den går bakåt (direction=0)

    def calibrate(self):
        """
        Kalibrerar motorn genom att snurra framåt (direction=1) tills limit switchen aktiveras.
        """
        print("Starting calibration...")
        while not self.limit_switch.is_pressed:
            self.step(1, direction=1, min_delay=0.005, max_delay=0.005)  # Långsamt framåt mot knappen

        print("Calibration complete. Position reset to 0.")
        self.position = 0  # Återställ positionen till 0

    def calibrate_max_position(self):
        """
        Kalibrerar motorn genom att flytta till position 0 och sedan bakåt tills användaren trycker på en tangent.
        Max positionen sparas efter att användaren stoppar motorn med en knapptryckning.
        """
        # Kalibrera först position 0
        self.calibrate()

        print("Now moving towards max position (press any key to stop)...")
        while not self._key_pressed():
            self.step(1, direction=0, min_delay=0.005, max_delay=0.005)  # Långsamt bakåt (direction=0)

        # När användaren trycker på en knapp, sätt positionen som max position
        self.max_position = self.position
        print(f"Calibration of max position complete. Max position set to {self.max_position} steps.")

    def move_to_max_position(self):
        """
        Roterar motorn bakåt (direction=0) tills max position uppnås.
        """
        if self.max_position is not None:
            print(f"Moving to max position: {self.max_position} steps.")
            while self.position < self.max_position:
                self.step(1, direction=0, min_delay=0.005, max_delay=0.005)  # Långsamt bakåt mot max position

            print(f"Reached max position: {self.max_position} steps.")
        else:
            print("Max position is not set.")

    def rotate(self, rotations, direction=1, min_delay=0.001, max_delay=0.01, ramp_steps=10):
        """
        Roterar motorn ett visst antal varv och justerar hastigheten under rotation.
        Uppdaterar också positionen. Stoppar motorn om max position uppnås.
        :param rotations: Antal varv att snurra
        :param direction: 1 för framåt, 0 för bakåt
        :param min_delay: Minsta fördröjning mellan pulser (snabbaste hastighet)
        :param max_delay: Största fördröjning mellan pulser (långsammaste hastighet)
        :param ramp_steps: Antal steg som används för att accelerera och decelerera
        """
        steps = int(rotations * self.steps_per_revolution)
        self.step(steps, direction, min_delay, max_delay, ramp_steps)

    def _key_pressed(self):
        """
        Kontrollera om någon tangent är tryckt för att stoppa kalibreringen.
        """
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            rlist, _, _ = select([sys.stdin], [], [], 0)
            if rlist:
                sys.stdin.read(1)
                return True
            return False
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

# Exempel på hur man använder klassen
if __name__ == "__main__":
    motor = StepperMotor(dir_pin=20, step_pin=21, limit_switch_pin=16)  # Maxposition inte inställd ännu

    try:
        motor.calibrate_max_position()  # Kalibrera både position 0 och max position
        print(f"Position after max calibration: {motor.position}")
        print(f"Max position set to: {motor.max_position}")
    finally:
        print("Motorkontroll avslutad.")
Editor is loading...