Control a motor

The video demonstrates how a motor (Modbus RTU with RS485 in RJ45) can be controlled with Python and the package fluidlab.

The driver of the motor is coded in the module fluidlab.instruments.modbus.unidrive_sp.

The first script with a simple loop:

from time import sleep

from fluidlab.exp import Timer
from fluidlab.instruments.motor_controller.unidrive_sp import UnidriveSP

motor = UnidriveSP()

# set a timer which ticks every 5 s
timer = Timer(time_between_ticks=5)

print("Enter in a loop for 3 ticks.")
for i in range(3):
    print(f"  Enter in the block of the loop. i = {i}.")
    print("  Start rotation with a frequency of 2 Hz.")
    motor.start_rotation(2)

    print("  Sleep 2 s.")
    sleep(2)

    print("  Change target rotation rate to 1 Hz.")
    motor.set_target_rotation_rate(1)

    print("  Sleep 2 s.")
    sleep(2)

    print("  Stop the motor.")
    motor.stop_rotation()

    print("  Wait for the tick.")
    timer.wait_tick()

And the code for the mini GUI (sorry, quick and dirty…):

"""Example of a tiny generic graphical driver.
==============================================

.. autoclass:: GraphicalDriver
   :members:
   :private-members:

"""

import sys

from PyQt5.QtWidgets import (
    QWidget,
    QApplication,
    QPushButton,
    QInputDialog,
    QGridLayout,
    QLCDNumber,
    QVBoxLayout,
)

from serial import SerialException

from fluidlab.instruments.motor_controller.unidrive_sp import (
    OpenLoopUnidriveSP,
    example_linear_ramps,
)


class FalseMotor:
    def __init__(self):
        self.rr = 0.0

    def unlock(self):
        pass

    def lock(self):
        pass

    def set_target_rotation_rate(self, rr, check=False):
        print(f"set_target_rotation_rate {rr} Hz")
        self.rr = rr

    def get_target_rotation_rate(self):
        return self.rr

    def start_rotation(self, a):
        pass

    def stop_rotation(self):
        self.rr = 0.0


class GraphicalDriver(QWidget):
    def __init__(self, class_motor=OpenLoopUnidriveSP):
        super().__init__()

        # initialization of the motor driver
        try:
            self.motor = class_motor()
        except (OSError, SerialException):
            print("OSError or SerialException so let's use a FalseMotor")
            self.motor = FalseMotor()

        # initialization of the window
        print("initialization of the window")
        self.initUI()

    def create_btn(self, name, function, x, y):
        button = QPushButton(name, self)
        self.grid.addWidget(button, x, y)
        button.clicked.connect(function)
        return button

    def initUI(self):
        self.grid = QGridLayout()
        self.grid.setSpacing(20)

        # create few basic buttons
        self.create_btn("Unlock", self.motor.unlock, 0, 0)
        self.create_btn("Lock", self.motor.lock, 0, 1)
        self.create_btn("Start", self.motor.start_rotation, 1, 0)
        self.create_btn("Stop", self.motor.stop_rotation, 1, 1)
        self.create_btn("Triangle", self.triangle_dialog, 2, 1)

        # create a layout for the speed with one button and one "lcd"
        speed_layout = QVBoxLayout()
        speed_layout.setSpacing(5)

        set_speed_btn = QPushButton("Set speed", self)
        set_speed_btn.clicked.connect(self.show_set_speed_dialog)
        self.set_speed_btn = set_speed_btn

        self.lcd = QLCDNumber(self)
        self.lcd.display(self.motor.get_target_rotation_rate())

        speed_layout.addWidget(set_speed_btn)
        speed_layout.addWidget(self.lcd)

        self.grid.addLayout(speed_layout, 2, 0)

        # global setting
        self.setLayout(self.grid)
        self.move(400, 300)
        self.setWindowTitle("Leroy Somer driver")
        self.show()

    def show_set_speed_dialog(self):
        speed, ok = QInputDialog.getText(
            self, "Input Dialog", "Enter the motor speed in Hz:"
        )
        if ok:
            self.motor.set_target_rotation_rate(float(speed))
            self.lcd.display(self.motor.get_target_rotation_rate())

    def triangle_dialog(self):
        max_speed, ok_a = QInputDialog.getText(
            self, "Input Dialog 1", "Enter the maximum motor speed in Hz:"
        )
        duration, ok_b = QInputDialog.getText(
            self, "Input Dialog 2", "Enter the duration in s:"
        )
        steps, ok_c = QInputDialog.getText(
            self, "Input Dialog 3", "Enter the number of steps:"
        )
        if ok_a and ok_b and ok_c:
            example_linear_ramps(self.motor, max_speed, duration, steps)


def main():
    app = QApplication(sys.argv)
    GraphicalDriver()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()