SMACC2
smacc_state_machine.cpp
Go to the documentation of this file.
1// Copyright 2021 RobosoftAI 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)
37: currentState_(nullptr), stateSeqCounter_(0)
38{
39 rclcpp::NodeOptions node_options;
40 // This enables loading arbitrary parameters
41 // However, best practice would be to declare parameters in the corresponding classes
42 // and provide descriptions about expected use
43 // TODO(henningkayser): remove once all parameters are declared inside the components
44 // node_options.automatically_declare_parameters_from_overrides(true);
45
46 nh_ = rclcpp::Node::make_shared(stateMachineName, node_options); //
47 RCLCPP_INFO_STREAM(
48 nh_->get_logger(), "Creating State Machine Base: " << nh_->get_fully_qualified_name());
49
50 signalDetector_ = signalDetector;
52
53 std::string runMode;
54 if (nh_->get_parameter("run_mode", runMode))
55 {
56 if (runMode == "debug")
57 {
59 }
60 else if (runMode == "release")
61 {
63 }
64 else
65 {
66 RCLCPP_ERROR(nh_->get_logger(), "Incorrect run_mode value: %s", runMode.c_str());
67 }
68 }
69 else
70 {
72 }
73}
74
76{
77 RCLCPP_INFO(nh_->get_logger(), "Finishing State Machine");
78}
79
80rclcpp::Node::SharedPtr ISmaccStateMachine::getNode() { return this->nh_; }
81
83
85
87
88const std::map<std::string, std::shared_ptr<smacc2::ISmaccOrthogonal>> &
90{
91 return this->orthogonals_;
92}
93
95{
96 std::lock_guard<std::recursive_mutex> lock(m_mutex_);
97
98 if (currentStateInfo_ != nullptr)
99 {
100 RCLCPP_WARN_STREAM(
101 nh_->get_logger(), "[StateMachine] setting state active "
102 << ": " << currentStateInfo_->getFullPath());
103
105 {
106 status_msg_.current_states.clear();
107 std::list<const SmaccStateInfo *> ancestorList;
108 currentStateInfo_->getAncestors(ancestorList);
109
110 for (auto & ancestor : ancestorList)
111 {
112 status_msg_.current_states.push_back(ancestor->toShortName());
113 }
114
115 status_msg_.global_variable_names.clear();
116 status_msg_.global_variable_values.clear();
117
118 for (auto entry : this->globalData_)
119 {
120 status_msg_.global_variable_names.push_back(entry.first);
121 status_msg_.global_variable_values.push_back(
122 entry.second.first()); // <- invoke to_string()
123 }
124
125 status_msg_.header.stamp = this->nh_->now();
127 }
128 }
129}
130
132{
133 smacc2_msgs::msg::SmaccTransitionLogEntry transitionLogEntry;
134 transitionLogEntry.timestamp = this->nh_->now();
135 transitionInfoToMsg(transitionInfo, transitionLogEntry.transition);
136 this->transitionLogHistory_.push_back(transitionLogEntry);
137
138 transitionLogPub_->publish(transitionLogEntry);
139}
140
142
144{
145 auto ros_clock = rclcpp::Clock::make_shared();
146 timer_ =
147 rclcpp::create_timer(nh_, ros_clock, 0.5s, [=]() { this->state_machine_visualization(); });
148}
149
150void ISmaccStateMachine::initializeROS(std::string shortname)
151{
152 RCLCPP_WARN_STREAM(nh_->get_logger(), "State machine base creation:" << shortname);
153 // STATE MACHINE TOPICS
154 stateMachinePub_ = nh_->create_publisher<smacc2_msgs::msg::SmaccStateMachine>(
155 shortname + "/smacc/state_machine_description", 1);
157 nh_->create_publisher<smacc2_msgs::msg::SmaccStatus>(shortname + "/smacc/status", 1);
158 transitionLogPub_ = nh_->create_publisher<smacc2_msgs::msg::SmaccTransitionLogEntry>(
159 shortname + "/smacc/transition_log", 1);
160
161 // STATE MACHINE SERVICES
162 transitionHistoryService_ = nh_->create_service<smacc2_msgs::srv::SmaccGetTransitionHistory>(
163 shortname + "/smacc/transition_log_history",
164 std::bind(
165 &ISmaccStateMachine::getTransitionLogHistory, this, std::placeholders::_1,
166 std::placeholders::_2, std::placeholders::_3));
167}
168
170 const std::shared_ptr<rmw_request_id_t> /*request_header*/,
171 const std::shared_ptr<smacc2_msgs::srv::SmaccGetTransitionHistory::Request> /*req*/,
172 std::shared_ptr<smacc2_msgs::srv::SmaccGetTransitionHistory::Response> res)
173{
174 RCLCPP_WARN(
175 nh_->get_logger(), "Requesting Transition Log History, current size: %ld",
176 this->transitionLogHistory_.size());
177 res->history = this->transitionLogHistory_;
178}
179
181{
182 std::lock_guard<std::recursive_mutex> lock(m_mutex_);
183
184 smacc2_msgs::msg::SmaccStateMachine state_machine_msg;
185 state_machine_msg.states = stateMachineInfo_->stateMsgs;
186
187 std::sort(
188 state_machine_msg.states.begin(), state_machine_msg.states.end(),
189 [](auto & a, auto & b) { return a.index < b.index; });
190 stateMachinePub_->publish(state_machine_msg);
191
192 status_msg_.header.stamp = this->nh_->now();
194}
195
196// void ISmaccStateMachine::lockStateMachine(std::string msg)
197// {
198// RCLCPP_DEBUG(nh_->get_logger(), "-- locking SM: %s", msg.c_str());
199// m_mutex_.lock();
200// }
201
202// void ISmaccStateMachine::unlockStateMachine(std::string msg)
203// {
204// RCLCPP_DEBUG(nh_->get_logger(), "-- unlocking SM: %s", msg.c_str());
205// m_mutex_.unlock();
206// }
207
209{
210 return demangleSymbol(typeid(*this).name());
211}
212
214{
215 for (auto & conn : this->stateCallbackConnections)
216 {
217 RCLCPP_WARN_STREAM(
218 getLogger(),
219 "[StateMachine] Disconnecting scoped-lifetime SmaccSignal "
220 "subscription");
221 conn.disconnect();
222 }
223
224 this->stateCallbackConnections.clear();
225
226 currentState_ = nullptr;
227}
228
230{
231 // transition from an orthogonal that doesn’t exist.
232 // transition from a source that doesn’t exist.
233
234 // std::stringstream errorbuffer;
235 // bool errorFound = false;
236
237 // for (auto &stentry : this->stateMachineInfo_->states)
238 // {
239 // auto stinfo = stentry.second;
240
241 // for (auto &transition : stinfo->transitions_)
242 // {
243 // auto evinfo = transition.eventInfo;
244 // bool found = false;
245 // for (auto &orthogonal : orthogonals_)
246 // {
247 // if (orthogonal.first == evinfo->getOrthogonalName())
248 // {
249 // found = true;
250 // break;
251 // }
252 // }
253
254 // if (!found)
255 // {
256 // errorbuffer << "---------" << std::endl
257 // << "[Consistency Checking] Transition event refers not existing orthogonal." << std::endl
258 // << "State: " << demangleType(*stinfo->tid_) << std::endl
259 // << "Transition: " << transition.transitionTypeInfo->getFullName() << std::endl
260 // << "Orthogonal: " << evinfo->getOrthogonalName() << std::endl
261 // << "---------" << std::endl;
262
263 // errorFound = true;
264 // }
265 // //std::string getEventSourceName();
266 // //std::string getOrthogonalName();
267 // }
268 // }
269
270 // if (errorFound)
271 // {
272 // RCLCPP_WARN_STREAM(nh_->get_logger(),"== STATE MACHINE CONSISTENCY CHECK: ==" << std::endl
273 // << errorbuffer.str() << std::endl
274 // << "=================");
275 // }
276 // cb from a client that doesn’t exist – don’t worry about making clients dynamically.
277}
278
279} // 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::Node::SharedPtr nh_
rclcpp::TimerBase::SharedPtr timer_
rclcpp::Publisher< smacc2_msgs::msg::SmaccTransitionLogEntry >::SharedPtr transitionLogPub_
void initializeROS(std::string smshortname)
smacc2_msgs::msg::SmaccStatus status_msg_
std::list< boost::signals2::connection > stateCallbackConnections
std::shared_ptr< SmaccStateMachineInfo > stateMachineInfo_
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(const std::string &name)
void transitionInfoToMsg(const SmaccTransitionInfo &transition, smacc2_msgs::msg::SmaccTransition &transitionMsg)
Definition: reflection.cpp:30