blob: 4f48737c222d2d6a8812bc8c5e9abae336fe2915 [file] [log] [blame]
#include <stddef.h>
#include <inttypes.h>
#include "aos/logging/logging.h"
#include "aos/logging/queue_logging.h"
namespace aos {
namespace controls {
// TODO(aschuh): Tests.
template <class T>
constexpr ::std::chrono::milliseconds ControlLoop<T>::kStaleLogInterval;
template <class T>
constexpr ::std::chrono::milliseconds ControlLoop<T>::kPwmDisableTime;
template <class T>
void ControlLoop<T>::ZeroOutputs() {
typename ::aos::Sender<OutputType>::Message output =
output_sender_.MakeMessage();
Zero(output.get());
output.Send();
}
template <class T>
void ControlLoop<T>::IteratePosition(const PositionType &position) {
no_goal_.Print();
no_sensor_state_.Print();
motors_off_log_.Print();
LOG_STRUCT(DEBUG, "position", position);
// Fetch the latest control loop goal. If there is no new
// goal, we will just reuse the old one.
goal_fetcher_.Fetch();
const GoalType *goal = goal_fetcher_.get();
if (goal) {
LOG_STRUCT(DEBUG, "goal", *goal);
} else {
LOG_INTERVAL(no_goal_);
}
const bool new_robot_state = robot_state_fetcher_.Fetch();
if (!robot_state_fetcher_.get()) {
LOG_INTERVAL(no_sensor_state_);
return;
}
if (sensor_reader_pid_ != robot_state_fetcher_->reader_pid) {
LOG(INFO, "new sensor reader PID %" PRId32 ", old was %" PRId32 "\n",
robot_state_fetcher_->reader_pid, sensor_reader_pid_);
reset_ = true;
sensor_reader_pid_ = robot_state_fetcher_->reader_pid;
}
bool outputs_enabled = robot_state_fetcher_->outputs_enabled;
// Check to see if we got a driver station packet recently.
if (new_robot_state) {
if (robot_state_fetcher_->outputs_enabled) {
// If the driver's station reports being disabled, we're probably not
// actually going to send motor values regardless of what the FPGA
// reports.
last_pwm_sent_ = robot_state_fetcher_->sent_time;
}
}
const ::aos::monotonic_clock::time_point monotonic_now =
event_loop_->monotonic_now();
const bool motors_off = monotonic_now >= kPwmDisableTime + last_pwm_sent_;
joystick_state_fetcher_.Fetch();
if (motors_off) {
if (joystick_state_fetcher_.get() && joystick_state_fetcher_->enabled) {
LOG_INTERVAL(motors_off_log_);
}
outputs_enabled = false;
}
typename ::aos::Sender<StatusType>::Message status =
status_sender_.MakeMessage();
if (status.get() == nullptr) {
return;
}
if (outputs_enabled) {
typename ::aos::Sender<OutputType>::Message output =
output_sender_.MakeMessage();
RunIteration(goal, &position, output.get(), status.get());
output->SetTimeToNow();
LOG_STRUCT(DEBUG, "output", *output);
output.Send();
} else {
// The outputs are disabled, so pass nullptr in for the output.
RunIteration(goal, &position, nullptr, status.get());
ZeroOutputs();
}
status->SetTimeToNow();
LOG_STRUCT(DEBUG, "status", *status);
status.Send();
}
} // namespace controls
} // namespace aos