Skip to content

Make use of polling functionality in 16-ev3dev kernel#241

Merged
ddemidov merged 7 commits intodevelopfrom
motor-wait
Oct 30, 2016
Merged

Make use of polling functionality in 16-ev3dev kernel#241
ddemidov merged 7 commits intodevelopfrom
motor-wait

Conversation

@ddemidov
Copy link
Copy Markdown
Member

Introduces the following functions:

  • Motor.wait(condition),
  • Motor.wait_while(state, timeout=None)
  • Motor.wait_until(state, timeout=None)

Make the following possible:

m.wait_while('running')
m.wait_until('stalled')

Closes #230

@ddemidov
Copy link
Copy Markdown
Member Author

Tested with 16th kernel. It turns out m.wait_until('stalled') needs to be used with care, since immediately after starting motors have both 'running' and 'stalled' in state. A sleep(0.1) before calling wait_until('stalled') resolves the issue.

Introduces the following functions:

* Motor.wait(condition),
* Motor.wait_while(state, timeout=None)
* Motor.wait_until(state, timeout=None)

Make the following possible:

m.wait_while('running')
m.wait_until('stalled')

Closes #230
@WasabiFan
Copy link
Copy Markdown
Member

Looks good, however I think you should add a note in the documentation for these functions that there may be a momentary delay and that it should be taken into account.

@ddemidov
Copy link
Copy Markdown
Member Author

ddemidov commented Oct 29, 2016 via email

@WasabiFan
Copy link
Copy Markdown
Member

I could also put a sleep(0.1) in the beginning of the 'wait()' method. What do you think?

Normally, I would discount that possibility as a hack 😆. However, in this case we're working with "real-time" interfaces, in the sense that many functions are doing things which take time in the real world. So I think this is at least worth considering.

One alternative I could think of would be to add some sort of logic specifically for the "stalled" case; maybe it would require that the motor stays stalled for more than 0.1 seconds (or some other threshold) before returning from the wait. In general, stalling only momentarily isn't something you care about. That has the advantage that it only kicks in when needed and is almost always what you would want, but I could imagine cases where you wouldn't want that and it might me complicated to implement.

Or, similarly, it could enact that delay condition only if you are waiting on a state that the motor is already in when the function is called.

Neither of these are perfect, but they're all worth considering I think. We should keep in mind that simplicity and predictability are important, so maybe in the end an unconditional sleep with an enable_sleep flag defaulted to True would be the best choice.

poll() is not a generator function, as I thought initially
@dwalton76
Copy link
Copy Markdown
Collaborator

