Program Listing for File unjam_command.cpp
↰ Return to documentation for file (src/tap/control/setpoint/commands/unjam_command.cpp
)
/*
* Copyright (c) 2020-2021 Advanced Robotics at the University of Washington <robomstr@uw.edu>
*
* This file is part of Taproot.
*
* Taproot is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Taproot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Taproot. If not, see <https://www.gnu.org/licenses/>.
*/
#include "unjam_command.hpp"
#include "tap/algorithms/math_user_utils.hpp"
#include "tap/control/setpoint/interfaces/setpoint_subsystem.hpp"
namespace tap
{
namespace control
{
namespace setpoint
{
class SetpointSubsystem; // forward declaration
UnjamCommand::UnjamCommand(
SetpointSubsystem* setpointSubsystem,
float unjamDisplacement,
float unjamThreshold,
uint32_t maxWaitTime,
uint_fast16_t targetCycleCount)
: unjamRotateTimeout(0),
maxWaitTime(maxWaitTime),
setpointSubsystem(setpointSubsystem),
unjamDisplacement(unjamDisplacement),
unjamThreshold(unjamThreshold),
targetCycleCount(targetCycleCount)
{
unjamDisplacement = abs(unjamDisplacement);
unjamThreshold = abs(unjamThreshold);
this->addSubsystemRequirement(setpointSubsystem);
unjamRotateTimeout.stop();
}
bool UnjamCommand::isReady() { return setpointSubsystem->isOnline(); }
void UnjamCommand::initialize()
{
unjamRotateTimeout.restart(maxWaitTime);
// store the current setpoint value to be able to restore subsystem state after command
// completion
setpointBeforeUnjam = setpointSubsystem->getSetpoint();
valueBeforeUnjam = setpointSubsystem->getCurrentValue();
forwardsCleared = false;
backwardsCleared = false;
backwardsCount = 0;
beginUnjamBackwards();
}
void UnjamCommand::execute()
{
float currValue = setpointSubsystem->getCurrentValue();
switch (currUnjamState)
{
case UNJAM_BACKWARD:
if (currValue <= valueBeforeUnjam - unjamThreshold)
{
backwardsCleared = true;
beginUnjamForwards();
}
else if (unjamRotateTimeout.isExpired())
{
beginUnjamForwards();
}
break;
case UNJAM_FORWARD:
if (currValue >= valueBeforeUnjam + unjamThreshold)
{
forwardsCleared = true;
beginUnjamBackwards();
}
else if (unjamRotateTimeout.isExpired())
{
beginUnjamBackwards();
}
break;
case JAM_CLEARED:
// Jam has been cleared. If it's taken longer than unjamRotateTimeout
// resume unjamming
if (unjamRotateTimeout.isExpired())
{
backwardsCleared = false;
forwardsCleared = false;
beginUnjamForwards();
}
}
// Forward and backward thresholds cleared, try to return to original setpoint.
if (currUnjamState != JAM_CLEARED && forwardsCleared && backwardsCleared)
{
currUnjamState = JAM_CLEARED;
setpointSubsystem->setSetpoint(setpointBeforeUnjam);
unjamRotateTimeout.restart(maxWaitTime);
}
}
void UnjamCommand::end(bool)
{
if (currUnjamState == JAM_CLEARED)
{
setpointSubsystem->clearJam();
}
else
{
setpointSubsystem->setSetpoint(setpointSubsystem->getCurrentValue());
}
}
bool UnjamCommand::isFinished() const
{
return !setpointSubsystem->isOnline() ||
(currUnjamState == JAM_CLEARED &&
tap::algorithms::compareFloatClose(
setpointSubsystem->getCurrentValue(),
setpointBeforeUnjam,
0.9f * setpointSubsystem->getJamSetpointTolerance())) ||
backwardsCount >= targetCycleCount + 1;
}
void UnjamCommand::beginUnjamForwards()
{
unjamRotateTimeout.restart(maxWaitTime);
setpointSubsystem->setSetpoint(valueBeforeUnjam + unjamDisplacement);
currUnjamState = UNJAM_FORWARD;
}
void UnjamCommand::beginUnjamBackwards()
{
unjamRotateTimeout.restart(maxWaitTime);
setpointSubsystem->setSetpoint(valueBeforeUnjam - unjamDisplacement);
currUnjamState = UNJAM_BACKWARD;
backwardsCount += 1;
}
} // namespace setpoint
} // namespace control
} // namespace tap