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

Threading #38 #42 #59

Merged
merged 7 commits into from
Oct 17, 2019
Merged

Threading #38 #42 #59

merged 7 commits into from
Oct 17, 2019

Conversation

fergusL
Copy link
Contributor

@fergusL fergusL commented Oct 16, 2019

This PR implements non-blocking versions of the goto_az(), .calibrate_dome_encoder_counts() and .find_home() methods (#38).

I've also fixed the simulated mode so that the triggering of gpio pins is handled by timed threads, as opposed to just letting various wait_for_active() calls to time out as was the case previously (#42).

This PR also relates to #52 and #32.

Copy link
Member

@AnthonyHorton AnthonyHorton left a comment

Choose a reason for hiding this comment

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

Looks good. If the abort is working in simulation I think we're reading to start testing by moving the real thing.

# degrees_per_tick for the tolerance
self.az_position_tolerance = max(
self.az_position_tolerance, self.degrees_per_tick)
self._az_position_tolerance = Angle(az_position_tolerance * u.deg)
Copy link
Member

Choose a reason for hiding this comment

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

I think you still should be checking whether the azimuth tolerance is less than one encoder tick, because it really shouldn't be. Probably serious enough to raise a ValueError.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As raise in the error instead of just using the degrees_per_tick and sweeping it under the rug? Or should we still change the tolerance to be the same as degrees_per_tick but log some kind of warning message?

domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
self._move_event = threading.Event()
# creating a threading simulated_rotation event, to indicate when a
# simulated rotation thread is running for testing mode calibration
self._simulated_rotation_event = threading.Event()
Copy link
Member

Choose a reason for hiding this comment

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

Do you really need to use a special Event for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, when I start the calibration thread I'm already setting the move_event flag. If I want to be able to simulate rotations for testing mode, I need a way of knowing when simulated rotations are done.

@@ -279,6 +289,11 @@ def dome_in_motion(self):
logger.debug(f'Dome in motion: {dome_motion}')
return dome_motion

@property
def movement_thread_active(self):
Copy link
Member

Choose a reason for hiding this comment

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

I'd be tempted to call this is_moving as it's more intuitive, & more in keeping with the general principle of naming things after meaning and not implementation details. The only things giving me second thoughts about that are that the dome can take up to a few seconds to come to a halt after being told to stop, and that the dome could be moving because someone is in the dome pressing the handset buttons. Maybe move_active instead?

That thought about the handset raises another issue. If someone does move the dome manually then the Pi is likely to lose track of where the dome actually is. It will see the encoder pulsing, but it has not way of telling which way the dome is moving. It would just assume the dome is moving in the direction that it last told it to, which might be wrong. What should happen instead is if the encoder starts registering pulses more than a few seconds after the Pi has told it to stop the Pi should just flag itself as 'unhomed', and refuse to move the dome again until eithe rehomed or synced.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another point is that I already had a .dome_in_motion property that returns True when the rotation relay is active. So kind of two things doing the same thing? Maybe I don't need the movement event at all?
Agree with the manual control problem, will make this an issue

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#60

Comment on lines 340 to 341
while self._move_event.is_set():
pass
Copy link
Member

Choose a reason for hiding this comment

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

It's a shame there isn't an equivalent of the .wait() method for waiting until an Event is not set...

You should put a timeout in here, just in case a move thread gets itself in such a mess it fails to respond to the abort and clear the ._move_event.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way abort is set up currently, it only triggers _thread_condition() to break out of the while True: loop. All of the actual actions are then carried out from within _thread_condition(), such as turning off the rotation relay, clearing the _move_event etc etc.
If we include time out in the actual abort() method, do we also want to run through the same process? Otherwise all the timeout would do is clear the abort_event flag?

domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
Copy link
Contributor

@wtgee wtgee left a comment

Choose a reason for hiding this comment

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

Looks good, the only concern would be what seem to be some extra threads within the calibrate method.

Comment on lines +293 to +295
def movement_thread_active(self):
"""Return true if a movement thread is running"""
return self._move_event.is_set()
Copy link
Contributor

Choose a reason for hiding this comment

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

I would also suggest a more intuitive name that doesn't include thread. Depends on what logic you want, but maybe is_moving.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Might be right, we also already have a .dome_in_motion property that is based off the rotation_relay state. I'm no longer sure if we even need this threading event.

domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
Comment on lines +521 to +522
first_rotation = threading.Thread(target=self._simulate_rotation)
first_rotation.start()
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need these? I don't see them anywhere else and this is calling a thread from within a thread.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So there is the calibration monitoring thread, that is checking for the right number of calibration rotations, abort events and timeouts. This needs to be making those checks regularly. For testing mode I also need to simulate the rotations, so they need to be run in a non-blocking thread.
So to begin I start an initial rotation before starting the while loop and include a clause within that loop that checks if the previous simulated rotation thread has completed. If the number of desired is rotations has been met the monitor thread will terminate, otherwise it will start another simulated rotation in its own thread.
Maybe there is a better way of doing this but the idea was that the thread monitoring calibration needs run separately to the thread simulating the rotation. I could have set the rotation threads up with a delay from within the main calibrate_dome_encoder_counts() method but you'd have to specify the timing of when each simulated rotation would start. I just thought that seemed messy/could lead to over lapping threads (a new rotation thread starts before the last is done etc).

domehunter/dome_control.py Show resolved Hide resolved
domehunter/dome_control.py Outdated Show resolved Hide resolved
@fergusL fergusL marked this pull request as ready for review October 17, 2019 09:07
Copy link
Contributor

@wtgee wtgee left a comment

Choose a reason for hiding this comment

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

Check the comment about the az_position_tolerance but I think this is good otherwise. The simulated calibration threads still seem a bit odd to me but since it's just for the simulation and that is working via the tests then I assume all good.

domehunter/dome_control.py Outdated Show resolved Hide resolved
domehunter/dome_control.py Show resolved Hide resolved
Comment on lines +511 to +513
delta_az = self.current_direction * raw_delta_az
logger.debug(f'Delta_az is {delta_az}, tolerance window is {self.az_position_tolerance}')
return delta_az <= self.az_position_tolerance
Copy link
Contributor

Choose a reason for hiding this comment

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

Won't multiplying it by the current_direction lead to a negative number with Direction.CCW? If so then the delta_az will always be less than the az_position_tolerance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nah multiplying by the Direction enum ensures that delta az is always positive. So if we are at an az of 170 and want to go to an az of 90, the raw_delta_az is -80 and we'd be going CCW to get there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the .wrap_at('180d') also handles situations where you want to go from az of 10 to az of 350, the raw_delta_az will be -20 (due to the wrapping) and the direction will be CCW so delta_az will be positive.

@fergusL fergusL merged commit a74120e into AstroHuntsman:develop Oct 17, 2019
@fergusL fergusL deleted the threading-#38-#42 branch October 17, 2019 11:21
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