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>
11#include <yarp/os/LogStream.h>
12#include <time.h>
13#include <stdlib.h>
14
15using namespace yarp::sig;
16using namespace yarp::dev;
17using namespace yarp::os;
18
19namespace {
20YARP_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{
34 m_ibattery_p = nullptr;
35}
36
37bool 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
77void BatteryWrapper::attach(yarp::dev::IBattery *s)
78{
79 m_ibattery_p=s;
80}
81
82void BatteryWrapper::detach()
83{
84 m_ibattery_p = nullptr;
85}
86
87bool BatteryWrapper::read(yarp::os::ConnectionReader& connection)
88{
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
220bool 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
348void 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
361void 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
388void 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
434void 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:88
A generic battery interface.
Definition: IBattery.h:28
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:23
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:64
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:46
bool write(const PortWriter &writer, const PortWriter *callback=nullptr) const override
Write an object to the port.
Definition: Port.cpp:436
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition: Port.cpp:511
void interrupt() override
Interrupt any current reads or writes attached to the port.
Definition: Port.cpp:383
void close() override
Stop port activity.
Definition: Port.cpp:363
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:33
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:63
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.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
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:43
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:171
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCTrace(component,...)
Definition: LogComponent.h:84
#define yCWarning(component,...)
Definition: LogComponent.h:192
#define yCDebug(component,...)
Definition: LogComponent.h:128
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
For streams capable of holding different kinds of content, check what they actually have.
An interface to the operating system, including Port based communication.