0

Part of my Python program opens a connection to an Arduino running GRBL. When this class is called, GRBL variables are set up and the serial connection is opened. I have everything else running the way I want, but it would be great to get gamepad input to control my motors instead of the key bindings I presently use.

I'm using XInput to get the gamepad events with the built-in thread handler. I can get this running and reading events in the background, but I'm having trouble triggering write commands outside the controller class. I always get "type object 'MotorTest' has no attribute 's'" if I try to run "MotorTest.test_move(MotorTest,direction='plus'), or "'MyOtherHandler' object has no attribute 'MotorTest'" if I try any "self" prefix. I don't want to re-initialize the MotorTest class obviously.

Modules used: XInput, switchcase, serial

Here are excerpts of the relevant code. I want to be able to control "def test_move" from the MyOtherHandler class:

class MotorTest:
    def __init__(self):
        """Initialize GRBL on the Arduino
        
        $1 = Hold current delay in ms. [0] for none, [255] always on.
        $32 = Set laser mode [1] for less pause between move commands.

        G20/21 = Set Inch/MM.
        G28 = Return home.
        G93 = Inverse time feed. Keeps constant speed even with other motors moving

        1 revolution takes 200 * 32 steps = 6400 steps/rev
        1 inch movement takes 18 revolutions = 18 * 6400 = 115200 steps/inch
        1 inch = 25.4 mm so 1 mm = 115200/25.4 = 4535.433 steps per mm

        """

        # Motor Variables
        inch = 'G20\n'
        millimeter = 'G21\n'
        step_per_mm = '1000'
        accel_rateX = '1000'
        accel_rateY = '1000'
        accel_rateZ = '1000'
        self.jog_amt = '0.05'
        self.jog_feed_rate = 200

        try:
            self.ports = list_ports.comports()
            self.port_ = None
            for port, desc, hwid in sorted(self.ports):
                #print("{}: {} [{}]".format(port, desc, hwid))
                if 'duino' in desc:
                    print("Arduino found on " + port)
                    self.port_ = port

            self.s = Serial(str(self.port_),115200)

            # More GRBL variable code here

    def test_move(self,direction):
        """
        Uses arrow key binding from main Tkinter class.

        $J = Jog mode
        $G91 = incremental mode. Using for JOG commands.
        """

        for case in switch(direction):
            if case('plus'):
                self.s.write(str.encode('$J=G91 Y{}  F{} \n'.format(self.jog_amt,self.jog_feed_rate)))
                break
            if case('minus'):
                self.s.write(str.encode('$J=G91 Y-{} F{} \n'.format(self.jog_amt,self.jog_feed_rate)))
                break
            if case('left'):
                self.s.write(str.encode('$J=G91 X-{} F{} \n'.format(self.jog_amt,self.jog_feed_rate)))
                break
            if case('right'):
                self.s.write(str.encode('$J=G91 X{}  F{} \n'.format(self.jog_amt,self.jog_feed_rate)))
                break
            if case('zPlus'):
                self.s.write(str.encode('$J=G91 Z{}  F{} \n'.format(self.jog_amt,self.jog_feed_rate)))
                break
            if case('zMinus'):
                self.s.write(str.encode('$J=G91 Z-{} F{} \n'.format(self.jog_amt,self.jog_feed_rate)))
                

class MyOtherHandler(EventHandler,MotorTest):
    def __init__(self, *controllers):
        super().__init__(*controllers)

    def process_button_event(self, event):
        if event.button_id == BUTTON_A:
            print("Pressed button A")
        elif event.button_id == BUTTON_B:
            print("Butt B")

    def process_stick_event(self, event):
        pass

    def process_trigger_event(self, event):
        if event.value > 0.00:
            print("Trigger LEFT = ", round(event.value,4), end='\r')
        else:
            print('\r\n')

    def process_connection_event(self, event):
        if event.type == EVENT_CONNECTED:
            print("**** CONTROLLER CONNECTED ****")
        else:
            print("**** CONTROLLER DISCONNECTED ****")
        
  • _I always get "type object 'MotorTest' has no attribute 's'" _ Please share the entire error output. – AMC Jun 25 '20 at 19:12
  • type object 'MotorTest' has no attribute 's' Stack trace: > File "C:\Users\Straylight\source\repos\PythonApplication3\PythonApplication3\python-scanner\src\stepper_control.py", line 119, in test_move > self.s.write(str.encode('$J=G91 Y{} F{} \n'.format(self.jog_amt,self.jog_feed_rate))) > File "C:\Users\Straylight\source\repos\PythonApplication3\PythonApplication3\python-scanner\src\stepper_control.py", line 169, in process_button_event > MotorTest.test_move(MotorTest,direction='plus') – Shalebridge Jun 25 '20 at 19:15
  • You can call `self.move_test(...)` directly inside `MyOtherHandler` because `MotorTest` is one of the base classes of `MyOtherHandler`. But you need to call `MotorTest.__init__()` function inside `MyOtherHandler.__init__()` function as well. – acw1668 Jun 26 '20 at 01:42
  • I was being dumb and didn't even realize there was no reason to have them as separate classes. I combined them and it does exactly what I want. Goes to show you what happens when you start just adding things to an already functional program. Thanks! – Shalebridge Jun 26 '20 at 20:14

0 Answers0