Skip to content

Resolve "moving Edcmund where it already is can leave is_moving True"

Closes #4191 (closed)

# Issue occurs with this CalcAxis Architecture (3 layers of calc at least on one branch and one moving physical axis in another branch)
    #
    #                CalcAxis(track_undu)
    #                   |            |
    #       CalcAxis(twotheta)    Axis(undu)
    #               |
    #         CalcAxis(theta)
    #               |
    #            Axis(robz)
    #

    # === Context: On GroupMove.move(axis_pos_dict, ...) with axis_pos_dict = {track_undu: pos}
    #
    # 1) fill_motion_dict:
    #    - CalcAxis always have a motion (even if already in place)
    #    - If Axis is already_in_place, motion is None and added to excluded_axes list
    #
    # 2) force possible CalcAxis linked these excluded Axis to re-compute their pseudo pos.
    #     for axis in excluded_axes:
    #         event.send(axis, "internal_position", axis.position))
    #
    # 3) discard motions if:
    #    - math.isclose(motion.delta, 0)
    #    - motion.axis is CalcAxis and set(motion.axis.controller.reals) - excluded_axes is empty
    #    - !!! discarded motions are not re-injected in excluded_axes !!! (FIXED BY MR !6058)
    #
    # 4) del controllers with no motions
    #
    # 5) cancel move if there are only motions of CalcAxis
    #
    # 6) for remaining motions do:
    #    - motion.axis._set_position = motion.user_target_pos
    #    - motion.axis._set_moving_state()  !!! On Axis and CalcAxis. on Axis should be enough  !!!
    #    - spawn move_task and link task's end to _end_of_move() callback
    #    - _end_of_move() calls axis._set_move_done() !!! on Axis only !!!.
    #    - Axis._set_move_done(), emit signal "internal_move_done" and "move_done"
    #    - "internal_move_done" triggers a callback _real_axis_move_done() on CalcControllers
    #    - _set_moving_state() is called on pseudos only if all its reals are not moving !!!

    # === Use case 1: mv(track_undu, 8) when all axes already in place => OK
    #
    # 1) motions_dict = {ctrl1: [track_undu], ctrl2: [twotheta], ctrl3: [theta]}
    #    excluded_axes = {undu, robz}
    #
    # 2) send internal_position: robz => theta => theta => track_undu
    #
    # 3) set(motion.axis.controller.reals) - excluded_axes:
    #  track_undu => {twotheta, undu} - {undu, robz} = {twotheta} => not empty
    #  twotheta   => {theta}          - {undu, robz} = {theta}    => not empty
    #  theta      => {robz}           - {undu, robz} = {}    => empty => theta motion discarded
    #
    # 4) motions_dict = {ctrl1: [track_undu], ctrl2: [twotheta]}
    #
    # 5) cancel move because only CalcAxis
    #

    # === Use case 2: mv(track_undu, 8) when all axes already in place except undu => ISSUE 4191
    #
    # 1) motions_dict = {ctrl1: [track_undu], ctrl2: [twotheta], ctrl3: [theta], ctrl4: [undu]}
    #    excluded_axes = {robz}
    #
    # 2) send internal_position: robz => theta => theta => track_undu
    #
    # 3) set(motion.axis.controller.reals) - excluded_axes:
    #  track_undu => {twotheta, undu} - {robz} = {twotheta, undu} => not empty
    #  twotheta   => {theta}          - {robz} = {theta}          => not empty
    #  theta      => {robz}           - {robz} = {}    => empty => theta motion discarded
    #
    # 4) motions_dict = {ctrl1: [track_undu], ctrl2: [twotheta], ctrl4: [undu]}
    #
    # 5) move not canceled
    #
    # 6) _set_moving_state() on => track_undu, twotheta, undu
    #    _end_of_move() calls axis._set_move_done() on => undu     (track_undu, twotheta are skipped)
    #    undu emits "internal_move_done" and triggers _real_axis_move_done on track_undu controller
    #    but twotheta is still moving and will remain like that forever!!! (because robz and theta have been discarded)
    #    so track_undu will also stay moving forever!!!
    #
    # CCL: twotheta motion should have been discarded too
    #      excluded_axes must be updated with discarded CalcAxis motions
Edited by Perceval Guillou

Merge request reports