Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature obc state machine makeover #580

Draft
wants to merge 11 commits into
base: dev
Choose a base branch
from
7 changes: 6 additions & 1 deletion atos/modules/ObjectControl/inc/objectcontrol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ namespace AbsoluteKinematics {
class RemoteControlled;
}

class SmImpl;

/*!
* \brief The ObjectControl class is intended as an overarching device
* used to control a scenario. No behaviour is implemented in it
Expand All @@ -86,6 +88,9 @@ namespace AbsoluteKinematics {
*/
class ObjectControl : public Module
{
// Forward declare state machine
class Sm;
friend class SmImpl;
friend class ObjectControlState;
friend class AbstractKinematics::Idle;
friend class AbstractKinematics::Initialized;
Expand Down Expand Up @@ -361,7 +366,7 @@ class ObjectControl : public Module
void injectObjectData(const MonitorMessage& monr);
//! \brief TODO
OsiHandler::LocalObjectGroundTruth_t buildOSILocalGroundTruth(const MonitorMessage&) const;

std::unique_ptr<Sm> sm;
void publishScenarioInfoToJournal();
};

204 changes: 204 additions & 0 deletions atos/modules/ObjectControl/inc/sm_impl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
#include "sml.hpp"
#include "objectcontrol.hpp"
#include <chrono>

#pragma once

