power_monitor.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2009, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #include "power_monitor.h"
36 
37 using namespace std;
38 using namespace power_monitor;
39 
40 PowerMonitor::PowerMonitor() : master_state_(-1),
41  battery_update_timeout_(120)
42 {
43  ros::NodeHandle node;
44  ros::NodeHandle pnh("~");
45 
46  static const string battery_server_topic = "battery/server2";
47  static const string power_board_node = "power_board";
48  string estimator_type_str = "advanced";
49  double freq = 0.1;
50 
51  pnh.getParam("estimation_method", estimator_type_str);
52  pnh.getParam("frequency", freq);
53  pnh.getParam("battery_update_timeout", battery_update_timeout_);
54 
55  ros::Duration(2).sleep();
56 
57  // Register the estimators
60 
61  // Setup the dynamic_reconfigure callback
62  dynamic_reconfigure::Server<PowerMonitorConfig>::CallbackType config_callback = boost::bind(&PowerMonitor::configCallback, this, _1, _2);
63  config_server_.setCallback(config_callback);
64 
65  // Set the active estimation method
66  if (estimator_types_.size() == 0)
67  {
68  ROS_FATAL("No power state estimators defined. Shutting down");
69  exit(1);
70  }
71  map<string, PowerStateEstimator::Type>::const_iterator i = estimator_types_.find(estimator_type_str);
72  if (i == estimator_types_.end())
73  {
74  // Requested estimator is unknown. Default to first estimator
75  string first_estimator_type_str = estimator_types_.begin()->first;
76  ROS_ERROR("Unknown power state estimator type: %s. Defaulting to %s", estimator_type_str.c_str(), first_estimator_type_str.c_str());
77  setActiveEstimator(estimator_types_.begin()->second);
78  }
79  else
80  setActiveEstimator(i->second);
81 
82  power_state_pub_ = node.advertise<pr2_msgs::PowerState>("power_state", 5, true);
84  battery_server_sub_ = node.subscribe(battery_server_topic, 10, &PowerMonitor::batteryServerUpdate, this);
85  power_node_sub_ = node.subscribe(power_board_node + "/state", 10, &PowerMonitor::powerNodeUpdate, this);
86 }
87 
89 {
92 }
93 
94 void PowerMonitor::configCallback(PowerMonitorConfig& config, uint32_t level)
95 {
96  setActiveEstimator((PowerStateEstimator::Type) config.power_state_estimator_);
97 }
98 
100 {
101  map<PowerStateEstimator::Type, boost::shared_ptr<PowerStateEstimator> >::const_iterator i = estimators_.find(estimator_type);
102  if (i == estimators_.end())
103  return false;
104  if (active_estimator_ == i->second)
105  return true;
106 
108  ROS_INFO("Power state estimator set to %s", i->second->getMethodName().c_str());
109  else
110  ROS_INFO("Power state estimator changed from %s to %s", active_estimator_->getMethodName().c_str(), i->second->getMethodName().c_str());
111 
112  active_estimator_ = i->second;
113 
114  return true;
115 }
116 
118 {
119  boost::mutex::scoped_lock lock(update_mutex_);
120 
121  ROS_DEBUG("Received battery message: voltage=%.2f", battery_server->battery[0].battery_register[0x9] / 1000.0f);
122 
123  battery_servers_[battery_server->id] = battery_server;
124 }
125 
127 {
128  boost::mutex::scoped_lock lock(update_mutex_);
129 
130  ROS_DEBUG("Received power board state message: %s", masterStateToString(power_board_state->master_state).c_str());
131 
132  master_state_ = power_board_state->master_state;
133 
134  // Publish the power state immediately if we're shutting down. Want to ensure we record these data points.
135  if (master_state_ == pr2_msgs::PowerBoardState::MASTER_SHUTDOWN)
136  {
137  ROS_WARN("Power board reports imminant shutdown");
139  }
140 }
141 
142 string PowerMonitor::masterStateToString(int8_t master_state) const
143 {
144  switch (master_state)
145  {
146  case pr2_msgs::PowerBoardState::MASTER_NOPOWER: return "No Power";
147  case pr2_msgs::PowerBoardState::MASTER_STANDBY: return "Standby";
148  case pr2_msgs::PowerBoardState::MASTER_ON: return "On";
149  case pr2_msgs::PowerBoardState::MASTER_OFF: return "Off";
150  case pr2_msgs::PowerBoardState::MASTER_SHUTDOWN: return "Shutdown";
151  default: return "Unknown";
152  }
153 }
154 
156 {
157  boost::mutex::scoped_lock lock(update_mutex_);
158 
159  vector<BatteryObservation> batteries;
160  for (map<int, boost::shared_ptr<const pr2_msgs::BatteryServer2> >::iterator i = battery_servers_.begin(); i != battery_servers_.end(); i++)
161  {
162  const pr2_msgs::BatteryServer2* bs = i->second.get();
163 
164  ros::Time stamp = bs->header.stamp;
165 
166  for (unsigned int j = 0; j < bs->battery.size(); j++)
167  {
168  const pr2_msgs::BatteryState2& b = bs->battery[j];
169 
170  bool ac_present = b.power_present;
171  float voltage = b.battery_register[0x9] / 1000.0f;
172  float current = b.battery_register[0xA] / 1000.0f;
173  unsigned int rsc = b.battery_register[0x0D];
174  float rem_cap = b.battery_register[0x0F] / 1000.0f;
175  unsigned int tte_min = b.battery_register[0x12];
176  unsigned int ttf_min = b.battery_register[0x13];
177 
178  ros::Duration tte;
179  if (tte_min > 0)
180  tte = ros::Duration(tte_min * 60, 0);
181  else
182  tte = ros::Duration(-1, 0);
183 
184  ros::Duration ttf;
185  if (ttf_min > 0)
186  ttf = ros::Duration(ttf_min * 60, 0);
187  else
188  ttf = ros::Duration(-1, 0);
189 
190  if (voltage == 0.0)
191  continue;
192 
193  batteries.push_back(BatteryObservation(stamp, ac_present, voltage, current, rsc, rem_cap, tte, ttf));
194 
195  ROS_DEBUG("Battery %d.%d: %6.2f V %6.2f A %6.2f W (soc: %d, cap: %6.2f, tte: %dm, ttf: %dm)", bs->id, j + 1, voltage, current, current * voltage, rsc, rem_cap, tte_min, ttf_min);
196  }
197  }
198 
199  return PowerObservation(ros::Time::now(), master_state_, batteries);
200 }
201 
203 {
204  ros::Time rv;
205  for (map<int, boost::shared_ptr<const pr2_msgs::BatteryServer2> >::const_iterator i = battery_servers_.begin(); i != battery_servers_.end(); i++)
206  {
207  const pr2_msgs::BatteryServer2* bs = i->second.get();
208  if (bs->header.stamp > rv)
209  rv = bs->header.stamp;
210  }
211 
212  return rv;
213 }
214 
216 {
217  // Don't publish power data if we haven't received battery data in a timeout, #4851
219  {
220  ROS_WARN_THROTTLE(60, "Power monitor not publishing estimate, batteries have not recently updated. Check diagnostics.");
221  return;
222  }
223 
225 }
226 
228 {
229  boost::mutex::scoped_lock lock(publish_mutex_);
230 
231  // Extract info from the battery server
233  if (obs.getBatteries().size() == 0)
234  {
235  ROS_DEBUG("Nothing observed");
236  return;
237  }
238 
239  ROS_DEBUG("Power: %6.1f W. Min voltage: %6.2f V", obs.getTotalPower(), obs.getMinVoltage());
240 
241  // Give every estimator the chance to record this observation
242  for (map<PowerStateEstimator::Type, boost::shared_ptr<PowerStateEstimator> >::const_iterator i = estimators_.begin(); i != estimators_.end(); i++)
243  i->second.get()->recordObservation(obs);
244 
245  // Use the active estimator to estimate the time and capacity remaining
247  if (active_estimator_->canEstimate(t))
248  {
249  PowerStateEstimate estimate = active_estimator_->estimate(t);
250  ROS_DEBUG("Remaining: %.0f min (%d%%)", estimate.time_remaining.toSec() / 60, estimate.relative_capacity);
251 
252  // Publish the power state estimate
253  pr2_msgs::PowerState ps;
254  ps.header.stamp = ros::Time::now();
255  ps.AC_present = obs.getAcCount();
256  ps.power_consumption = obs.getTotalPower();
257  ps.prediction_method = active_estimator_->getMethodName();
258  ps.relative_capacity = (int8_t) estimate.relative_capacity;
259  ps.time_remaining = estimate.time_remaining;
261  }
262 }
263 
264 int main(int argc, char** argv)
265 {
266  ros::init(argc, argv, "power_monitor");
267  PowerMonitor monitor;
268  ros::spin();
269  return 0;
270 }
void batteryServerUpdate(const boost::shared_ptr< const pr2_msgs::BatteryServer2 > &battery_server)
#define ROS_FATAL(...)
#define ROS_WARN_THROTTLE(rate,...)
void publish(const boost::shared_ptr< M > &message) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
bool setActiveEstimator(PowerStateEstimator::Type estimator_type)
bool sleep() const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
boost::shared_ptr< PowerStateEstimator > active_estimator_
Definition: power_monitor.h:95
#define ROS_WARN(...)
std::map< PowerStateEstimator::Type, boost::shared_ptr< PowerStateEstimator > > estimators_
Definition: power_monitor.h:93
std::map< int, boost::shared_ptr< const pr2_msgs::BatteryServer2 > > battery_servers_
Definition: power_monitor.h:90
ros::Publisher power_state_pub_
Definition: power_monitor.h:98
ros::Subscriber power_node_sub_
std::string masterStateToString(int8_t master_state) const
void onPublishTimer(const ros::TimerEvent &e)
void addEstimator(PowerStateEstimator *estimator)
#define ROS_INFO(...)
PowerObservation extractObservation()
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
dynamic_reconfigure::Server< power_monitor::PowerMonitorConfig > config_server_
Definition: power_monitor.h:84
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ROSCPP_DECL void spin()
virtual std::string getMethodName() const =0
unsigned int getAcCount() const
Definition: observation.cpp:56
virtual PowerStateEstimator::Type getMethodType() const =0
bool getParam(const std::string &key, std::string &s) const
static Time now()
int main(int argc, char **argv)
const std::vector< BatteryObservation > & getBatteries() const
Definition: observation.cpp:54
void configCallback(power_monitor::PowerMonitorConfig &config, uint32_t level)
#define ROS_ERROR(...)
ros::Time getLastBatteryUpdate() const
std::map< std::string, PowerStateEstimator::Type > estimator_types_
Definition: power_monitor.h:92
ros::Subscriber battery_server_sub_
Definition: power_monitor.h:99
void powerNodeUpdate(const boost::shared_ptr< const pr2_msgs::PowerBoardState > &power_board_state)
#define ROS_DEBUG(...)


power_monitor
Author(s): Tim Field, Curt Meyers
autogenerated on Fri May 14 2021 02:50:05