YARP
Yet Another Robot Platform
BatteryWrapper.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-License-Identifier: LGPL-2.1-or-later
4  */
5 
6 #include "BatteryWrapper.h"
7 #include <sstream>
8 #include <string>
10 #include <yarp/os/LogComponent.h>
11 #include <yarp/os/LogStream.h>
12 #include <time.h>
13 #include <stdlib.h>
14 
15 using namespace yarp::sig;
16 using namespace yarp::dev;
17 using namespace yarp::os;
18 
19 namespace {
20 YARP_LOG_COMPONENT(BATTERYWRAPPER, "yarp.devices.BatteryWrapper")
21 }
22 
24 {
25  m_period = DEFAULT_THREAD_PERIOD;
26  m_ibattery_p = nullptr;
27  m_ownDevices = false;
28  memset(m_log_buffer, 0, 1024);
29 }
30 
32 {
33  threadRelease();
34  m_ibattery_p = nullptr;
35 }
36 
37 bool BatteryWrapper::attachAll(const PolyDriverList &battery2attach)
38 {
39  if (m_ownDevices)
40  {
41  return false;
42  }
43 
44  if (battery2attach.size() != 1)
45  {
46  yCError(BATTERYWRAPPER, "Cannot attach more than one device");
47  return false;
48  }
49 
50  yarp::dev::PolyDriver * Idevice2attach = battery2attach[0]->poly;
51 
52  if (Idevice2attach->isValid())
53  {
54  Idevice2attach->view(m_ibattery_p);
55  }
56 
57  if(nullptr == m_ibattery_p)
58  {
59  yCError(BATTERYWRAPPER, "Subdevice passed to attach method is invalid");
60  return false;
61  }
62  attach(m_ibattery_p);
63  PeriodicThread::setPeriod(m_period);
64  return PeriodicThread::start();
65 }
66 
68 {
69  if (PeriodicThread::isRunning())
70  {
71  PeriodicThread::stop();
72  }
73  m_ibattery_p = nullptr;
74  return true;
75 }
76 
77 void BatteryWrapper::attach(yarp::dev::IBattery *s)
78 {
79  m_ibattery_p=s;
80 }
81 
82 void BatteryWrapper::detach()
83 {
84  m_ibattery_p = nullptr;
85 }
86 
87 bool BatteryWrapper::read(yarp::os::ConnectionReader& connection)
88 {
90  yarp::os::Bottle out;
91  bool ok = in.read(connection);
92  if (!ok) {
93  return false;
94  }
95 
96  // parse in, prepare out
97  int code = in.get(0).asVocab32();
98  bool ret = false;
99  if (code == VOCAB_IBATTERY)
100  {
101  int cmd = in.get(1).asVocab32();
102  if (cmd == VOCAB_BATTERY_INFO)
103  {
104  if (m_ibattery_p)
105  {
106  std::string info;
107  m_ibattery_p->getBatteryInfo(info);
108  out.addVocab32(VOCAB_IS);
109  out.addVocab32(cmd);
110  out.addString(info);
111  ret = true;
112  }
113  }
114  else
115  {
116  yCError(BATTERYWRAPPER, "Invalid vocab received");
117  }
118  }
119  else
120  {
121  yCError(BATTERYWRAPPER, "Invalid vocab received");
122  }
123 
124  if (!ret)
125  {
126  out.clear();
128  }
129 
130  yarp::os::ConnectionWriter *returnToSender = connection.getWriter();
131  if (returnToSender != nullptr)
132  {
133  out.write(*returnToSender);
134  }
135  return true;
136 }
137 
139 {
140  return true;
141 }
142 
144 {
145  Property params;
146  params.fromString(config.toString());
147 
148  if (!config.check("period"))
149  {
150  m_period = 1.0;
151  yCWarning(BATTERYWRAPPER) << "Missing 'period' parameter. Assuming default value 1.0 s";
152  }
153  else
154  {
155  m_period = config.find("period").asFloat32();
156  }
157  yCInfo(BATTERYWRAPPER) << "Using period:" << m_period << "s";
158 
159  if (!config.check("quitPortName"))
160  {
161  m_quitPortName = config.find("quitPortName").asString();
162  }
163 
164  if (!config.check("name"))
165  {
166  yCError(BATTERYWRAPPER) << "Missing 'name' parameter. Check you configuration file; it must be like:";
167  yCError(BATTERYWRAPPER) << "--name: prefix of the ports opened by the device, e.g. /robotName/battery1";
168  yCError(BATTERYWRAPPER) << "/data:o and /rpc:i are automatically appended by the wrapper at the end";
169  return false;
170  }
171  else
172  {
173  m_streamingPortName = config.find("name").asString() + "/data:o";
174  m_rpcPortName = config.find("name").asString() + "/rpc:i";
175  }
176 
177  m_enable_shutdown = config.check("enable_shutdown", Value(0), "enable/disable the automatic shutdown").asBool();
178  m_enable_log = config.check("enable_log", Value(0), "enable/disable log to file").asBool();
179 
180  if(!initialize_YARP(config))
181  {
182  yCError(BATTERYWRAPPER) << m_sensorId << "Error initializing YARP ports";
183  return false;
184  }
185 
186  if (m_enable_log)
187  {
188  yCInfo(BATTERYWRAPPER, "writing to log file batteryLog.txt");
189  m_logFile = fopen("batteryLog.txt", "w");
190  }
191 
192  if (config.check("subdevice"))
193  {
194  PolyDriverList driverlist;
195  Property p;
196  p.fromString(config.toString());
197  p.unput("device");
198  p.unput("subdevice");
199  p.put("device", config.find("subdevice").asString());
200  p.setMonitor(config.getMonitor(), "subdevice"); // pass on any monitoring
201 
202  if (!m_driver.open(p) || !m_driver.isValid())
203  {
204  yCError(BATTERYWRAPPER) << "Failed to open subdevice.. check params";
205  return false;
206  }
207 
208  driverlist.push(&m_driver, "1");
209  if (!attachAll(driverlist))
210  {
211  yCError(BATTERYWRAPPER) << "Failed to open subdevice.. check params";
212  return false;
213  }
214  m_ownDevices = true;
215  }
216 
217  return true;
218 }
219 
220 bool BatteryWrapper::initialize_YARP(yarp::os::Searchable &params)
221 {
222  if (!m_streamingPort.open(m_streamingPortName.c_str()))
223  {
224  yCError(BATTERYWRAPPER) << "Error opening port" << m_streamingPortName;
225  return false;
226  }
227  if (!m_rpcPort.open(m_rpcPortName.c_str()))
228  {
229  yCError(BATTERYWRAPPER) << "Error opening port" << m_rpcPortName;
230  return false;
231  }
232  m_rpcPort.setReader(*this);
233  return true;
234 }
235 
237 {
238 }
239 
241 {
242  if (m_ibattery_p!=nullptr)
243  {
244  m_log_buffer[0] = 0;
245 
246  //acquire data from the wrapped device
247  bool ret_sts, ret_chg, ret_vlt, ret_cur, ret_tmp;
248  {
249  double tmp;
250  ret_chg = m_ibattery_p->getBatteryCharge(tmp);
251  if (ret_chg) {
252  m_battery_charge = tmp;
253  }
254  }
255  {
256  double tmp;
257  ret_vlt = m_ibattery_p->getBatteryVoltage(tmp);
258  if (ret_vlt) {
259  m_battery_voltage = tmp;
260  }
261  }
262  {
263  double tmp;
264  ret_cur = m_ibattery_p->getBatteryCurrent(tmp);
265  if (ret_cur) {
266  m_battery_current = tmp;
267  }
268  }
269  {
270  double tmp;
271  ret_tmp = m_ibattery_p->getBatteryTemperature(tmp);
272  if (ret_tmp) {
273  m_battery_temperature = tmp;
274  }
275  }
276  {
278  ret_sts = m_ibattery_p->getBatteryStatus(tmp);
279  if (ret_sts) {
280  m_battery_status = tmp;
281  }
282  }
283 
284  if (ret_sts)
285  {
286  m_lastStateStamp.update();
287  yarp::os::Bottle& b = m_streamingPort.prepare();
288  b.clear();
289  b.addFloat64(m_battery_voltage); //0
290  b.addFloat64(m_battery_current); //1
291  b.addFloat64(m_battery_charge); //2
292  b.addFloat64(m_battery_temperature); //3
293  b.addInt32(m_battery_status); //4
294  m_streamingPort.setEnvelope(m_lastStateStamp);
295  m_streamingPort.write();
296 
297  // if the battery is not charging, checks its status of charge
298  if (m_battery_status > 0.4) {
299  check_battery_status(m_battery_charge);
300  }
301 
302  // save data to file
303  if (m_enable_log)
304  {
305  time_t rawtime;
306  struct tm * timeinfo;
307  time(&rawtime);
308  timeinfo = localtime(&rawtime);
309  char* battery_timestamp = asctime(timeinfo);
310  std::snprintf(m_log_buffer, 1024, "battery status: %+6.1fA % 6.1fV charge:% 6.1f%% time: %s", m_battery_current, m_battery_voltage, m_battery_charge, battery_timestamp);
311  fprintf(m_logFile, "%s", m_log_buffer);
312  }
313  }
314  else
315  {
316  yCError(BATTERYWRAPPER, "BatteryWrapper: %s: Sensor returned error", m_sensorId.c_str());
317  }
318  }
319 }
320 
322 {
323  yCTrace(BATTERYWRAPPER, "BatteryWrapper::Close");
324  if (PeriodicThread::isRunning())
325  {
326  PeriodicThread::stop();
327  }
328 
329  //close the device
330  m_driver.close();
331 
332  m_streamingPort.interrupt();
333  m_streamingPort.close();
334  m_rpcPort.interrupt();
335  m_rpcPort.close();
336 
337  // save data to file
338  if (m_enable_log)
339  {
340  fclose(m_logFile);
341  }
342 
343  PeriodicThread::stop();
344  detachAll();
345  return true;
346 }
347 
348 void BatteryWrapper::notify_message(std::string msg)
349 {
350 #ifdef WIN32
351  yCWarning(BATTERYWRAPPER, "%s", msg.c_str());
352 #else
353  yCWarning(BATTERYWRAPPER, "%s", msg.c_str());
354  std::string cmd = "echo " + msg + " | wall";
355  int retval;
356  retval = system(cmd.c_str());
357  yCDebug(BATTERYWRAPPER) << "system executed command" << cmd.c_str() << " with return value:" << retval;
358 #endif
359 }
360 
361 void BatteryWrapper::emergency_shutdown(std::string msg)
362 {
363 #ifdef WIN32
364  std::string cmd;
365  cmd = "shutdown /s /t 120 /c " + msg;
366  yCWarning(BATTERYWRAPPER, "%s", msg.c_str());
367  system(cmd.c_str());
368 #else
369  std::string cmd;
370  int retval;
371  yCWarning(BATTERYWRAPPER, "%s", msg.c_str());
372  cmd = "echo " + msg + " | wall";
373  retval = system(cmd.c_str());
374  yCDebug(BATTERYWRAPPER) << "system executed command" << cmd.c_str() << " with return value:" << retval;
375 
376  cmd = "sudo shutdown -h 2 " + msg;
377  retval = system(cmd.c_str());
378  yCDebug(BATTERYWRAPPER) << "system executed command" << cmd.c_str() << " with return value:" << retval;
379 
380 #ifdef ICUB_SSH_SHUTDOWN
381  cmd = "ssh icub@pc104 sudo shutdown -h 2";
382  retval = system(cmd.c_str());
383  yCDebug(BATTERYWRAPPER) << "system executed command" << cmd.c_str() << " with return value:" << retval;
384 #endif
385 #endif
386 }
387 
388 void BatteryWrapper::check_battery_status(double battery_charge)
389 {
390  static bool notify_15 = true;
391  static bool notify_12 = true;
392  static bool notify_10 = true;
393  static bool notify_0 = true;
394 
395  if (battery_charge > 20)
396  {
397  notify_15 = true;
398  notify_12 = true;
399  notify_10 = true;
400  notify_0 = true;
401  }
402 
403  if (battery_charge < 5)
404  {
405  if (notify_0)
406  {
407  if (m_enable_shutdown)
408  {
409  emergency_shutdown("CRITICAL WARNING: battery charge below critical level 5%. The robot will be stopped and the system will shutdown in 2mins.");
410  if (m_quitPortName != "") { stop_robot(m_quitPortName); }
411  notify_0 = false;
412  }
413  else
414  {
415  notify_message("CRITICAL WARNING: battery charge reached critical level 5%, but the emergency shutodown is currently disabled!");
416  notify_0 = false;
417  }
418  }
419  }
420  else if (battery_charge < 10)
421  {
422  if (notify_10) { notify_message("WARNING: battery charge below 10%"); notify_10 = false; }
423  }
424  else if (battery_charge < 12)
425  {
426  if (notify_12) { notify_message("WARNING: battery charge below 12%"); notify_12 = false; }
427  }
428  else if (battery_charge < 15)
429  {
430  if (notify_15) { notify_message("WARNING: battery charge below 15%"); notify_15 = false; }
431  }
432 }
433 
434 void BatteryWrapper::stop_robot(std::string quit_port)
435 {
436  //typical quit_port:
437  // "/icub/quit"
438  // "/ikart/quit"
439 
440  Port port_shutdown;
441  port_shutdown.open((m_streamingPortName + "/shutdown:o").c_str());
442  yarp::os::Network::connect((m_streamingPortName + "/shutdown:o").c_str(), quit_port.c_str());
443  Bottle bot;
444  bot.addString("quit");
445  port_shutdown.write(bot);
446  port_shutdown.interrupt();
447  port_shutdown.close();
448 }
define control board standard interfaces
constexpr yarp::conf::vocab32_t VOCAB_IS
Definition: GenericVocabs.h:14
constexpr yarp::conf::vocab32_t VOCAB_FAILED
Definition: GenericVocabs.h:16
constexpr yarp::conf::vocab32_t VOCAB_IBATTERY
Definition: IBattery.h:14
constexpr yarp::conf::vocab32_t VOCAB_BATTERY_INFO
Definition: IBattery.h:15
bool ret
constexpr double DEFAULT_THREAD_PERIOD
bool attachAll(const yarp::dev::PolyDriverList &p) override
Attach to a list of objects.
void run() override
Loop function.
bool threadInit() override
Initialization method.
bool detachAll() override
Detach the object (you must have first called attach).
bool close() override
Close the DeviceDriver.
void threadRelease() override
Release method.
bool open(yarp::os::Searchable &params) override
Open the DeviceDriver.
bool view(T *&x)
Get an interface to the device driver.
Definition: DeviceDriver.h:74
A generic battery interface.
Definition: IBattery.h:30
virtual bool getBatteryCurrent(double &current)=0
Get the instantaneous current measurement.
virtual bool getBatteryVoltage(double &voltage)=0
Get the instantaneous voltage measurement.
virtual bool getBatteryInfo(std::string &battery_info)=0
get the battery hardware characteristics (e.g.
virtual bool getBatteryStatus(Battery_status &status)=0
get the battery status
virtual bool getBatteryCharge(double &charge)=0
get the battery status of charge
virtual bool getBatteryTemperature(double &temperature)=0
get the battery temperature
void push(PolyDriver *p, const char *k)
A container for a device driver.
Definition: PolyDriver.h:24
bool close() override
Close the DeviceDriver.
Definition: PolyDriver.cpp:173
bool isValid() const
Check if device is valid.
Definition: PolyDriver.cpp:196
bool open(const std::string &txt)
Construct and configure a device by its common name.
Definition: PolyDriver.cpp:140
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:74
void addVocab32(yarp::conf::vocab32_t x)
Places a vocabulary item in the bottle, at the end of the list.
Definition: Bottle.cpp:164
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition: Bottle.cpp:240
void addFloat64(yarp::conf::float64_t x)
Places a 64-bit floating point number in the bottle, at the end of the list.
Definition: Bottle.cpp:158
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:246
void clear()
Empties the bottle of any objects it contains.
Definition: Bottle.cpp:121
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
Definition: Bottle.cpp:230
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
Definition: Bottle.cpp:140
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:170
void close() override
Stop port activity.
bool setEnvelope(PortWriter &envelope) override
Set an envelope (e.g., a timestamp) to the next message which will be sent.
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
void interrupt() override
Interrupt any current reads or writes attached to the port.
void write(bool forceStrict=false)
Write the current object being returned by BufferedPort::prepare.
T & prepare()
Access the object which will be transmitted by the next call to yarp::os::BufferedPort::write.
An interface for reading from a network connection.
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
An interface for writing to a network connection.
static bool connect(const std::string &src, const std::string &dest, const std::string &carrier="", bool quiet=true)
Request that an output port connect to an input port.
Definition: Network.cpp:682
An abstraction for a periodic thread.
A mini-server for network communication.
Definition: Port.h:47
bool write(const PortWriter &writer, const PortWriter *callback=nullptr) const override
Write an object to the port.
Definition: Port.cpp:427
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition: Port.cpp:502
void interrupt() override
Interrupt any current reads or writes attached to the port.
Definition: Port.cpp:374
void close() override
Stop port activity.
Definition: Port.cpp:354
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
Definition: Port.cpp:79
A class for storing options and configuration information.
Definition: Property.h:34
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1063
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:1015
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
Definition: Property.cpp:1046
A base class for nested structures that can be searched.
Definition: Searchable.h:66
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
void update()
Set the timestamp to the current time, and increment the sequence number (wrapping to 0 if the sequen...
Definition: Stamp.cpp:124
A single value (typically within a Bottle).
Definition: Value.h:45
virtual yarp::conf::vocab32_t asVocab32() const
Get vocabulary identifier as an integer.
Definition: Value.cpp:228
virtual yarp::conf::float32_t asFloat32() const
Get 32-bit floating point value.
Definition: Value.cpp:216
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
#define yCInfo(component,...)
Definition: LogComponent.h:132
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCTrace(component,...)
Definition: LogComponent.h:85
#define yCWarning(component,...)
Definition: LogComponent.h:143
#define yCDebug(component,...)
Definition: LogComponent.h:109
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
An interface for the device drivers.
An interface to the operating system, including Port based communication.
Signal processing.
Definition: Image.h:22