power_state_phidget.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00004 #
00005 # Licensed under the Apache License, Version 2.0 (the "License");
00006 # you may not use this file except in compliance with the License.
00007 # You may obtain a copy of the License at
00008 #
00009 #   http://www.apache.org/licenses/LICENSE-2.0
00010 #
00011 # Unless required by applicable law or agreed to in writing, software
00012 # distributed under the License is distributed on an "AS IS" BASIS,
00013 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 # See the License for the specific language governing permissions and
00015 # limitations under the License.
00016 
00017 
00018 import numpy as np
00019 import rospy
00020 from cob_msgs.msg import PowerState
00021 from cob_phidgets.msg import AnalogSensor
00022 
00023 
00024 class PowerStatePhidget():
00025     PHIDGET_MAX_VALUE = 999
00026     PHIDGET_MIN_VALUE = 0
00027     PERIOD_RECORD_SIZE = 6
00028     VOLTAGE_COLLECTION_TIME = 6.0  # sec
00029 
00030     def __init__(self):
00031         self.voltage = None
00032         self.current = None
00033         self.last_update = rospy.Time(0)
00034         self.charging = False
00035         try:
00036             self.voltage_divider_factor = rospy.get_param("~voltage_divider_factor")
00037         except KeyError:
00038             raise KeyError("Parameter \"~voltage_divider_factor\" not found on parameter server.")
00039         self.voltage_full = rospy.get_param("~voltage_full", 52.0)
00040         self.voltage_empty = rospy.get_param("~voltage_empty", 38.0)
00041         self.current_max = rospy.get_param("~current_max", 30.0)
00042         self.current_min = rospy.get_param("~current_min", -30.0)
00043 
00044         self.pub_power_state = rospy.Publisher('power_state', PowerState, queue_size=1)
00045         self.sub_analog_sensors = rospy.Subscriber("analog_sensors", AnalogSensor, self.phidget_cb)
00046 
00047         self.pr_next = 0
00048         self.period_record = []
00049         self.cb_avg_time = 0.1
00050         self.voltage_bag_maxlen = 100
00051         self.voltage_bag = []
00052 
00053     def append_voltage_bag(self, num):
00054         while len(self.voltage_bag) >= self.voltage_bag_maxlen:
00055             self.voltage_bag.pop(0)
00056         self.voltage_bag.append(num)
00057 
00058     def calculate_voltage(self):
00059         if len(self.voltage_bag) > 0:
00060             self.voltage = np.mean(self.voltage_bag)
00061 
00062     def phidget_cb(self, msg):
00063         # Estimate commands frequency; we do continuously as it can be very different depending on the
00064         # publisher type, and we don't want to impose extra constraints to keep this package flexible
00065         if len(self.period_record) < self.PERIOD_RECORD_SIZE:
00066             self.period_record.append((rospy.Time.now() - self.last_update).to_sec())
00067         else:
00068             self.period_record[self.pr_next] = (rospy.Time.now() - self.last_update).to_sec()
00069 
00070         self.pr_next += 1
00071         self.pr_next %= len(self.period_record)
00072         self.last_update = rospy.Time.now()
00073 
00074         if len(self.period_record) <= self.PERIOD_RECORD_SIZE / 2:
00075             # wait until we have some values; make a reasonable assumption (10 Hz) meanwhile
00076             self.cb_avg_time = 0.1
00077         else:
00078             # enough; recalculate with the latest input
00079             self.cb_avg_time = np.median(self.period_record)
00080 
00081         # now set the max voltage bag size
00082         self.voltage_bag_maxlen = int(self.VOLTAGE_COLLECTION_TIME / self.cb_avg_time)
00083 
00084         voltage_raw = None
00085         current_raw = None
00086 
00087         for i in range(0, len(msg.uri)):
00088             if msg.uri[i] == "voltage":
00089                 voltage_raw = msg.value[i]
00090             if msg.uri[i] == "current":
00091                 current_raw = msg.value[i]
00092 
00093         if voltage_raw != None:
00094             # Calculation of real voltage
00095             voltage = self.voltage_divider_factor * voltage_raw / self.PHIDGET_MAX_VALUE
00096             voltage = round(voltage, 3)
00097             self.append_voltage_bag(voltage)
00098 
00099         if current_raw != None:
00100             # Calculation of real current
00101             self.current = self.current_min + (self.current_max - self.current_min) * (current_raw -
00102                                                                                        self.PHIDGET_MIN_VALUE) / (self.PHIDGET_MAX_VALUE - self.PHIDGET_MIN_VALUE)
00103             self.current = round(self.current, 3)
00104 
00105             if self.current > 0:
00106                 self.charging = True
00107             else:
00108                 self.charging = False
00109 
00110     def calculate_power_consumption(self):
00111         if not self.charging and self.voltage != None and self.current != None:
00112             return round(self.voltage * abs(self.current), 3)
00113         else:
00114             return 0.0
00115 
00116     def calculate_relative_remaining_capacity(self):
00117         percentage = None
00118         if self.voltage != None:
00119             percentage = round((self.voltage - self.voltage_empty) * 100 / (self.voltage_full - self.voltage_empty), 3)
00120             percentage = min(percentage, 100)
00121             percentage = max(percentage, 0)
00122             return percentage
00123         else:
00124             return 0.0
00125 
00126     def publish(self):
00127         self.calculate_voltage()
00128         if self.voltage != None and self.current != None and (rospy.Time.now() - self.last_update) < rospy.Duration(1):
00129             ps = PowerState()
00130             ps.header.stamp = self.last_update
00131             ps.voltage = self.voltage
00132             ps.current = self.current
00133             ps.power_consumption = self.calculate_power_consumption()
00134             ps.relative_remaining_capacity = self.calculate_relative_remaining_capacity()
00135             ps.charging = self.charging
00136             self.pub_power_state.publish(ps)
00137 
00138 if __name__ == "__main__":
00139     rospy.init_node("power_state_phidget")
00140     try:
00141         psp = PowerStatePhidget()
00142     except KeyError as e:
00143         rospy.logerr("Shutting down: {}".format(e.message))
00144         exit(1)
00145 
00146     rospy.loginfo("power state phidget running")
00147     rate = rospy.Rate(10)
00148     while not rospy.is_shutdown():
00149         psp.publish()
00150         rate.sleep()


cob_phidget_power_state
Author(s): Benjamin Maidel
autogenerated on Sat Jun 8 2019 21:02:17