Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[report] Timing of StepperFast.ino #2

Open
yoursunny opened this issue Oct 1, 2018 · 1 comment
Open

[report] Timing of StepperFast.ino #2

yoursunny opened this issue Oct 1, 2018 · 1 comment

Comments

@yoursunny
Copy link
Contributor

I measured timing of StepperFast.ino.

This test was performed on a Sintro Uno R3 unit, not connected to any motor etc.
The command sequence is: "E", "Z", "Tn", and I measure how soon does - appear after sending the T command.

Test results:

degree duration (seconds)
0 0.10
1~255 3.31
256~359 3.27

I was expecting the duration to increase from 0 to 180 and decrease from 180 to 359.
It's surprising that there are only two duration values and the gap suspiciously falls between 255 and 256, the overflow point of uint8_t type.

The program for this test is:

#!/usr/bin/python3

import serial
import time


class Turntable:
    """
    Control a MocoMakers.com turntable over serial port.
    """

    def __init__(self, port, ackTimeout=0.2):
        """
        Initialize a turntable controller.
        :param port: serial port name
        :type port: str
        :param ackTimeout: how long (seconds) to wait for an acknowledgement
        :type ackTimeout: float
        """
        self.ackTimeout = ackTimeout
        self.serial = serial.Serial(
            port=port, baudrate=115200, timeout=ackTimeout, writeTimeout=ackTimeout)
        for i in range(10):
            self.serial.read()

    def close(self):
        self._cmd("E", immediate=True)
        self.serial.close()

    def _cmd(self, cmd, immediate=False, timeout=None):
        """
        Send a command and wait for completion.
        :param cmd: command string including parameters
        :type cmd: str
        :param immediate: whether the command would complete immediately (no "-" return)
        :type immediate: boolean
        :param timeout: timeout (seconds) for command completion
        :type timeout: float
        :return: whether success
        :rtype: bool
        """
        cmd = ("%s\n" % cmd).encode("ascii")
        self.serial.write(cmd)
        time.sleep(0.1)
        ack = self.serial.read()
        if ack != cmd[0:1]:
            return False
        if immediate:
            return True

        timeout = timeout if timeout is not None else 30.0
        elapsed = 0.0
        while elapsed < timeout:
            ack = self.serial.read()
            if ack == b'-':
                return True
            elapsed = elapsed + self.ackTimeout
        return False

    def zero(self):
        """
        Mark current position as zero.
        """
        return self._cmd("Z", immediate=True)

    def rotateBy(self, n, timeout=None):
        """
        Rotate n degrees from current position.
        :param n: relative position (degrees).
        :type n: float
        """
        return self._cmd("B%0.2f" % n, timeout=timeout)

    def rotateTo(self, n, timeout=None):
        """
        Rotate n degrees from zero position.
        :param n: absolute position (degrees).
        :type n: float
        """
        return self._cmd("T%0.2f" % n, timeout=timeout)

    def stop(self, timeout=None):
        """
        Stop rotation.
        """
        return self._cmd("S", timeout=timeout)

    def estop(self):
        """
        Emergency stop.
        """
        return self._cmd("E", immediate=True)


def measureTiming(port):
    """
    Measure rotation timing of a turntable and print as TSV.
    """
    turntable = Turntable(port)
    for n in range(0, 360):
        if not turntable.estop():
            raise RuntimeError("estop command failed")
        if not turntable.zero():
            raise RuntimeError("zero command failed")
        t0 = time.time()
        ok = turntable.rotateTo(n)
        t1 = time.time()
        if not ok:
            raise RuntimeError("rotateTo command failed")
        print("%d\t%0.2f" % (n, t1-t0))


if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser(
        description='Turntable timing measurements.')
    parser.add_argument('--port', type=str, required=True, help='serial port')
    args = parser.parse_args()
    measureTiming(args.port)
@yoursunny
Copy link
Contributor Author

The last test result was incorrect due to bug #4. I retested on the real unit with the following code:

def measureTiming(port):
    """
    Measure rotation timing of a turntable and print as TSV.
    """
    for n in range(0, 1800, 30):
        turntable = Turntable(port)
        if not turntable.zero():
            raise RuntimeError("zero command failed")
        t0 = time.time()
        ok = turntable.rotateBy(n)
        t1 = time.time()
        if not ok:
            raise RuntimeError("rotateTo command failed")
        print("%d\t%0.2f" % (n, t1-t0))
        turntable.close()

The results are:

rotateBy duration(seconds)
0 0.10
30 6.23
60 7.42
90 8.48
120 9.50
150 10.51
180 11.51
210 12.51
240 13.52
270 14.47
300 15.48
330 16.48
360 17.48
390 18.48
420 19.48
450 20.48
480 21.48
510 22.48
540 23.45
570 24.45
600 25.45
630 26.46
660 27.45
690 28.46
720 29.46
750 30.46
780 31.46
810 32.46
840 33.47
870 34.47

My test indicates that the display is consistent with LCD display, but the actual motor/turntable is very inaccurate. In fact, rotateTo(oldPosition) does not actually go to the old position. This is probably a hardware issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant