NativeDesign / python-tmcl

TMCL Serial interface to Trinamic Stepper Motors
MIT License
19 stars 9 forks source link

TrinamicException: Invalid Value but still moving #7

Open nicksauerwein opened 6 years ago

nicksauerwein commented 6 years ago

When calling some functions the motor reacts as accepted, but the code trows an error.

For example:

motor.rotate_right(1600)

but if I call it again several times I sometimes get:

---------------------------------------------------------------------------
TrinamicException                         Traceback (most recent call last)
<ipython-input-38-1ab72c70bd37> in <module>()
----> 1 motor.rotate_right(1700)

~/anaconda3/lib/python3.6/site-packages/TMCL-1.2-py3.6.egg/TMCL/motor.py in rotate_right(self, velocity)
     69 
     70         def rotate_right(self, velocity):
---> 71                 reply = self.send(Command.ROR, 0, self.motor_id, velocity)
     72                 return reply.status
     73 

~/anaconda3/lib/python3.6/site-packages/TMCL-1.2-py3.6.egg/TMCL/motor.py in send(self, cmd, type, motorbank, value)
     51 
     52         def send( self, cmd, type, motorbank, value ):
---> 53                 return self.bus.send(self.module_id, cmd, type, motorbank, value)
     54 
     55         def stop( self ):

~/anaconda3/lib/python3.6/site-packages/TMCL-1.2-py3.6.egg/TMCL/bus.py in send(self, address, command, type, motorbank, value)
     54                         rep = self.serial.read(REPLY_LENGTH)
     55                         reply = Reply(struct.unpack(REPLY_STRUCTURE, rep))
---> 56                         return self._handle_reply(reply)
     57 
     58         def get_module( self, address=1 ):

~/anaconda3/lib/python3.6/site-packages/TMCL-1.2-py3.6.egg/TMCL/bus.py in _handle_reply(self, reply)
     92         def _handle_reply (self, reply):
     93                 if reply.status < Reply.Status.SUCCESS:
---> 94                         raise TrinamicException(reply)
     95                 return reply
     96 

TrinamicException: Invalid Value

This seems to be a timing issue.

Thanks for your help.

obfu5c8 commented 6 years ago

TrinamicException instances are raised when the controller module responds to a command, but with a non-success status code. This implies that the python code is functioning properly, but that the module is unwilling to execute the command (however I can't hypothesise as to why at this time).

Response status codes are mapped in accordance with the TMCL docs (http://www.mctechnology.nl/pdf/TMCL_reference_2015.pdf#page=7) .

Possible workaround

I assume the purpose of multiple high-speed calls to the rotate_right command are to change the speed of the motor while it is rotating. The rotate_right method maps to TMCL command ROR which is described in the docs as follows:

Internal function: First, velocity mode is selected. Then, the velocity value is transferred to axis parameter #0 ("target velocity").

It might be that repeated high-speed attempts to put the module into 'velocity mode' is what is causing the issue (I'm totally guessing here though). You could try calling ROR only once when motion starts, and then on successive calls update the 'target velocity' axis parameter directly instead.

nicksauerwein commented 6 years ago

It seems that every second call I get this error. But the strange thing is that the motor reacts as expected. This error actually arises in all functions that I call. (STOP, ROL, ROR, ...)

nicksauerwein commented 6 years ago

I solved this issue. The problem arises when more then one motor is connected. When you send a message at one motor, all the motors are answering. The status byte of the messages of the wrong motors is always 4 ('wrong value'). I modified the bus class so is works fine now.

            checksum = self._binaryadd(address, command, type, motorbank, value)
            msg = struct.pack(MSG_STRUCTURE, address, command, type, motorbank, value, checksum)

            self.serial.write(msg)

            while True:
                rep = self.serial.read(REPLY_LENGTH)

                if len(rep) < 9:
                        raise ValueError('increase the waiting time!!!')

                reply = Reply(struct.unpack(REPLY_STRUCTURE, rep))

                if reply.status == 100 and reply.module_address != address:
                    raise ValueError('two messages interfered: only send one message at the time!')

                if reply.module_address == address:
                    break

            #print ('Status: ',reply.status, 'Motor: ',reply.module_address,'Command: ',reply.command,'Value: ',reply.value)

            time.sleep(0.01)

            return self._handle_reply(reply)