Esempio n. 1
0
void AMControlMoveAction::onMoveStarted()
{
	disconnect(control_, SIGNAL(moveStarted()), this, SLOT(onMoveStarted()));
	disconnect(control_, SIGNAL(moveReTargetted()), this, SLOT(onMoveStarted()));
	// From now on, if we get a moveReTargetted() signal, this would be bad: someone is re-directing our move to a different setpoint, so this now counts as a failure.
	connect(control_, SIGNAL(moveReTargetted()), this, SLOT(onMoveReTargetted()));

	notifyStarted();
	// start the progressTick timer
	connect(&progressTick_, SIGNAL(timeout()), this, SLOT(onProgressTick()));
	progressTick_.start(250);
}
Esempio n. 2
0
void AMControlMoveAction::startImplementation() {
	const AMControlInfo& setpoint = *(controlMoveInfo()->controlInfo());

	// lookup the control we need to use to run this
	control_ = getControlForAction(setpoint);

	// Must have a control, and it must be able to move.
	if(!control_) {
		AMErrorMon::report(AMErrorReport(this,
										 AMErrorReport::Alert,
										 -1,
										 QString("There was an error moving the control '%1' into position, because the control was not found. Please report this problem to the Acquaman developers.").arg(setpoint.name())));
		notifyFailed();
		return;
	}
	// check we can move...
	if(!control_->canMove()) {
		AMErrorMon::report(AMErrorReport(this,
										 AMErrorReport::Alert,
										 -2,
										 QString("There was an error moving the control '%1' into position, because the control was not connected and ready to move. Please report this problem to the beamline staff.")
										 .arg(control_->name())));
		notifyFailed();
		return;
	}

	// check that the destination is in range...
	if(control_->valueOutOfRange(controlMoveInfo()->isRelativeMove() ? control_->value()+setpoint.value() : setpoint.value())) {
		AMErrorMon::report(AMErrorReport(this,
										 AMErrorReport::Alert,
										 -3,
										 QString("There was an error moving the control '%1' into position, because the destination %2 %3 was outside its range. Please report this problem to the beamline staff.")
										 .arg(control_->name())
										 .arg(setpoint.value())
										 .arg(setpoint.units())));
		notifyFailed();
		return;
	}

	// connect to its moveSucceeded and moveFailed signals
	connect(control_, SIGNAL(moveStarted()), this, SLOT(onMoveStarted()));
	connect(control_, SIGNAL(moveReTargetted()), this, SLOT(onMoveStarted()));	// For controls that support allowsMovesWhileMoving(), they might already be moving when we request our move(). A moveReTargetted() signal from them also counts as a moveStarted() for us.
	connect(control_, SIGNAL(moveFailed(int)), this, SLOT(onMoveFailed(int)));
	connect(control_, SIGNAL(moveSucceeded()), this, SLOT(onMoveSucceeded()));

	// remember the start position:
	startPosition_ = control_->toInfo();

	// start the move:
	int failureExplanation;
	if(controlMoveInfo()->isRelativeMove())
		failureExplanation = control_->moveRelative(setpoint.value());
	else
		failureExplanation = control_->move(setpoint.value());

	if(failureExplanation != AMControl::NoFailure)
		onMoveFailed(failureExplanation);
}
// Start a move to the value setpoint:
AMControl::FailureExplanation CLSMDriveMotorControl::move(double Setpoint) {

    if(isMoving()) {
        if(!allowsMovesWhileMoving()) {
            AMErrorMon::debug(this, AMPVCONTROL_COULD_NOT_MOVE_WHILE_MOVING, QString("AMPVControl: Could not move %1 (%2) to %3, because the control is already moving.").arg(name()).arg(writePV_->pvName()).arg(setpoint_));
            return AlreadyMovingFailure;
        }

        if(!moveInProgress()) {
            // the control is already moving, but it's not one of our moves. In this situation, there is no way that we can start a move and be assured that we'll be notified when OUR move finishes.
            AMErrorMon::debug(this, AMPVCONTROL_COULD_NOT_MOVE_WHILE_MOVING_EXTERNAL, QString("AMPVControl: Could not move %1 (%2) to %3, because the control is already moving.").arg(name()).arg(writePV_->pvName()).arg(setpoint_));
            return AlreadyMovingFailure;
        }

        // Otherwise: This control supports mid-move updates, and we're already moving. We just need to update the setpoint and send it.
        setpoint_ = writeUnitConverter()->convertToRaw(Setpoint);
        writePV_->setValue(setpoint_);
        // since the settling phase is considered part of a move, it's OK to be here while settling... But for Acquaman purposes, this will be considered a single re-targetted move, even though the hardware will see two.  If we're settling, disable the settling timer, because we only want to respond to the end of the second move.
        if(settlingInProgress_) {
            settlingInProgress_ = false;
            settlingTimer_.stop();
        }
        emit moveReTargetted(); // re-targetted moves will emit moveReTargetted(), although no moveSucceeded()/moveFailed() will be issued for the initial move.
    }

    else {
        settlingInProgress_ = false;
        stopInProgress_ = false;
        moveInProgress_ = false;
        // Flag that "our" move started:
        startInProgress_ = true;

        // This is our new target:
        setpoint_ = writeUnitConverter()->convertToRaw(Setpoint);

        // Special case: "null move" should complete immediately. Use only if moveStartTolerance() is non-zero, and the move distance is within moveStartTolerance().
        if(moveStartTolerance() != 0 && fabs(setpoint()-value()) < moveStartTolerance()) {
            startInProgress_ = false;
            moveInProgress_ = true;
            emit moveStarted();
            moveInProgress_ = false;
            emit moveSucceeded();
        }
        // Normal move:
        else {
            // Issue the move command:
            writePV_->setValue(setpoint_);
            // start the timer to check if our move failed to start:
            moveStartTimer_.start(int(moveStartTimeout_*1000.0));
        }
    }

    return NoFailure;
}
Esempio n. 4
0
// Start a move to the value setpoint:
AMControl::FailureExplanation AMPVControl::move(double setpoint) {

	if(isMoving()) {
		if(!allowsMovesWhileMoving()) {
			AMErrorMon::debug(this, AMPVCONTROL_COULD_NOT_MOVE_WHILE_MOVING, QString("AMPVControl: Could not move %1 (%2) to %3, because the control is already moving.").arg(name()).arg(writePV_->pvName()).arg(setpoint_));
			return AlreadyMovingFailure;
		}

		// assuming this control can accept mid-move updates. We just need to update our setpoint and send it.

		if(!canMove()) {	// this would be rare: a past move worked, but now we're no longer connected?
			AMErrorMon::debug(this, AMPVCONTROL_COULD_NOT_MOVE_BASED_ON_CANMOVE, QString("AMPVControl: Could not move %1 (%2) to %3.").arg(name()).arg(writePV_->pvName()).arg(setpoint_));
			return NotConnectedFailure;
		}
		setpoint_ = setpoint;
		writePV_->setValue(setpoint_);
		completionTimer_.start(int(completionTimeout_*1000.0)); // restart the completion timer... Since this might be another move, give it some more time.
		// re-targetted moves will emit moveReTargetted(), although no moveSucceeded()/moveFailed() will be issued for the first move.
		emit moveReTargetted();

		// check for done:
		if(inPosition()) {
			completionTimer_.stop();
			emit movingChanged(moveInProgress_ = false);
			emit moveSucceeded();
		}
	}

	// Regular case: start of a new move.
	else {
		// kill any old countdowns:
		completionTimer_.stop();

		if(!canMove()) {
			AMErrorMon::debug(this, AMPVCONTROL_COULD_NOT_MOVE_BASED_ON_CANMOVE, QString("AMPVControl: Could not move %1 (%2) to %3.").arg(name()).arg(writePV_->pvName()).arg(setpoint_));
			return NotConnectedFailure;
		}

		// new move target:
		setpoint_ = setpoint;
		// Issue the move, check on attemptMoveWhenWithinTolerance
		if(!attemptMoveWhenWithinTolerance_ && inPosition()){
			emit moveSucceeded();
		}
		else{
			writePV_->setValue(setpoint_);

			// We're now moving! Let's hope this control makes it... (No way to actually check.)
			emit movingChanged(moveInProgress_ = true);
			// emit the signal that we started:
			emit moveStarted();

			// Are we in-position? [With the default tolerance of AMCONTROL_TOLERANCE_DONT_CARE, we will always be in-position, and moves will complete right away, that's the intended behaviour, because we have no other way of knowing when they'll finish.]
			if(inPosition()) {
				emit movingChanged(moveInProgress_ = false);
				emit moveSucceeded();
			}
			else {
				// start the countdown to see if we get there in time or stall out: (completionTimeout_ is in seconds)
				completionTimer_.start(int(completionTimeout_*1000.0));
			}
		}
	}
	return NoFailure;
}