I have some similar functions in helper.py (I'll remove these in the future infavor of the patch above). I had to jump through some small hoops to work around how the initial states are set. I forget exactly what I did and am on my phone right now but maybe take a quick look at that to see what things I had to look out for. Mindcuber is a great test case for this because if anything is off at all it will be very obvious :)

@ddemidov
Copy link
Copy Markdown
Member Author

I've added hold_for=100 parameter for wait methods. How it works is when condition is met first time, it sleeps for hold_for milliseconds and rechecks the condition. Only if second check is successful, the method returns.

@ddemidov
Copy link
Copy Markdown
Member Author

@dwalton76, thanks, will check helper.py!

@ddemidov
Copy link
Copy Markdown
Member Author

@dwalton76, it looks like wait functions in your MotorMixin class provide a bit different functionality. You are using position attribute to check if the motor is actually running, which definitely has its uses. And the methods this PR introduces only look at state attribute.

@dwalton76
Copy link
Copy Markdown
Collaborator

Ah good point. We should think about what to name these so that the differences are clear. Maybe the helper.py ones could be wait_pos_* and the PR ones could be wait_state_* ?

@ddemidov
Copy link
Copy Markdown
Member Author

From your experience, does wait for position works better than running motor to relative/absolute position and waiting for its state to change?

@dwalton76
Copy link
Copy Markdown
Collaborator

Yeah the only way I could make it 100% reliable was to use the motor position

@ddemidov
Copy link
Copy Markdown
Member Author

This smells both like a possible bug in drivers and a functionality duplication. It may be confusing for the users if we provide both run_to_abs_pos()/wait_while('running') and wait_for_abs_pos(). Does the need for second means the first is broken?

@dwalton76
Copy link
Copy Markdown
Collaborator

One scenario I remember was the state of the motor would read running before the motor actually started moving so I started using pos to work around that. I want to say I had the same problem with stopping a motor in that the state would read stopped when the motor was in fact still moving (although not for long). There were some other problems but my memory is fuzzy.

Agreed though that we don't want multiple ways to do the same thing. I still have mindcuber assembled so I'll give it a try using the functions you are adding here and try to pinpoint the scenarios where using state alone wasn't reliable.

Copy link
Copy Markdown
Collaborator

@dwalton76 dwalton76 left a comment

Choose a reason for hiding this comment

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

Maybe have it return True if the condition is met and False if we hit the timeout

@ddemidov
Copy link
Copy Markdown
Member Author

Maybe have it return True if the condition is met and False if we hit the timeout

Good idea! Implemented in 30e4da4

@dlech
Copy link
Copy Markdown
Member

dlech commented Oct 29, 2016

I could also put a sleep(0.1) in the beginning of the 'wait()' method. What do you think?

Or you could fix the motor driver itself. It should not be reporting stalled unless it is really stalled.

@ddemidov
Copy link
Copy Markdown
Member Author

Or you could fix the motor driver itself. It should not be reporting stalled unless it is really stalled.

For future reference: https://github.com/ev3dev/lego-linux-drivers/blob/master/ev3/legoev3_motor.c#L637

@ddemidov
Copy link
Copy Markdown
Member Author

It looks like 'stalled' flag is set whenever more time has passed between samples (are those position clicks?) than a predefined constant, max_us_per_sample. With this in mind, it seems logical that motor is considered stalled in the beginning of the run, when it has not yet gained speed.

How would you fix this? Would simple increase of max_us_per_sample work?

@dlech
Copy link
Copy Markdown
Member

dlech commented Oct 29, 2016

How would you fix this? Would simple increase of max_us_per_sample work?

I think we could just increase the time before we set the stalled flag. In the code that you linked, we are setting speed = 0 and stalled = true at the same time. We could modify this to just set the speed to 0 and start a stall timer. If the speed does not change for 0.1 seconds, then set the stalled flag.

dlech pushed a commit to ev3dev/lego-linux-drivers that referenced this pull request Oct 30, 2016
May help with sporadic misreports. See discussion in
ev3dev/ev3dev-lang-python#241
@ddemidov
Copy link
Copy Markdown
Member Author

We can probably drop the hold_for parameter, since it was only introduced as a workaround for stalled misreports which should be fixed by ev3dev/lego-linux-drivers#57.

@ddemidov ddemidov merged commit 61b5439 into develop Oct 30, 2016
@ddemidov ddemidov deleted the motor-wait branch October 30, 2016 20:08
@dwalton76
Copy link
Copy Markdown
Collaborator

I'm working on a new rubiks cube robot and the ability to do

m.wait_until('running')
m.wait_while('running')

is golden...thank you @ddemidov for implementing this

@WasabiFan
Copy link
Copy Markdown
Member

Do you need to do those two in sequence, or is calling just the second reliable? I'm thinking we should document how we recommend that you use these methods with a sample like this.

@dwalton76
Copy link
Copy Markdown
Collaborator

I think you are correct that only the wait_while() is typically needed...I'll verify tonight.

@dwalton76
Copy link
Copy Markdown
Collaborator

I got distracted....just verified that the m.wait_until('running') is not needed.

@ddemidov ddemidov mentioned this pull request Sep 22, 2017
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.

4 participants