mvsim-cli-topic.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2024 Jose Luis Blanco Claraco |
5  | Copyright (C) 2017 Borys Tymchenko (Odessa Polytechnic University) |
6  | Distributed under 3-clause BSD License |
7  | See COPYING |
8  +-------------------------------------------------------------------------+ */
9 
10 #include <mrpt/core/exceptions.h>
11 #include <mrpt/math/distributions.h>
12 #include <mrpt/math/ops_containers.h>
13 #include <mrpt/system/datetime.h>
14 
15 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
16 #include <mvsim/Comms/Client.h>
17 #include <mvsim/mvsim-msgs/ObservationLidar2D.pb.h>
18 #include <mvsim/mvsim-msgs/TimeStampedPose.pb.h>
19 #endif
20 
21 #include "mvsim-cli.h"
22 
23 static int printCommandsTopic(bool showErrorMsg);
24 static int topicList();
25 static int topicEcho();
26 static int topicHz();
27 
28 const std::map<std::string, cmd_t> cliTopicCommands = {
29  {"list", cmd_t(&topicList)},
30  {"echo", cmd_t(&topicEcho)},
31  {"hz", cmd_t(&topicHz)},
32 };
33 
35 {
36  const auto& lstCmds = cli->argCmd.getValue();
37  if (cli->argHelp.isSet()) return printCommandsTopic(false);
38  if (lstCmds.size() != 2 && lstCmds.size() != 3) return printCommandsTopic(true);
39 
40  // Take second unlabeled argument:
41  const std::string subcommand = lstCmds.at(1);
42  auto itSubcmd = cliTopicCommands.find(subcommand);
43 
44  if (itSubcmd == cliTopicCommands.end()) return printCommandsTopic(true);
45 
46  // Execute command:
47  return (itSubcmd->second)();
48 
49  return 0;
50 }
51 
52 int topicList()
53 {
54 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
56 
57  client.setMinLoggingLevel(mrpt::typemeta::TEnumType<mrpt::system::VerbosityLevel>::name2value(
58  cli->argVerbosity.getValue()));
59 
60  std::cout << "# Connecting to server...\n";
61  client.connect();
62  std::cout << "# Connected.\n";
63  std::cout << "# Querying list of topics to server...\n";
64  const auto lstTopics = client.requestListOfTopics();
65 
66  std::cout << "# Done. Found " << lstTopics.size() << " topics:\n";
67 
68  for (const auto& n : lstTopics)
69  {
70  if (cli->argDetails.isSet())
71  {
72  std::cout << "- name: \"" << n.name << "\"\n"
73  << " type: \"" << n.type << "\"\n"
74  << " publishers:\n";
75 
76  ASSERT_EQUAL_(n.endpoints.size(), n.publishers.size());
77 
78  for (size_t i = 0; i < n.endpoints.size(); i++)
79  {
80  std::cout << " - endpoint: \"" << n.endpoints[i] << "\"\n"
81  << " - publisherNode: \"" << n.publishers[i] << "\"\n";
82  }
83  }
84  else
85  {
86  std::cout << n.name << " [" << n.type << "] from node ";
87  if (n.publishers.size() != 1)
88  std::cout << n.publishers.size() << " publishers.\n";
89  else
90  std::cout << n.publishers.at(0) << "\n";
91  }
92  }
93 #endif
94  return 0;
95 }
96 
97 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
98 static void echo_TimeStampedPose(const std::string& data)
99 {
100  mvsim_msgs::TimeStampedPose out;
101  if (bool ok = out.ParseFromString(data); !ok)
102  {
103  std::cerr << "ERROR: Protobuf could not parse message.\n";
104  return;
105  }
106  out.PrintDebugString();
107 }
108 static void echo_ObservationLidar2D(const std::string& data)
109 {
110  mvsim_msgs::ObservationLidar2D out;
111  if (bool ok = out.ParseFromString(data); !ok)
112  {
113  std::cerr << "ERROR: Protobuf could not parse message.\n";
114  return;
115  }
116  out.PrintDebugString();
117 }
118 
119 static void callbackSubscribeTopicGeneric(const zmq::message_t& msg)
120 {
121  const auto [typeName, serializedData] = mvsim::internal::parseMessageToParts(msg);
122  std::cout << "[" << mrpt::system::dateTimeLocalToString(mrpt::Clock::now())
123  << "] Received data : \n";
124  std::cout << " - typeName: " << typeName << "\n";
125  std::cout << " - data: " << serializedData.size() << " bytes\n";
126 
127  if (typeName == mvsim_msgs::TimeStampedPose().GetTypeName())
128  echo_TimeStampedPose(serializedData);
129  else if (typeName == mvsim_msgs::ObservationLidar2D().GetTypeName())
130  echo_ObservationLidar2D(serializedData);
131 
132  std::cout << std::endl;
133 }
134 #endif
135 
137 {
138 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
140 
141  client.setMinLoggingLevel(mrpt::typemeta::TEnumType<mrpt::system::VerbosityLevel>::name2value(
142  cli->argVerbosity.getValue()));
143 
144  const auto& lstCmds = cli->argCmd.getValue();
145  if (lstCmds.size() != 3) return printCommandsTopic(true);
146 
147  const auto& topicName = lstCmds.at(2);
148 
149  std::cout << "# Connecting to server...\n";
150  client.connect();
151  std::cout << "# Connected.\n";
152 
153  std::cout << "# Subscribing to topic '" << topicName << "'. Press CTRL+C to stop.\n";
154  client.subscribe_topic_raw(topicName, &callbackSubscribeTopicGeneric);
155 
156  // loop until user does a CTRL+C
157  for (;;)
158  {
159  }
160 
161 #endif
162  return 0;
163 }
164 
165 int topicHz()
166 {
167 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
169 
170  client.setMinLoggingLevel(mrpt::typemeta::TEnumType<mrpt::system::VerbosityLevel>::name2value(
171  cli->argVerbosity.getValue()));
172 
173  const auto& lstCmds = cli->argCmd.getValue();
174  if (lstCmds.size() != 3) return printCommandsTopic(true);
175 
176  const auto& topicName = lstCmds.at(2);
177 
178  std::cout << "# Connecting to server...\n";
179  client.connect();
180  std::cout << "# Connected.\n";
181 
182  const double WAIT_SECONDS = 5.0;
183 
184  std::cout << "# Subscribing to topic '" << topicName << "'. Will listen for " << WAIT_SECONDS
185  << " seconds...\n";
186 
187  int numMsgs = 0;
188  std::optional<double> lastMsgTim;
189  std::vector<double> measuredPeriods;
190 
191  client.subscribe_topic_raw(
192  topicName,
193  [&](const zmq::message_t&)
194  {
195  numMsgs++;
196  const double t = mrpt::Clock::nowDouble();
197  if (lastMsgTim)
198  {
199  const double dt = t - lastMsgTim.value();
200  measuredPeriods.push_back(dt);
201  }
202  lastMsgTim = t;
203  });
204 
205  std::this_thread::sleep_for(
206  std::chrono::milliseconds(static_cast<size_t>(WAIT_SECONDS * 1000)));
207 
208  const double rate = numMsgs / WAIT_SECONDS;
209 
210  std::cout << std::endl;
211  std::cout << "- ReceivedMsgs: " << numMsgs << std::endl;
212  std::cout << "- Rate: " << rate << " # Hz" << std::endl;
213 
214  if (numMsgs > 0)
215  {
216  double periodMean = 0, periodStd = 0;
217  mrpt::math::meanAndStd(measuredPeriods, periodMean, periodStd);
218 
219  std::cout << "- MeanPeriod: " << periodMean << " # [sec] 1/T = " << 1.0 / periodMean
220  << " Hz" << std::endl;
221 
222  std::cout << "- PeriodStdDev: " << periodStd << " # [sec]" << std::endl;
223 
224  double periodMin = 0, periodMax = 0;
225  mrpt::math::minimum_maximum(measuredPeriods, periodMin, periodMax);
226 
227  std::cout << "- PeriodMin: " << periodMin << " # [sec]" << std::endl;
228  std::cout << "- PeriodMax: " << periodMax << " # [sec]" << std::endl;
229 
230  const double conf = 0.05;
231  double tMean, tLow, tHigh;
232 
233  mrpt::math::CVectorDouble x;
234  for (size_t i = 0; i < measuredPeriods.size(); i++) x.push_back(measuredPeriods[i]);
235 
236  mrpt::math::confidenceIntervals(x, tMean, tLow, tHigh, conf, 100);
237 
238  std::cout << "- Period_05percent: " << tLow << " # [sec]" << std::endl;
239  std::cout << "- Period_95percent: " << tHigh << " # [sec]" << std::endl;
240  }
241 
242 #endif
243  return 0;
244 }
245 
246 int printCommandsTopic(bool showErrorMsg)
247 {
248  if (showErrorMsg)
249  {
251  std::cerr << "Error: missing or unknown subcommand.\n";
253  }
254 
255  fprintf(
256  stderr,
257  R"XXX(Usage:
258 
259  mvsim topic --help Show this help
260  mvsim topic list [--details] List all advertised topics in the server
261  mvsim topic echo <topicName> Subscribe and print a topic
262  mvsim topic hz <topicName> Estimate topic publication rate (in Hz)
263 
264 )XXX");
265 
266  return showErrorMsg ? 1 : 0;
267 }
Client.h
setConsoleNormalColor
void setConsoleNormalColor()
Definition: mvsim-cli-main.cpp:41
call-shutdown.client
client
Definition: call-shutdown.py:26
printCommandsTopic
static int printCommandsTopic(bool showErrorMsg)
Definition: mvsim-cli-topic.cpp:246
topicEcho
static int topicEcho()
Definition: mvsim-cli-topic.cpp:136
mvsim::Client
Definition: Client.h:48
topicList
static int topicList()
Definition: mvsim-cli-topic.cpp:52
topicHz
static int topicHz()
Definition: mvsim-cli-topic.cpp:165
cmd_t
std::function< int(void)> cmd_t
Definition: mvsim-cli.h:65
commandTopic
int commandTopic()
Definition: mvsim-cli-topic.cpp:34
mvsim-cli.h
setConsoleErrorColor
void setConsoleErrorColor()
Definition: mvsim-cli-main.cpp:32
cli
std::unique_ptr< cli_flags > cli
Definition: mvsim-cli-main.cpp:24
conf
Definition: conf.py:1
t
geometry_msgs::TransformStamped t
cliTopicCommands
const std::map< std::string, cmd_t > cliTopicCommands
Definition: mvsim-cli-topic.cpp:28


mvsim
Author(s):
autogenerated on Wed May 28 2025 02:13:08