SMACC2
Loading...
Searching...
No Matches
smacc_state_machine.cpp
Go to the documentation of this file.
1// Copyright 2025 Robosoft Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*****************************************************************************************************************
16 *
17 * Authors: Pablo Inigo Blasco, Brett Aldrich
18 *
19 ******************************************************************************************************************/
20
21#include <rcl/time.h>
22#include <chrono>
23#include <functional>
28#include <smacc2_msgs/msg/smacc_status.hpp>
29#include <smacc2_msgs/msg/smacc_transition_log_entry.hpp>
30
31namespace smacc2
32{
33using namespace std::chrono_literals;
34using namespace smacc2::introspection;
36 std::string stateMachineName, SignalDetector * signalDetector, rclcpp::NodeOptions nodeOptions)
37: nh_(nullptr), stateSeqCounter_(0)
38{
39 nh_ = rclcpp::Node::make_shared(stateMachineName, nodeOptions); //
40 RCLCPP_INFO_STREAM(
41 nh_->get_logger(), "Creating state machine base: " << nh_->get_fully_qualified_name());
42
43 signalDetector_ = signalDetector;
45
46 std::string runMode;
47 if (nh_->get_parameter("run_mode", runMode))
48 {
49 if (runMode == "debug")
50 {
52 }
53 else if (runMode == "release")
54 {
56 }
57 else
58 {
59 RCLCPP_ERROR(nh_->get_logger(), "Incorrect run_mode value: %s", runMode.c_str());
60 }
61 }
62 else
63 {
65 }
66}
67
69{
70 RCLCPP_INFO(nh_->get_logger(), "Finishing State Machine");
71}
72
74{
75 RCLCPP_INFO(nh_->get_logger(), "[SmaccSignal] Object signal disconnecting %ld", (long)object_ptr);
76 if (stateCallbackConnections.count(object_ptr) > 0)
77 {
78 auto callbackSemaphore = stateCallbackConnections[object_ptr];
79 callbackSemaphore->finalize();
80 stateCallbackConnections.erase(object_ptr);
81 }
82 else
83 {
84 RCLCPP_INFO(nh_->get_logger(), "[SmaccSignal] No signals found %ld", (long)object_ptr);
85 }
86}
87
88rclcpp::Node::SharedPtr ISmaccStateMachine::getNode() { return this->nh_; }
89
91
93
95
96const std::map<std::string, std::shared_ptr<smacc2::ISmaccOrthogonal>> &
98{
99 return this->orthogonals_;
100}
101
103{
104 std::lock_guard<std::recursive_mutex> lock(m_mutex_);
105
106 if (currentStateInfo_ != nullptr)
107 {
108 RCLCPP_WARN_STREAM(
109 nh_->get_logger(),
110 "[StateMachine] Setting state active: " << currentStateInfo_->getFullPath());
111
113 {
114 status_msg_.current_states.clear();
115 std::list<const SmaccStateInfo *> ancestorList;
116 currentStateInfo_->getAncestors(ancestorList);
117
118 for (auto & ancestor : ancestorList)
119 {
120 status_msg_.current_states.push_back(ancestor->toShortName());
121 }
122
123 status_msg_.global_variable_names.clear();
124 status_msg_.global_variable_values.clear();
125
126 for (auto entry : this->globalData_)
127 {
128 status_msg_.global_variable_names.push_back(entry.first);
129 status_msg_.global_variable_values.push_back(
130 entry.second.first()); // <- invoke to_string()
131 }
132
133 status_msg_.header.stamp = this->nh_->now();
135 }
136 }
137}
138
140{
141 smacc2_msgs::msg::SmaccTransitionLogEntry transitionLogEntry;
142 transitionLogEntry.timestamp = this->nh_->now();
143 transitionInfoToMsg(transitionInfo, transitionLogEntry.transition);
144 this->transitionLogHistory_.push_back(transitionLogEntry);
145
146 transitionLogPub_->publish(transitionLogEntry);
147}
148
150
152{
153 auto ros_clock = rclcpp::Clock::make_shared();
154 timer_ =
155 rclcpp::create_timer(nh_, ros_clock, 0.5s, [=]() { this->state_machine_visualization(); });
156}
157
158void ISmaccStateMachine::initializeROS(std::string shortname)
159{
160 RCLCPP_WARN_STREAM(nh_->get_logger(), "State machine base creation: " << shortname);
161 // STATE MACHINE TOPICS
162 stateMachinePub_ = nh_->create_publisher<smacc2_msgs::msg::SmaccStateMachine>(
163 shortname + "/smacc/state_machine_description", rclcpp::QoS(1));
164 stateMachineStatusPub_ = nh_->create_publisher<smacc2_msgs::msg::SmaccStatus>(
165 shortname + "/smacc/status", rclcpp::QoS(1));
166 transitionLogPub_ = nh_->create_publisher<smacc2_msgs::msg::SmaccTransitionLogEntry>(
167 shortname + "/smacc/transition_log", rclcpp::QoS(1));
168
169 eventsLogPub_ = nh_->create_publisher<smacc2_msgs::msg::SmaccEvent>(
170 shortname + "/smacc/event_log", rclcpp::QoS(100));
171
172 // STATE MACHINE SERVICES
173 transitionHistoryService_ = nh_->create_service<smacc2_msgs::srv::SmaccGetTransitionHistory>(
174 shortname + "/smacc/transition_log_history",
175 std::bind(
176 &ISmaccStateMachine::getTransitionLogHistory, this, std::placeholders::_1,
177 std::placeholders::_2, std::placeholders::_3));
178
179 // Notify signal detector that ROS initialization is complete
180 // This allows the polling loop to start safely accessing ROS objects
182}
183
185 const std::shared_ptr<rmw_request_id_t> /*request_header*/,
186 const std::shared_ptr<smacc2_msgs::srv::SmaccGetTransitionHistory::Request> /*req*/,
187 std::shared_ptr<smacc2_msgs::srv::SmaccGetTransitionHistory::Response> res)
188{
189 RCLCPP_WARN(
190 nh_->get_logger(), "Requesting transition log history, current size: %ld",
191 this->transitionLogHistory_.size());
192 res->history = this->transitionLogHistory_;
193}
194
196{
197 std::lock_guard<std::recursive_mutex> lock(m_mutex_);
198
199 smacc2_msgs::msg::SmaccStateMachine state_machine_msg;
200 state_machine_msg.states = stateMachineInfo_->stateMsgs;
201
202 std::sort(
203 state_machine_msg.states.begin(), state_machine_msg.states.end(),
204 [](auto & a, auto & b) { return a.index < b.index; });
205 stateMachinePub_->publish(state_machine_msg);
206
207 status_msg_.header.stamp = this->nh_->now();
209}
210
212{
213 RCLCPP_DEBUG(nh_->get_logger(), "-- locking SM: %s", msg.c_str());
214 m_mutex_.lock();
215}
216
218{
219 RCLCPP_DEBUG(nh_->get_logger(), "-- unlocking SM: %s", msg.c_str());
220 m_mutex_.unlock();
221}
222
224{
225 return demangleSymbol(typeid(*this).name());
226}
227
229
230} // namespace smacc2
std::map< std::string, std::shared_ptr< smacc2::ISmaccOrthogonal > > orthogonals_
void publishTransition(const SmaccTransitionInfo &transitionInfo)
rclcpp::Publisher< smacc2_msgs::msg::SmaccStateMachine >::SharedPtr stateMachinePub_
std::shared_ptr< SmaccStateInfo > currentStateInfo_
rclcpp::Node::SharedPtr getNode()
std::map< std::string, std::pair< std::function< std::string()>, boost::any > > globalData_
rclcpp::Service< smacc2_msgs::srv::SmaccGetTransitionHistory >::SharedPtr transitionHistoryService_
virtual void onInitialize()
this function should be implemented by the user to create the orthogonals
std::vector< smacc2_msgs::msg::SmaccTransitionLogEntry > transitionLogHistory_
const std::map< std::string, std::shared_ptr< smacc2::ISmaccOrthogonal > > & getOrthogonals() const
rclcpp::Publisher< smacc2_msgs::msg::SmaccStatus >::SharedPtr stateMachineStatusPub_
ISmaccStateMachine(std::string stateMachineName, SignalDetector *signalDetector, rclcpp::NodeOptions nodeOptions=rclcpp::NodeOptions())
void lockStateMachine(std::string msg)
void disconnectSmaccSignalObject(void *object)
void unlockStateMachine(std::string msg)
rclcpp::TimerBase::SharedPtr timer_
rclcpp::Publisher< smacc2_msgs::msg::SmaccTransitionLogEntry >::SharedPtr transitionLogPub_
std::map< void *, std::shared_ptr< CallbackCounterSemaphore > > stateCallbackConnections
void initializeROS(std::string smshortname)
smacc2_msgs::msg::SmaccStatus status_msg_
std::shared_ptr< SmaccStateMachineInfo > stateMachineInfo_
rclcpp::Publisher< smacc2_msgs::msg::SmaccEvent >::SharedPtr eventsLogPub_
void getTransitionLogHistory(const std::shared_ptr< rmw_request_id_t > request_header, const std::shared_ptr< smacc2_msgs::srv::SmaccGetTransitionHistory::Request > req, std::shared_ptr< smacc2_msgs::srv::SmaccGetTransitionHistory::Response > res)
void initialize(ISmaccStateMachine *stateMachine)
std::string demangleSymbol()
void transitionInfoToMsg(const SmaccTransitionInfo &transition, smacc2_msgs::msg::SmaccTransition &transitionMsg)