Skip to content

StepperHAL

Encoder

Warning

Encoder not yet verified due to missing hardware

Class to get position information from encoder

Attributes:

Name Type Description
pin_A

Encoder channel A connected to GPIO pin for Tx

pin_B

Encoder channel B connectet to GPIO pin for Rx

angle_calc(self)

Stepper angle calculation

Source code in hardware/stepper_hal.py
def angle_calc(self):
    """
        Stepper angle calculation
    """

    total_angle = self.enc_imp * self.motor_step_angle
    return total_angle

enc_impulses(self)

Callbacks when edges are detected

Decode Gray Code and update counter

Source code in hardware/stepper_hal.py
def enc_impulses(self):
    """
        Callbacks when edges are detected

        Decode Gray Code and update counter
    """
    current_A= int(self.input_A.is_pressed)
    current_B= int(self.input_B.is_pressed)
    state=f"{current_A}{current_B}"

    if self.old_state=='00':
        if state=='01':
            logging.debug(f"old_state {self.old_state}, new_state {state}, direction ->")
            self.direction='Right'
        elif self.state=='10':
            logging.debug(f"old_state {self.old_state}, new_state {state}, direction <-")
            self.direction='Left'

    elif self.old_state=='01':
        if state=='11':
            logging.debug(f"old_state {self.old_state}, new_state {state}, direction ->")
            self.direction='Right'
        elif state=='00':
            logging.debug(f"old_state {self.old_state}, new_state {state}, direction <-")
            self.direction='Left'
            self.enc_imp= self.enc_imp-1

    elif self.old_state=='10':
        if state=='00':
            logging.debug(f"old_state {self.old_state}, new_state {state}, direction ->")
            self.direction='Right'
            self.enc_imp= self.enc_imp+1
        elif state=='11':
            logging.debug(f"old_state {self.old_state}, new_state {state}, direction <-")
            self.direction='Left'

    elif self.old_state=='11':
        if state=='10':
            logging.debug(f"old_state {self.old_state}, new_state {state}, direction ->")
            self.direction='Right'
        elif state=='01':
            logging.debug(f"old_state {self.old_state}, new_state {state}, direction <-")
            self.direction='Left'

    self.old_state=state

set_imp_count_zero(self) async

Set pulse counter to zero

Source code in hardware/stepper_hal.py
async def set_imp_count_zero(self):
    """
        Set pulse counter to zero
    """

    old_imp_val=self.enc_imp
    self.enc_imp=0
    logging.info(f"Encoder.set_imp_zero: old {old_imp_val} new {self.enc_imp}")

EncoderStepperHAL (StepperHAL)

Stepper hardware abstraction layer for Rocking Stepper with encoder simulated by counting the steps

Attributes:

Name Type Description
direction Literal

stepper direction with default FORWARD

step_style int

step type with default DOUBLE

max_angle float

forward limit for Rocking Stepper

min_angle float

backward limit for Rocking Stepper

__init__(self, stepper_name, port_number, stop_at_exit=True) special

Parameters:

Name Type Description Default
stepper_name

stepper naming

required
port_number

Motor HAT ports 1,2

required
Source code in hardware/stepper_hal.py
def __init__(self, stepper_name, port_number, stop_at_exit=True):
    """
        Arguments:
            stepper_name: stepper naming
            port_number: Motor HAT ports 1,2
    """
    super().__init__(stepper_name, port_number, stop_at_exit=True)
    #self.encoder = Encoder()      #currently not used

calibrate(self) async

Determine middle position rocking stepper by stopper

Source code in hardware/stepper_hal.py
async def calibrate(self): #with stopper
    """
        Determine middle position rocking stepper by stopper
    """

    direction=STEPPER.FORWARD               #used current interval
    interval=0.05
    while(not self.forward_stopper.is_pressed):
        self.motor.onestep(direction=direction, style=self.step_style)
        await asyncio.sleep(interval)

    direction=STEPPER.BACKWARD
    counter=0
    while(not self.backward_stopper.is_pressed):
        self.motor.onestep(direction=direction, style=self.step_style)
        await asyncio.sleep(interval)
        counter += 1

    middle=round(counter/2)
    logging.info(f"Found center at {middle} steps")

    for _ in range(middle):
        self.motor.onestep(direction=STEPPER.FORWARD, style=self.step_style)
        await asyncio.sleep(interval)

    self.step_count=0             #start_position; counter reset

get_position(self) async

Returns:

Type Description

Stepper position in steps (0 == Center)

Source code in hardware/stepper_hal.py
async def get_position(self):      #currently without stopper
    """
        Return:
            Stepper position in steps (0 == Center)
    """

    return self.step_count  #WITHOUT encoder device

    #WITH encoder device - not verified due to missing working hardware
    # angle_pos=await self.encoder.angle_calc()
    # logging.debug(f"current angle: {angle_pos}")
    # pos_current=int(angle_pos/self.encoder.motor_step_angle)
    # return int(pos_current)     #Algo adaptation necessary so that angle can be passed

set_position(self, pos_goal) async

