mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-23 01:21:42 +00:00
Move robot base classes from opmode to framework (#8344)
Having these in opmode will be confusing to users when opmodes are added.
This commit is contained in:
280
wpilibc/src/main/native/include/wpi/framework/RobotBase.hpp
Normal file
280
wpilibc/src/main/native/include/wpi/framework/RobotBase.hpp
Normal file
@@ -0,0 +1,280 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "wpi/hal/DriverStation.h"
|
||||
#include "wpi/hal/HALBase.h"
|
||||
#include "wpi/hal/Main.h"
|
||||
#include "wpi/nt/NetworkTable.hpp"
|
||||
#include "wpi/system/Errors.hpp"
|
||||
#include "wpi/system/RuntimeType.hpp"
|
||||
#include "wpi/util/RuntimeCheck.h"
|
||||
#include "wpi/util/condition_variable.hpp"
|
||||
#include "wpi/util/mutex.hpp"
|
||||
#include "wpi/util/string.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
int RunHALInitialization();
|
||||
|
||||
namespace impl {
|
||||
#ifndef __FRC_SYSTEMCORE__
|
||||
void ResetMotorSafety();
|
||||
#endif
|
||||
|
||||
template <class Robot>
|
||||
void RunRobot(wpi::util::mutex& m, Robot** robot) {
|
||||
try {
|
||||
static Robot theRobot;
|
||||
{
|
||||
std::scoped_lock lock{m};
|
||||
*robot = &theRobot;
|
||||
}
|
||||
theRobot.StartCompetition();
|
||||
} catch (const wpi::RuntimeError& e) {
|
||||
e.Report();
|
||||
WPILIB_ReportError(
|
||||
err::Error,
|
||||
"The robot program quit unexpectedly."
|
||||
" This is usually due to a code error.\n"
|
||||
" The above stacktrace can help determine where the error occurred.\n"
|
||||
" See https://wpilib.org/stacktrace for more information.\n");
|
||||
throw;
|
||||
} catch (const std::exception& e) {
|
||||
HAL_SendError(1, err::Error, 0, e.what(), "", "", 1);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace impl
|
||||
|
||||
template <class Robot>
|
||||
int StartRobot() {
|
||||
uint32_t foundMajor;
|
||||
uint32_t foundMinor;
|
||||
uint32_t expectedMajor;
|
||||
uint32_t expectedMinor;
|
||||
WPI_String runtimePath;
|
||||
if (!WPI_IsRuntimeValid(&foundMajor, &foundMinor, &expectedMajor,
|
||||
&expectedMinor, &runtimePath)) {
|
||||
// We could make this error better, however unlike Java, there is only a
|
||||
// single scenario that could be occuring. The entirety of VS is too out
|
||||
// of date. In most cases the linker should detect this, but not always.
|
||||
fmt::println(
|
||||
"Your copy of Visual Studio is out of date. Please update it.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int halInit = RunHALInitialization();
|
||||
if (halInit != 0) {
|
||||
return halInit;
|
||||
}
|
||||
|
||||
static wpi::util::mutex m;
|
||||
static wpi::util::condition_variable cv;
|
||||
static Robot* robot = nullptr;
|
||||
static bool exited = false;
|
||||
|
||||
if (HAL_HasMain()) {
|
||||
std::thread thr([] {
|
||||
try {
|
||||
impl::RunRobot<Robot>(m, &robot);
|
||||
} catch (...) {
|
||||
HAL_ExitMain();
|
||||
{
|
||||
std::scoped_lock lock{m};
|
||||
robot = nullptr;
|
||||
exited = true;
|
||||
}
|
||||
cv.notify_all();
|
||||
throw;
|
||||
}
|
||||
|
||||
HAL_ExitMain();
|
||||
{
|
||||
std::scoped_lock lock{m};
|
||||
robot = nullptr;
|
||||
exited = true;
|
||||
}
|
||||
cv.notify_all();
|
||||
});
|
||||
|
||||
HAL_RunMain();
|
||||
|
||||
// signal loop to exit
|
||||
if (robot) {
|
||||
robot->EndCompetition();
|
||||
}
|
||||
|
||||
// prefer to join, but detach to exit if it doesn't exit in a timely manner
|
||||
using namespace std::chrono_literals;
|
||||
std::unique_lock lock{m};
|
||||
if (cv.wait_for(lock, 1s, [] { return exited; })) {
|
||||
thr.join();
|
||||
} else {
|
||||
thr.detach();
|
||||
}
|
||||
} else {
|
||||
impl::RunRobot<Robot>(m, &robot);
|
||||
}
|
||||
|
||||
#ifndef __FRC_SYSTEMCORE__
|
||||
wpi::impl::ResetMotorSafety();
|
||||
#endif
|
||||
HAL_Shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement a Robot Program framework. The RobotBase class is intended to be
|
||||
* subclassed to create a robot program. The user must implement
|
||||
* StartCompetition() which will be called once and is not expected to exit. The
|
||||
* user must also implement EndCompetition(), which signals to the code in
|
||||
* StartCompetition() that it should exit.
|
||||
*
|
||||
* It is not recommended to subclass this class directly - instead subclass
|
||||
* IterativeRobotBase or TimedRobot.
|
||||
*/
|
||||
class RobotBase {
|
||||
public:
|
||||
/**
|
||||
* Determine if the Robot is currently enabled.
|
||||
*
|
||||
* @return True if the Robot is currently enabled by the Driver Station.
|
||||
*/
|
||||
bool IsEnabled() const;
|
||||
|
||||
/**
|
||||
* Determine if the Robot is currently disabled.
|
||||
*
|
||||
* @return True if the Robot is currently disabled by the Driver Station.
|
||||
*/
|
||||
bool IsDisabled() const;
|
||||
|
||||
/**
|
||||
* Determine if the robot is currently in Autonomous mode.
|
||||
*
|
||||
* @return True if the robot is currently operating Autonomously as determined
|
||||
* by the Driver Station.
|
||||
*/
|
||||
bool IsAutonomous() const;
|
||||
|
||||
/**
|
||||
* Determine if the robot is currently in Autonomous mode and enabled.
|
||||
*
|
||||
* @return True if the robot us currently operating Autonomously while enabled
|
||||
* as determined by the Driver Station.
|
||||
*/
|
||||
bool IsAutonomousEnabled() const;
|
||||
|
||||
/**
|
||||
* Determine if the robot is currently in Operator Control mode.
|
||||
*
|
||||
* @return True if the robot is currently operating in Tele-Op mode as
|
||||
* determined by the Driver Station.
|
||||
*/
|
||||
bool IsTeleop() const;
|
||||
|
||||
/**
|
||||
* Determine if the robot is current in Operator Control mode and enabled.
|
||||
*
|
||||
* @return True if the robot is currently operating in Tele-Op mode while
|
||||
* enabled as determined by the Driver Station.
|
||||
*/
|
||||
bool IsTeleopEnabled() const;
|
||||
|
||||
/**
|
||||
* Determine if the robot is currently in Test mode.
|
||||
*
|
||||
* @return True if the robot is currently running in Test mode as determined
|
||||
* by the Driver Station.
|
||||
*/
|
||||
bool IsTest() const;
|
||||
|
||||
/**
|
||||
* Determine if the robot is current in Test mode and enabled.
|
||||
*
|
||||
* @return True if the robot is currently operating in Test mode while
|
||||
* enabled as determined by the Driver Station.
|
||||
*/
|
||||
bool IsTestEnabled() const;
|
||||
|
||||
/**
|
||||
* Returns the main thread ID.
|
||||
*
|
||||
* @return The main thread ID.
|
||||
*/
|
||||
static std::thread::id GetThreadId();
|
||||
|
||||
/**
|
||||
* Start the main robot code. This function will be called once and should not
|
||||
* exit until signalled by EndCompetition()
|
||||
*/
|
||||
virtual void StartCompetition() = 0;
|
||||
|
||||
/** Ends the main loop in StartCompetition(). */
|
||||
virtual void EndCompetition() = 0;
|
||||
|
||||
/**
|
||||
* Get the current runtime type.
|
||||
*
|
||||
* @return Current runtime type.
|
||||
*/
|
||||
static RuntimeType GetRuntimeType();
|
||||
|
||||
/**
|
||||
* Get if the robot is real.
|
||||
*
|
||||
* @return If the robot is running in the real world.
|
||||
*/
|
||||
static constexpr bool IsReal() {
|
||||
#ifdef __FRC_SYSTEMCORE__
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the robot is a simulation.
|
||||
*
|
||||
* @return If the robot is running in simulation.
|
||||
*/
|
||||
static constexpr bool IsSimulation() {
|
||||
#ifdef __FRC_SYSTEMCORE__
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a generic robot program.
|
||||
*
|
||||
* User code can be placed in the constructor that runs before the
|
||||
* Autonomous or Operator Control period starts. The constructor will run to
|
||||
* completion before Autonomous is entered.
|
||||
*
|
||||
* This must be used to ensure that the communications code starts. In the
|
||||
* future it would be nice to put this code into it's own task that loads on
|
||||
* boot so ensure that it runs.
|
||||
*/
|
||||
RobotBase();
|
||||
|
||||
virtual ~RobotBase() = default;
|
||||
|
||||
protected:
|
||||
RobotBase(RobotBase&&) = default;
|
||||
RobotBase& operator=(RobotBase&&) = default;
|
||||
|
||||
static std::thread::id m_threadId;
|
||||
NT_Listener connListenerHandle;
|
||||
};
|
||||
|
||||
} // namespace wpi
|
||||
Reference in New Issue
Block a user