node_common.cpp
Go to the documentation of this file.
1 //
3 // Parker-Lord Inertial Device Driver Implementation File
4 //
5 // Copyright (c) 2017, Brian Bingham
6 // Copyright (c) 2020, Parker Hannifin Corp
7 // This code is licensed under MIT license (see LICENSE file for details)
8 //
10 
11 #include <thread>
12 #include <string>
13 #include <iomanip>
14 #include <algorithm>
15 
17 
18 namespace microstrain
19 {
20 
21 constexpr auto NMEA_MAX_LENGTH = 82;
22 
23 void logCallbackProxy(void* user, mip_log_level level, const char* fmt, va_list args)
24 {
25  // Convert the varargs into a string
26  std::string log_str;
27  va_list args_copy;
28  va_copy(args_copy, args);
29  const int required_len = vsnprintf(nullptr, 0, fmt, args_copy);
30  if (required_len >= 0)
31  {
32  log_str.resize(required_len);
33  vsnprintf(&log_str[0], required_len + 1, fmt, args);
34  }
35  va_end(args_copy);
36 
37  // Send to the real logging callback after removing the newline (ROS adds one back)
38  if (!log_str.empty())
39  {
40  log_str.pop_back();
41  reinterpret_cast<NodeCommon*>(user)->logCallback(level, "MIP SDK: " + log_str);
42  }
43 }
44 
46 {
47  // This should receive all packets, populate ROS messages and publish them as well
48  if (!config_.mip_device_->device().update())
49  {
50  MICROSTRAIN_ERROR(node_, "Unable to update device");
51 
52  // Attempt a reconnect
53  bool reconnected = false;
54  int reconnect_attempt = 0;
55  while (reconnect_attempt++ < config_.reconnect_attempts_)
56  {
57  MICROSTRAIN_WARN(node_, "Reconnect attempt %d...", reconnect_attempt);
58  if (config_.mip_device_->reconnect())
59  {
60  MICROSTRAIN_INFO(node_, "Successfully reconnected to the device");
62  {
63  MICROSTRAIN_INFO(node_, "Reconfiguring device...");
64  config_.mip_device_->disconnect(); // We will reconnect to the device in the configure call
66  continue;
67  }
68 
69  // Reactivate
70  if (!publishers_.configure())
71  continue;
72  if (!activate())
73  continue;
74 
75  // Reconnected
76  reconnected = true;
77  break;
78  }
79 
80  // Wait between attempts
81  std::this_thread::sleep_for(std::chrono::seconds(5));
82  }
83 
84  if (!reconnected)
85  {
86  throw std::runtime_error("Device disconnected");
87  }
88  }
89 
90  // Publish the NMEA messages
91  if (config_.mip_device_->shouldParseNmea())
92  {
93  for (auto& nmea_message : config_.mip_device_->nmeaMsgs())
94  {
95  // Determine the right frame ID based on the talker ID
96  const std::string& talker_id_str = nmea_message.sentence.substr(1, 2);
98  nmea_message.header.frame_id = config_.nmea_talker_id_to_frame_id_mapping_.at(talker_id_str);
99  else
100  nmea_message.header.frame_id = config_.frame_id_;
101  publishers_.nmea_sentence_pub_->publish(nmea_message);
102  }
103  }
104 }
105 
107 {
108  // This should receive all packets and populate NMEA messages
109  config_.aux_device_->device().update();
110 
111  // Publish the NMEA messages
112  if (config_.aux_device_->shouldParseNmea())
113  {
114  for (auto& nmea_message : config_.aux_device_->nmeaMsgs())
115  {
116  // Assume that the aux port will only produce NMEA from GNSS1
117  nmea_message.header.frame_id = config_.gnss_frame_id_[GNSS1_ID];
118  publishers_.nmea_sentence_pub_->publish(nmea_message);
119  }
120  }
121 }
122 
123 void NodeCommon::logCallback(const mip_log_level level, const std::string& log_str)
124 {
125  switch (level)
126  {
127  case MIP_LOG_LEVEL_FATAL:
128  MICROSTRAIN_FATAL(node_, "%s", log_str.c_str());
129  break;
130  case MIP_LOG_LEVEL_ERROR:
131  MICROSTRAIN_ERROR(node_, "%s", log_str.c_str());
132  break;
133  case MIP_LOG_LEVEL_WARN:
134  MICROSTRAIN_WARN(node_, "%s", log_str.c_str());
135  break;
136  case MIP_LOG_LEVEL_INFO:
137  MICROSTRAIN_INFO(node_, "%s", log_str.c_str());
138  break;
139  case MIP_LOG_LEVEL_DEBUG:
140  MICROSTRAIN_DEBUG(node_, "%s", log_str.c_str());
141  break;
142  }
143 }
144 
145 bool NodeCommon::initialize(RosNodeType* init_node)
146 {
147  node_ = init_node;
148  config_ = Config(node_);
152 
153  // Initialize the MIP SDK logger
155 
156  return true;
157 }
158 
159 bool NodeCommon::configure(RosNodeType* config_node)
160 {
161  if (!node_)
162  return false;
163 
164  MICROSTRAIN_DEBUG(node_, "Reading config");
165  if (!config_.configure(config_node))
166  {
167  MICROSTRAIN_ERROR(node_, "Failed to read configuration for node");
168  return false;
169  }
170  MICROSTRAIN_DEBUG(node_, "Configuring Publishers");
171  if (!publishers_.configure())
172  {
173  MICROSTRAIN_ERROR(node_, "Failed to configure publishers");
174  return false;
175  }
176 
177  MICROSTRAIN_DEBUG(node_, "Configuring Services");
178  if (!services_.configure())
179  {
180  MICROSTRAIN_ERROR(node_, "Failed to setup services");
181  return false;
182  }
183 
184  // Determine loop rate as 2*(max update rate), but abs. max of 1kHz
185  const int max_rate = std::max({config_.nmea_max_rate_hz_, config_.mip_publisher_mapping_->getMaxDataRate()});
186  timer_update_rate_hz_ = std::min(2 * max_rate, 2000);
187  if (timer_update_rate_hz_ <= 100)
188  timer_update_rate_hz_ = 100.0;
189  MICROSTRAIN_INFO(node_, "Setting spin rate to <%f> hz", timer_update_rate_hz_);
190 
191  // Save the config node for later
192  config_node_ = config_node;
193 
194  return true;
195 }
196 
198 {
199  if (!node_)
200  return false;
201 
202  // Activate the subscribers
203  MICROSTRAIN_DEBUG(node_, "Activating Subscribers");
204  if (!subscribers_.activate())
205  {
206  MICROSTRAIN_ERROR(node_, "Failed to activate subscribers");
207  return false;
208  }
209 
210  // Activate the publishers
211  MICROSTRAIN_DEBUG(node_, "Activating publishers");
212  if (!publishers_.activate())
213  {
214  MICROSTRAIN_ERROR(node_, "Failed to activate publishers");
215  return false;
216  }
217 
218  // Resume the device
219  mip::CmdResult mip_cmd_result;
220  MICROSTRAIN_INFO(node_, "Resuming the device data streams");
222  {
223  MICROSTRAIN_ERROR(node_, "Failed to resume device data streams");
224  MICROSTRAIN_ERROR(node_, "Error(%d): %s", mip_cmd_result.value, mip_cmd_result.name());
225  return false;
226  }
227 
228  MICROSTRAIN_INFO(node_, "Node activated");
229  return true;
230 }
231 
233 {
234  // Stop the timers.
235  if (main_parsing_timer_ != nullptr)
236  stopTimer(main_parsing_timer_);
237  if (aux_parsing_timer_ != nullptr)
238  stopTimer(aux_parsing_timer_);
239 
240  // Set the device to idle
241  mip::CmdResult mip_cmd_result;
242  MICROSTRAIN_INFO(node_, "Forcing the device to idle");
243  if (config_.mip_device_)
244  {
245  if (!(mip_cmd_result = config_.mip_device_->forceIdle()))
246  {
247  MICROSTRAIN_ERROR(node_, "Unable to set node to idle");
248  MICROSTRAIN_ERROR(node_, "Error(%d): %s", mip_cmd_result.value, mip_cmd_result.name());
249  }
250  }
251 
252  return true;
253 }
254 
256 {
257  // Reset the timers
258  main_parsing_timer_.reset();
259  aux_parsing_timer_.reset();
260 
261  // Disconnect the device
262  if (config_.mip_device_)
263  config_.mip_device_.reset();
264 
265  // Disconnect the aux device
266  if (config_.aux_device_)
267  config_.aux_device_.reset();
268 
269  // Close the raw data file if enabled
271  config_.raw_file_.close();
272 
273  return true;
274 }
275 
276 } // namespace microstrain
microstrain::NodeCommon::main_parsing_timer_
RosTimerType main_parsing_timer_
Definition: node_common.h:94
microstrain::NodeCommon::shutdown
bool shutdown()
Shuts down the node.
Definition: node_common.cpp:255
mip_log_level
uint8_t mip_log_level
Logging level enum.
Definition: mip_logging.h:26
microstrain::NodeCommon::config_
Config config_
Definition: node_common.h:87
microstrain::Services
Contains service functions and service handles.
Definition: services.h:32
microstrain::Config::mip_device_
std::shared_ptr< RosMipDeviceMain > mip_device_
Definition: config.h:84
microstrain::Config::nmea_max_rate_hz_
float nmea_max_rate_hz_
Definition: config.h:184
microstrain::NodeCommon::services_
Services services_
Definition: node_common.h:90
microstrain::Services::configure
bool configure()
Configures the services.
Definition: services.cpp:23
microstrain::NMEA_MAX_LENGTH
constexpr auto NMEA_MAX_LENGTH
Definition: node_common.cpp:21
microstrain::NodeCommon::configure
bool configure(RosNodeType *config_node)
Configures the node.
Definition: node_common.cpp:159
microstrain::Config::aux_device_
std::shared_ptr< RosMipDeviceAux > aux_device_
Definition: config.h:85
microstrain::logCallbackProxy
void logCallbackProxy(void *user, mip_log_level level, const char *fmt, va_list args)
Definition: node_common.cpp:23
microstrain::NodeCommon::node_
RosNodeType * node_
Definition: node_common.h:85
microstrain::NodeCommon::logCallback
void logCallback(const mip_log_level level, const std::string &log_str)
Definition: node_common.cpp:123
microstrain::NodeCommon::activate
bool activate()
Activates the node.
Definition: node_common.cpp:197
microstrain::Config::frame_id_
std::string frame_id_
Definition: config.h:124
microstrain::NodeCommon::parseAndPublishMain
void parseAndPublishMain()
Reads messages from the main port of the device, parses them, and publishes them.
Definition: node_common.cpp:45
microstrain::NodeCommon::timer_update_rate_hz_
double timer_update_rate_hz_
Definition: node_common.h:92
mip_cmd_result
mip_cmd_result
Represents the status of a MIP command.
Definition: mip_result.h:25
microstrain::NodeCommon::initialize
bool initialize(RosNodeType *init_node)
Initializes the node into an idle state.
Definition: node_common.cpp:145
microstrain::Config::configure_after_reconnect_
bool configure_after_reconnect_
Definition: config.h:90
MIP_LOG_LEVEL_WARN
#define MIP_LOG_LEVEL_WARN
Warning logs are logged when something concerning happens that may or not be a mistake.
Definition: mip_logging.h:30
microstrain::Publishers::configure
bool configure()
Configures the publishers.
Definition: publishers.cpp:78
microstrain::Config
Contains configuration information for the node, configures the device on startup This class holds th...
Definition: config.h:58
microstrain::NodeCommon::publishers_
Publishers publishers_
Definition: node_common.h:88
mip::commands_base::resume
TypedResult< Resume > resume(C::mip_interface &device)
Definition: commands_base.cpp:239
microstrain::Config::reconnect_attempts_
int reconnect_attempts_
Definition: config.h:89
microstrain::NodeCommon::aux_parsing_timer_
RosTimerType aux_parsing_timer_
Definition: node_common.h:95
microstrain::NodeCommon::subscribers_
Subscribers subscribers_
Definition: node_common.h:89
microstrain::NodeCommon::config_node_
RosNodeType * config_node_
Definition: node_common.h:86
microstrain::Publishers::Publisher::publish
void publish()
Publishes the message on the publisher.
Definition: publishers.h:164
microstrain::Publishers::activate
bool activate()
Only technically needed for ROS2 lifecycle publishers, this will activate the publishers,...
Definition: publishers.cpp:381
microstrain::Publishers::nmea_sentence_pub_
Publisher< NMEASentenceMsg >::SharedPtr nmea_sentence_pub_
Definition: publishers.h:279
node_common.h
microstrain::Config::configure
bool configure(RosNodeType *node)
Reads configuration, and configures the device.
Definition: config.cpp:45
microstrain::Config::raw_file_
std::ofstream raw_file_
Definition: config.h:179
microstrain::NodeCommon::parseAndPublishAux
void parseAndPublishAux()
Reads messages from the aux port of the device, parses them, and publishes them.
Definition: node_common.cpp:106
microstrain::NodeCommon::deactivate
bool deactivate()
Deactivates the node.
Definition: node_common.cpp:232
MIP_LOG_LEVEL_INFO
#define MIP_LOG_LEVEL_INFO
Info logs are logged when some general info needs to be conveyed to the user.
Definition: mip_logging.h:31
MIP_LOG_LEVEL_DEBUG
#define MIP_LOG_LEVEL_DEBUG
Debug logs are logged for debug purposes.
Definition: mip_logging.h:32
microstrain::Config::gnss_frame_id_
std::string gnss_frame_id_[NUM_GNSS]
Definition: config.h:129
microstrain::Config::raw_file_enable_
bool raw_file_enable_
Definition: config.h:177
microstrain::NodeCommon
Base class for ROS1 and ROS2 nodes.
Definition: node_common.h:33
microstrain::Config::mip_publisher_mapping_
std::shared_ptr< MipPublisherMapping > mip_publisher_mapping_
Definition: config.h:86
MIP_LOG_LEVEL_ERROR
#define MIP_LOG_LEVEL_ERROR
Error logs are logged when an error occurs.
Definition: mip_logging.h:29
microstrain::Subscribers::activate
bool activate()
Activates the subscribers.
Definition: subscribers.cpp:31
microstrain::Subscribers
Contains subscribers and the functions they call.
Definition: subscribers.h:42
MIP_LOG_LEVEL_FATAL
#define MIP_LOG_LEVEL_FATAL
Fatal logs are logged when an unrecoverable error occurs.
Definition: mip_logging.h:28
microstrain::GNSS1_ID
constexpr auto GNSS1_ID
Definition: ros_compat.h:39
microstrain::Publishers
Contains ROS messages and the publishers that will publish them.
Definition: publishers.h:32
MIP_LOG_INIT
#define MIP_LOG_INIT(callback, level, user)
Helper macro used to initialize the MIP logger.
Definition: mip_logging.h:63
microstrain
ROS1 Includes.
Definition: microstrain_inertial_driver.h:23
microstrain::Config::nmea_talker_id_to_frame_id_mapping_
std::map< std::string, std::string > nmea_talker_id_to_frame_id_mapping_
Definition: config.h:185


microstrain_inertial_driver
Author(s): Brian Bingham, Parker Hannifin Corp
autogenerated on Mon Jun 24 2024 02:51:40