// State transitions
class SmImpl {
public:
// States
constexpr static auto idle = boost::sml::state<class Idle>;
constexpr static auto initialized = boost::sml::state<class Initialized>;
constexpr static auto connecting = boost::sml::state<class Connecting>; // Is this really a state? could be a transition, if we wait for all objects to connect
constexpr static auto armed = boost::sml::state<class Armed>;
constexpr static auto disarming = boost::sml::state<class Disarming>; // Same with this one
constexpr static auto aborting = boost::sml::state<class Aborting>; // Same with this one
constexpr static auto ready = boost::sml::state<class Ready>;
constexpr static auto testlive = boost::sml::state<class TestLive>;

// Events
struct InitializeRequest {};
struct ConnectRequest {};
struct DisconnectRequest {};
struct ArmRequest {};
struct DisarmRequest {};
struct StartRequest {};
struct AbortRequest {};
struct StartObjectRequest {
uint32_t id;
std::chrono::system_clock::time_point startTime;
};
struct ConnectedToObject {};
struct ConnectedToLiveObject {};
struct DisconnectedFromObject {};
struct ObjectDisarmed {};
struct AllObjectsConnected {};
struct AllObjectsDisarmed {};
struct ObjectAborting {};

// Guards
struct scenarioLoaded {
auto operator()(ObjectControl* handler) {
return handler->loadScenario();
}
} scenarioLoaded;

struct allObjectsConnected{
auto operator()(ObjectControl* handler) {
handler->areAllObjectsIn(OBJECT_STATE_DISARMED);
};
} allObjectsConnected;

struct anyObjectInArmedState{
auto operator()(ObjectControl* handler) {
handler->isAnyObjectIn(OBJECT_STATE_ARMED);
};
} anyObjectInArmedState;

struct allObjectsInArmedState{
auto operator()(ObjectControl* handler) {
handler->areAllObjectsIn(OBJECT_STATE_ARMED);
};
} allObjectsInArmedState;

struct anyObjectInRunningState{
auto operator()(ObjectControl* handler) {
handler->isAnyObjectIn(OBJECT_STATE_RUNNING);
};
} anyObjectInRunningState;

struct allObjectsDisarmedOrDisconnected{
auto operator()(ObjectControl* handler) {
static auto disarmedOrDisconnected = [](const std::shared_ptr<TestObject> obj) {
return obj->getState() == OBJECT_STATE_DISARMED || !obj->isConnected();
};
handler->areAllObjects(disarmedOrDisconnected);
};
} allObjectsDisarmedOrDisconnected;

struct allObjectsDisarmed{
auto operator()(ObjectControl* handler) {
handler->areAllObjectsIn(OBJECT_STATE_DISARMED);
};
} allObjectsDisarmed;

// Actions
struct setKinematicsMode {
auto operator()(ObjectControl* handler) {
//JournalRecordData(JournalRecordType::JOURNAL_RECORD_EVENT, "INIT successful");
try {
auto anchorID = handler->getAnchorObjectID();
handler->transformScenarioRelativeTo(anchorID);
handler->controlMode = ObjectControl::RELATIVE_KINEMATICS;
RCLCPP_INFO(handler->get_logger(), "Relative control mode enabled");
} catch (std::invalid_argument&) {
handler->controlMode = ObjectControl::ABSOLUTE_KINEMATICS;
RCLCPP_INFO(handler->get_logger(), "Absolute control mode enabled");
}
}
} setKinematicsMode;

struct connectToTestObjects{
auto operator()(ObjectControl* handler) {
//RCLCPP_INFO(handler->get_logger(), "Handling connect request");
//JournalRecordData(JOURNAL_RECORD_EVENT, "CONNECT received");
handler->beginConnectionAttempt();
};
} connectToTestObjects;

struct clearScenario{
auto operator()(ObjectControl* handler) {
handler->clearScenario();
};
} clearScenario;

struct disconnectFromTestObjects{
auto operator()(ObjectControl* handler) {
//JournalRecordData(JOURNAL_RECORD_EVENT, "DISCONNECT received");
handler->abortConnectionAttempt();
handler->disconnectObjects();
};
} disconnectFromTestObjects;

struct armObjects{
auto operator()(ObjectControl* handler) {
//JournalRecordData(JOURNAL_RECORD_EVENT, "ARM received");
handler->armObjects();
};
} armObjects;

struct startListeners{
auto operator()(ObjectControl* handler) {
handler->startListeners();
handler->notifyObjectsConnected();
};
} startListeners;

struct disarmObjects{
auto operator()(ObjectControl* handler) {
//JournalRecordData(JOURNAL_RECORD_EVENT, "DISARM received");
handler->disarmObjects();
};
} disarmObjects;

struct startObjectRequest{
auto operator()(ObjectControl* handler, StartObjectRequest const& request) {
handler->startObject(request.id, request.startTime);
};
} startObjectRequest;

auto operator()() const noexcept {
using namespace boost::sml;
return make_transition_table(
// Idle states
*idle + event<InitializeRequest> [scenarioLoaded] / setKinematicsMode = initialized,
*idle + event<InitializeRequest> [!scenarioLoaded] = idle,

// Initialized can go back to idle or connecting
initialized + event<ConnectRequest> = connecting,
initialized + event<DisconnectRequest> / clearScenario = idle,

// Try to connect
connecting + event<DisconnectRequest> / disconnectFromTestObjects = idle,
connecting + event<ConnectedToObject> [anyObjectInArmedState] = disarming,
connecting + event<ConnectedToObject> [anyObjectInRunningState] = aborting,
connecting + event<ConnectedToObject> [!allObjectsConnected] = connecting,
connecting + event<ConnectedToObject> [allObjectsConnected] / armObjects = armed,
connecting + event<AllObjectsConnected> / startListeners = ready,

// Try to disarm
disarming + event<DisconnectRequest> / disconnectFromTestObjects = idle,
disarming + event<ObjectDisarmed> [allObjectsDisarmedOrDisconnected] = ready,
disarming + event<ObjectDisarmed> [!allObjectsDisarmedOrDisconnected] = disarming,
disarming + event<AllObjectsDisarmed> = ready,

// Armed state (some transitions missing here..?)
armed + event<StartRequest> [allObjectsInArmedState] = testlive,
armed + event<DisarmRequest> = disarming,
armed + event<ObjectDisarmed> = ready,
armed + event<DisconnectedFromObject> = disarming,

// TestLive state
testlive + event<AbortRequest> = aborting,
testlive + event<StartObjectRequest> / startObjectRequest = testlive,

// Abort when object requests it, when the operator request it, or when something goes wrong
connecting + event<ObjectAborting> = aborting,
connecting + event<ConnectedToLiveObject> = aborting,
connecting + event<AbortRequest> = aborting,
disarming + event<ObjectAborting> = aborting,
disarming + event<ConnectedToLiveObject> = aborting,
disarming + event<AbortRequest> = aborting,
armed + event<AbortRequest> = aborting,
armed + event<ObjectAborting> = aborting,
armed + event<ConnectedToLiveObject> = aborting,

// on_entry functions for states
idle + on_entry<_> / clearScenario,
connecting + on_entry<_> / connectToTestObjects,
armed + on_entry<_> / armObjects,
disarming + on_entry<_> / disarmObjects
);
}
};
Loading
Loading