Move stepper to given position

Parameters:

Name Type Description Default
pos_goal int

target position to be moved to in steps (negative => backward, positive => forward)

required
Source code in hardware/stepper_hal.py
async def set_position(self, pos_goal: int) -> int: #without stopper
    """
        Move stepper to given position

        Arguments:
            pos_goal: target position to be moved to in steps (negative => backward, positive => forward)
    """

    pos_current = await self.get_position()
    logging.debug(f"Port {self.name} current position {pos_current}")

    steps = pos_current-pos_goal
    direction = STEPPER.FORWARD if steps<0 else STEPPER.BACKWARD

    logging.debug(f"steps to go {abs(steps)} in direction {direction}")

    for _ in range(abs(steps)):
        self.motor.onestep(direction=direction, style=self.step_style)
        await asyncio.sleep(self.interval)

        if direction == STEPPER.FORWARD:
            self.step_count = self.step_count+1
        else:
            self.step_count = self.step_count-1

        logging.debug(f"{self.name} step_count {self.step_count}")

    pos_current = await self.get_position()
    logging.debug(f"{self.name} check {pos_current} = {pos_goal} as start position?")
    return pos_current

StepperHAL (HAL)

Stepper hardware abstraction layer

Attributes:

Name Type Description
direction Literal

stepper direction with default FORWARD

step_style int

step type with default DOUBLE

interval float

initial waiting time

step_count int

motor rock control without encoder

motor_step_angle float

step resolution with step_style DOUBLE

max_angle float

max rocking angle

min_angle float

min rocking angle

motor

Stepper reference

forward_stopper

micro-limit-switch at GPIO Pin 24

backward_stopper

micro-limit-switch at GPIO Pin 25

__init__(self, stepper_name, port_number, stop_at_exit=True) special

Initialize motors and stopper

Parameters:

Name Type Description Default
stepper_name

Name of the stepper

required
port_number

Motor HAT ports 1, 2

required
Source code in hardware/stepper_hal.py
def __init__(self, stepper_name, port_number, stop_at_exit=True):
    """
        Initialize motors and stopper

        Arguments:
            stepper_name: Name of the stepper
            port_number: Motor HAT ports 1, 2
    """

    station=MotorKit(i2c=board.I2C())
    self.name=stepper_name
    self.port_number=port_number
    if port_number==1:
        self.motor=station.stepper1
    elif port_number==2:
        self.motor=station.stepper2
    if stop_at_exit:
        atexit.register(self.motor_stop)  #necessary as motor voltage is otherwise not released

    if port_number ==1:
        self.forward_stopper = Button(24, pull_up=True)             #GPIO 24 stopper
        self.backward_stopper = Button(25, pull_up=True)            #GPIO 25 stopper
        self.forward_stopper.when_pressed = self.change_direction   #Callback functions
        self.backward_stopper.when_pressed = self.change_direction

change_direction(self, angle=0)

Change direction when stopper is pressed

Parameters:

Name Type Description Default
angle float

current position in degree

0
Source code in hardware/stepper_hal.py
def change_direction(self, angle:float = 0):  #Rocking Stepper
    """
        Change direction when stopper is pressed

        Arguments:
            angle: current position in degree
    """

    if angle >= self.max_angle or self.forward_stopper.is_pressed:                 #trigger: max. def. angle
        self.direction=STEPPER.BACKWARD
        logging.info(f"direction changes to BACKWARD")
    elif angle <= self.min_angle or self.backward_stopper.is_pressed:               #trigger: min. def. angle
        self.direction=STEPPER.FORWARD
        logging.info(f"direction changes to FORWARD")

close(self)

Stop and release motor

Source code in hardware/stepper_hal.py
def close(self):
    """
       Stop and release motor
    """

    self.motor_stop()
    logging.info(f"Close stepper {self.name}")

motor_stop(self)

Single motor hold

Source code in hardware/stepper_hal.py
def motor_stop(self):
    """
        Single motor hold
    """

    self.motor.release()

rock(self) async

Rock stepper within given angle

Source code in hardware/stepper_hal.py
async def rock(self): #Rocking Stepper
    """
        Rock stepper within given angle
    """

    while True:
        self.motor.onestep(direction=self.direction, style=self.step_style)
        await asyncio.sleep(self.interval)
        logging.debug(f"rock_direction: {self.direction} with interval {self.interval}")

        step = (1 if self.direction == STEPPER.FORWARD else - 1)
        self.step_count = self.step_count + step

        logging.debug(f"{self.name} step_count {self.step_count}")

        rock_angle=self.step_count*self.motor_step_angle
        self.change_direction(rock_angle)     #option: add conditions here

rotate(self) async

Rotate stepper

Source code in hardware/stepper_hal.py
async def rotate(self):
    """
        Rotate stepper
    """

    while True:
        self.motor.onestep(direction=self.direction, style=self.step_style)
        await asyncio.sleep(self.interval)
        logging.debug(f"rotate: {self.name} direction: {self.direction} with interval {self.interval}")
Back to top