Skip to content

Only reset port settings for motor on first start() #125

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

Merged
merged 4 commits into from
Mar 18, 2022

Conversation

mutesplash
Copy link
Contributor

This should mostly solve Issue #122

Don't allow the motor to start() if some other type of movement is currently running.  Additionally, remember what the current speed of a start()ed motor is in order to not allow a serial command to be sent that effectively does nothing.
What is position but a specification of degrees
@@ -217,16 +244,31 @@ def start(self, speed=None):

:param speed: Speed ranging from -100 to 100
"""
if self.runmode == Motor.runmodes['Free']:
if self.current_freerun_speed == speed:
# Already running at this speed, do nothing

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a first order filter.
In a scenario with a constantly changing speed value, this code will fail to reduce the message rate. Therefore, the interface must sill be able to sustain the full message speed in order to rule out a random failure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but but the Pi is fast compared to the serial port and you're going to need/want all the bandwidth you can get out of the serial port in your scenario. This is seems kind of cheap.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, in this case there might be a minor benefit.

if speed is None:
speed = self.default_speed
else:
if not (speed >= -100 and speed <= 100):
raise MotorException("Invalid Speed")
cmd = "port {} ; combi 0 1 0 2 0 3 0 ; select 0 ; pid {} 0 0 s1 1 0 0.003 0.01 0 100; set {}\r".format(self.port, self.port, speed)
cmd = "port {} ; set {}\r".format(self.port, speed)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is the solution.

Copy link

@OliverFaust OliverFaust left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, the patch works.

If this is transferred to main branch, you might want to consider extending the functionality with the following update_speed function in the Motor class:

    def update_speed(self, speed=None):
        """Update motor speed

        :param speed: Speed ranging from -100 to 100
        """
        if self.runmode == Motor.runmodes['Free']:
            if self.current_freerun_speed == speed:
                # Already running at this speed, do nothing
                return
        elif self.runmode != Motor.runmodes['None']:
       	    # Motor is running some other mode, wait for it to stop or stop() it yourself
       	    return

        if speed is None:
            speed = self.default_speed
        else:
            if not (speed >= -100 and speed <= 100):
                raise MotorException("Invalid Speed")
        cmd = "port {} ; set {}\r".format(self.port, speed)
        if self.runmode == Motor.runmodes['None']:
            raise MotorException("Motor not started")
        self.runmode = Motor.runmodes['Free']
        self.current_freerun_speed = speed
        self._write(cmd)

And the corresponding extension for the Pair class:

    def update_speed(self, speedl=None, speedr=None):
        """Start motors

        :param speed: Speed ranging from -100 to 100
        """
        if speedl is None:
            speedl = self.default_speed
        if speedr is None:
            speedr = self.default_speed
        self._leftmotor.update_speed(speedl)
        self._rightmotor.update_speed(speedr)

@mutesplash
Copy link
Contributor Author

update_speed() would mostly duplicate start() and only save the elif branch from executing as you would just bail out if it weren't already running. Not sure if it's worth it even if you make start() call update_speed() to de-duplicate, as then it would make sense to require start() before update_speed() and then repeated start() calls would assume a re-initialization and then we'd be back to looping start() makes the motor serial line crash.

@OliverFaust
Copy link

From a technical point of view I agree with that assessment.
Once this functionality is transferred to the main branch, you might want to include an example which calls the start function in a hard loop. That might help users to create robot functionality.

@chrisruk
Copy link
Contributor

chrisruk commented Mar 17, 2022

Thanks a lot for this pull request @mutesplash, I've just been testing it with alternating between a speed of 0 and 1, and it seemed to work great :). I'll also add an extra test case soon for the motors that tests for this issue that your pull request fixes.

Do you mind altering this pull req. so that we use an enum for runmodes (I just checked enum was introduced in 3.4 and the minimum python version we're supporting is 3.7).

Edit: Also if possible could the ramp deduplication possibly go in a separate pull request, as that seems to be a separate improvement, and would probably make it a bit easier for me to merge this pull request first, then spend time separately reviewing that

@mutesplash
Copy link
Contributor Author

There we go

@chrisruk chrisruk merged commit a4edde7 into RaspberryPiFoundation:main Mar 18, 2022
@mutesplash mutesplash deleted the patch-9 branch March 18, 2022 13:37
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

Successfully merging this pull request may close these issues.

3 participants