SMACC2
Loading...
Searching...
No Matches
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: nh_(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
81{
82 RCLCPP_INFO(
83 nh_->get_logger(), "[SmaccSignals] object signal disconnecting %ld", (long)object_ptr);
84 if (stateCallbackConnections.count(object_ptr) > 0)
85 {
86 auto callbackSemaphore = stateCallbackConnections[object_ptr];
87 callbackSemaphore->finalize();
88 stateCallbackConnections.erase(object_ptr);
89 }
90 else
91 {
92 RCLCPP_INFO(nh_->get_logger(), "[SmaccSignals] no signals found %ld", (long)object_ptr);
93 }
94}
95
96rclcpp::Node::SharedPtr ISmaccStateMachine::getNode() { return this->nh_; }
97
99
101
103
104const std::map<std::string, std::shared_ptr<smacc2::ISmaccOrthogonal>> &
106{
107 return this->orthogonals_;
108}
109
111{
112 std::lock_guard<std::recursive_mutex> lock(m_mutex_);
113
114 if (currentStateInfo_ != nullptr)
115 {
116 RCLCPP_WARN_STREAM(
117 nh_->get_logger(), "[StateMachine] setting state active "
118 << ": " << currentStateInfo_->getFullPath());
119
121 {
122 status_msg_.current_states.clear();
123 std::list<const SmaccStateInfo *> ancestorList;
124 currentStateInfo_->getAncestors(ancestorList);
125
126 for (auto & ancestor : ancestorList)
127 {
128 status_msg_.current_states.push_back(ancestor->toShortName());
129 }
130
131 status_msg_.global_variable_names.clear();
132 status_msg_.global_variable_values.clear();
133
134 for (auto entry : this->globalData_)
135 {
136 status_msg_.global_variable_names.push_back(entry.first);
137 status_msg_.global_variable_values.push_back(
138 entry.second.first()); // <- invoke to_string()
139 }
140
141 status_msg_.header.stamp = this->nh_->now();
143 }
144 }
145}
146
148{
149 smacc2_msgs::msg::SmaccTransitionLogEntry transitionLogEntry;
150 transitionLogEntry.timestamp = this->nh_->now();
151 transitionInfoToMsg(transitionInfo, transitionLogEntry.transition);
152 this->transitionLogHistory_.push_back(transitionLogEntry);
153
154 transitionLogPub_->publish(transitionLogEntry);
155}
156
158
160{
161 auto ros_clock = rclcpp::Clock::make_shared();
162 timer_ =
163 rclcpp::create_timer(nh_, ros_clock, 0.5s, [=]() { this->state_machine_visualization(); });
164}
165
166void ISmaccStateMachine::initializeROS(std::string shortname)
167{
168 RCLCPP_WARN_STREAM(nh_->get_logger(), "State machine base creation:" << shortname);
169 // STATE MACHINE TOPICS
170 stateMachinePub_ = nh_->create_publisher<smacc2_msgs::msg::SmaccStateMachine>(
171 shortname + "/smacc/state_machine_description", 1);
173 nh_->create_publisher<smacc2_msgs::msg::SmaccStatus>(shortname + "/smacc/status", 1);
174 transitionLogPub_ = nh_->create_publisher<smacc2_msgs::msg::SmaccTransitionLogEntry>(
175 shortname + "/smacc/transition_log", 1);
176
177 // STATE MACHINE SERVICES
178 transitionHistoryService_ = nh_->create_service<smacc2_msgs::srv::SmaccGetTransitionHistory>(
179 shortname + "/smacc/transition_log_history",
180 std::bind(
181 &ISmaccStateMachine::getTransitionLogHistory, this, std::placeholders::_1,
182 std::placeholders::_2, std::placeholders::_3));
183}
184
186 const std::shared_ptr<rmw_request_id_t> /*request_header*/,
187 const std::shared_ptr<smacc2_msgs::srv::SmaccGetTransitionHistory::Request> /*req*/,
188 std::shared_ptr<smacc2_msgs::srv::SmaccGetTransitionHistory::Response> res)
189{
190 RCLCPP_WARN(
191 nh_->get_logger(), "Requesting Transition Log History, current size: %ld",
192 this->transitionLogHistory_.size());
193 res->history = this->transitionLogHistory_;
194}
195
197{
198 std::lock_guard<std::recursive_mutex> lock(m_mutex_);
199
200 smacc2_msgs::msg::SmaccStateMachine state_machine_msg;
201 state_machine_msg.states = stateMachineInfo_->stateMsgs;
202
203 std::sort(
204 state_machine_msg.states.begin(), state_machine_msg.states.end(),
205 [](auto & a, auto & b) { return a.index < b.index; });
206 stateMachinePub_->publish(state_machine_msg);
207
208 status_msg_.header.stamp = this->nh_->now();
210}
211
213{
214 RCLCPP_DEBUG(nh_->get_logger(), "-- locking SM: %s", msg.c_str());
215 m_mutex_.lock();
216}
217
219{
220 RCLCPP_DEBUG(nh_->get_logger(), "-- unlocking SM: %s", msg.c_str());
221 m_mutex_.unlock();
222}
223
225{
226 return demangleSymbol(typeid(*this).name());
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)
void lockStateMachine(std::string msg)
void disconnectSmaccSignalObject(void *object)
rclcpp::Node::SharedPtr nh_
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_
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)
Definition: reflection.cpp:30