From 4e14772df54d241e5cdfb34827502d69b5e43b29 Mon Sep 17 00:00:00 2001
From: Paul Beuchat <beuchatp@control.ee.ethz.ch>
Date: Thu, 6 Dec 2018 09:54:30 +0100
Subject: [PATCH] Continued developing the battery monitor

---
 .../d_fall_pps/include/nodes/BatteryMonitor.h |  26 ++-
 .../src/d_fall_pps/param/BatteryMonitor.yaml  |  16 +-
 .../d_fall_pps/src/nodes/BatteryMonitor.cpp   | 193 +++++++++++-------
 3 files changed, 144 insertions(+), 91 deletions(-)

diff --git a/pps_ws/src/d_fall_pps/include/nodes/BatteryMonitor.h b/pps_ws/src/d_fall_pps/include/nodes/BatteryMonitor.h
index 7ee4abd0..7f4a1efc 100644
--- a/pps_ws/src/d_fall_pps/include/nodes/BatteryMonitor.h
+++ b/pps_ws/src/d_fall_pps/include/nodes/BatteryMonitor.h
@@ -66,7 +66,7 @@
 //    DDDD   EEEEE  F      III  N   N  EEEEE  SSSS
 //    ----------------------------------------------------------------------------------
 
-// Battery states
+// Battery levels
 #define BATTERY_LEVEL_000            0
 #define BATTERY_LEVEL_010            1
 #define BATTERY_LEVEL_020            2
@@ -80,6 +80,10 @@
 #define BATTERY_LEVEL_100           10
 #define BATTERY_LEVEL_UNAVAILABLE   -1
 
+// Battery states
+#define BATTERY_STATE_NORMAL         0
+#define BATTERY_STATE_LOW            1
+
 // The types, i.e., agent or coordinator
 #define TYPE_INVALID      -1
 #define TYPE_COORDINATOR   1
@@ -109,9 +113,6 @@
 //      V    A   A  R   R  III  A   A  BBBB   LLLLL  EEEEE  SSSS
 //    ----------------------------------------------------------------------------------
 
-// The level of the battery
-int m_battery_level;
-
 // The status of the crazyradio as received via messages
 //int m_crazyradio_status;
 
@@ -121,20 +122,27 @@ int m_agent_operating_state;
 // Publisher for the filtered battery voltage
 ros::Publisher filteredBatteryVoltagePublisher;
 
-// Publisher for the battery state
+// Publisher for the battery level
 ros::Publisher batteryLevelPublisher;
 
+// Publisher for changes in the battery state
+ros::Publisher batteryStateChangedPublisher;
+
 
 
 // VARIABLES THAT ARE LOADED FROM THE YAML FILE
 
 // Battery thresholds while in the "motors off" state, in [Volts]
-float m_battery_threshold_lower_while_standby = 3.30f;
-float m_battery_threshold_upper_while_standby = 4.20f;
+float yaml_battery_voltage_threshold_lower_while_standby = 3.30f;
+float yaml_battery_voltage_threshold_upper_while_standby = 4.20f;
 
 // Battery thresholds while in the "flying" state, in [Volts]
-float m_battery_threshold_lower_while_flying = 2.60f;
-float m_battery_threshold_upper_while_flying = 3.70f;
+float yaml_battery_voltage_threshold_lower_while_flying = 2.60f;
+float yaml_battery_voltage_threshold_upper_while_flying = 3.70f;
+
+// Delay before changing the state of the battery, in [number of measurements]
+// > Note that the delay in seconds therefore depends on the polling period
+int yaml_battery_delay_threshold_to_change_state = 5;
 
 
 
diff --git a/pps_ws/src/d_fall_pps/param/BatteryMonitor.yaml b/pps_ws/src/d_fall_pps/param/BatteryMonitor.yaml
index 86b384ec..3aeb5976 100755
--- a/pps_ws/src/d_fall_pps/param/BatteryMonitor.yaml
+++ b/pps_ws/src/d_fall_pps/param/BatteryMonitor.yaml
@@ -1,10 +1,14 @@
+# Frequency of requesting the battery voltage, in [milliseconds]
+battery_polling_period: 200
+
 # Battery thresholds while in the "motors off" state, in [Volts]
-battery_threshold_lower_while_standby: 3.30
-battery_threshold_upper_while_standby: 4.20
+battery_voltage_threshold_lower_while_standby: 3.30
+battery_voltage_threshold_upper_while_standby: 4.20
 
 # Battery thresholds while in the "flying" state, in [Volts]
-battery_threshold_lower_while_flying: 2.60
-battery_threshold_upper_while_flying: 3.70
+battery_voltage_threshold_lower_while_flying: 2.60
+battery_voltage_threshold_upper_while_flying: 3.70
 
-# Frequency of requesting the battery voltage, in [milliseconds]
-battery_polling_period: 200
\ No newline at end of file
+# Delay before changing the state of the battery, in [number of measurements]
+# > Note that the delay in seconds therefore depends on the polling period
+battery_delay_threshold_to_change_state: 5
\ No newline at end of file
diff --git a/pps_ws/src/d_fall_pps/src/nodes/BatteryMonitor.cpp b/pps_ws/src/d_fall_pps/src/nodes/BatteryMonitor.cpp
index b3bb4d0c..53384c11 100644
--- a/pps_ws/src/d_fall_pps/src/nodes/BatteryMonitor.cpp
+++ b/pps_ws/src/d_fall_pps/src/nodes/BatteryMonitor.cpp
@@ -64,22 +64,13 @@ using namespace d_fall_pps;
 
 
 
+void agentOperatingStateCallback(const std_msgs::Int32& msg)
+{
+	// Extract the data
+	m_agent_operating_state = msg.data;
+}
 
 
-//    ----------------------------------------------------------------------------------
-//    L       OOO     A    DDDD
-//    L      O   O   A A   D   D
-//    L      O   O  A   A  D   D
-//    L      O   O  AAAAA  D   D
-//    LLLLL   OOO   A   A  DDDD
-//
-//    PPPP     A    RRRR     A    M   M  EEEEE  TTTTT  EEEEE  RRRR    SSSS
-//    P   P   A A   R   R   A A   MM MM  E        T    E      R   R  S
-//    PPPP   A   A  RRRR   A   A  M M M  EEE      T    EEE    RRRR    SSS
-//    P      AAAAA  R  R   AAAAA  M   M  E        T    E      R  R       S
-//    P      A   A  R   R  A   A  M   M  EEEEE    T    EEEEE  R   R  SSSS
-//    ----------------------------------------------------------------------------------
-
 
 
 
@@ -100,6 +91,8 @@ void crazyRadioStatusCallback(const std_msgs::Int32& msg)
 
 
 
+
+
 void newBatteryVoltageCallback(const std_msgs::Float32& msg)
 {
 	// Extract the data
@@ -115,48 +108,75 @@ void newBatteryVoltageCallback(const std_msgs::Float32& msg)
 	// Convert the battery percentage to a level
 	int filtered_battery_voltage_as_level = convertPercentageToLevel(filtered_battery_voltage_as_percentage);
 
-	// Then publish that the battery level is unavailable
+	// Publish that the battery voltage
+	std_msgs::Float32 filtered_battery_voltage_msg;
+	filtered_battery_voltage_msg.data = filtered_battery_voltage;
+	filteredBatteryVoltagePublisher.publish(filtered_battery_voltage_msg);
+
+	// Publish that the battery level
 	std_msgs::Int32 battery_level_msg;
-	battery_level_msg.data = BATTERY_LEVEL_UNAVAILABLE;
+	battery_level_msg.data = filtered_battery_voltage_as_level;
 	batteryLevelPublisher.publish(battery_level_msg);
 
-	// ROS_INFO_STREAM("filtered data: " << filtered_battery_voltage);
-	if(
-		(flying_state != STATE_MOTORS_OFF && (filtered_battery_voltage < m_battery_threshold_while_flying))
-		||
-		(flying_state == STATE_MOTORS_OFF && (filtered_battery_voltage < m_battery_threshold_while_motors_off))
-	)
-	{
-		if(getBatteryState() != BATTERY_STATE_LOW)
-		{
-		setBatteryStateTo(BATTERY_STATE_LOW);
-		ROS_INFO("[PPS CLIENT] low level battery triggered");
-		}
+	// Update the battery state using the level
+	// > Note that the function called sends a message
+	//   only if the battery state changes
+	updateBatteryStateBasedOnLevel(filtered_battery_voltage_as_level);
+}
+
+
+
+
+
+// > For converting a voltage to a percentage, depending on the current "my_flying_state" value
+float fromVoltageToPercent(float voltage , float operating_state )
+{
+	// INITIALISE THE LOCAL VARIABLE FOR THE VOLTAGE WHEN FULL/EMPTY
+	float voltage_when_full;
+	float voltage_when_empty;
 
+	// COMPUTE THE PERCENTAGE DIFFERENTLY DEPENDING ON
+	// THE CURRENT FLYING STATE
+	if (operating_state == STATE_MOTORS_OFF)
+	{
+		// Voltage limits for a "standby" type of state
+		voltage_when_empty = yaml_battery_voltage_threshold_lower_while_standby;
+		voltage_when_full  = yaml_battery_voltage_threshold_upper_while_standby;
 	}
 	else
 	{
-	// TO AVOID BEING ABLE TO IMMEDIATELY TAKE-OFF AFTER A
-	// "BATTERY LOW" EVENT IS TRIGGERED, WE DO NOT SET THE
-	// BATTERY STATE BACK TO NORMAL
-	// if(getBatteryState() != BATTERY_STATE_NORMAL)
-	// {
-	//     setBatteryStateTo(BATTERY_STATE_NORMAL);
-	// }
+		// Voltage limits for a "flying" type of state
+		voltage_when_empty = yaml_battery_voltage_threshold_lower_while_flying;
+		voltage_when_full  = yaml_battery_voltage_threshold_upper_while_flying;
 	}
-}
 
+	// COMPUTE THE PERCENTAGE
+	float percentage = 100.0f * (voltage-voltage_when_empty)/(voltage_when_full-voltage_when_empty);
 
+	// CLIP THE PERCENTAGE TO BE BETWEEN [0,100]
+	// > This should not happen to often
+	if(percentage > 100.0f)
+	{
+		percentage = 100.0f;
+	}
+	if(percentage < 0.0f)
+	{
+		percentage = 0.0f;
+	}
 
-void agentOperatingStateCallback(const std_msgs::Int32& msg)
-{
-	// Extract the data
-	m_agent_operating_state = msg.data;
+	// RETURN THE PERCENTAGE
+	return percentage;
 }
 
 
+
+
+
 int convertPercentageToLevel(float percentage)
 {
+	// Initialise the battery level
+	static int battery_level = BATTERY_LEVEL_UNAVAILABLE;
+
 	// Iterate through the levels
 	for (i_level=0;i_level<10;i++)
 	{
@@ -164,7 +184,7 @@ int convertPercentageToLevel(float percentage)
 		float threshold = float(i_level) * 10.0f;
 		// Add a buffer to the threshold to prevent
 		// high frequency changes to the level
-		if (m_battery_level==i_level)
+		if (battery_level==i_level)
 		{
 			threshold += 2.0f;
 		}
@@ -178,51 +198,66 @@ int convertPercentageToLevel(float percentage)
 	// returning, then the percentage is at or above
 	// the maximum level
 	return BATTERY_LEVEL_100;
-
 }
 
 
-// > For converting a voltage to a percentage, depending on the current "my_flying_state" value
-float fromVoltageToPercent(float voltage , float operating_state )
+
+
+
+void updateBatteryStateBasedOnLevel(level)
 {
-	// INITIALISE THE LOCAL VARIABLE FOR THE VOLTAGE WHEN FULL/EMPTY
-	float voltage_when_full;
-	float voltage_when_empty;
+	// Initialise the battery state
+	static int battery_state = BATTERY_STATE_NORMAL;
 
-	// COMPUTE THE PERCENTAGE DIFFERENTLY DEPENDING ON
-	// THE CURRENT FLYING STATE
-	if (operating_state == STATE_MOTORS_OFF)
+	// Initialise a counter for delaying a change of state
+	static int num_since_change = 0;
+
+	if (level == 0)
 	{
-		// Voltage limits for a "standby" type of state
-		voltage_when_empty = m_battery_threshold_lower_while_standby;
-		voltage_when_full  = m_battery_threshold_upper_while_standby;
+		if (battery_state == BATTERY_STATE_NORMAL)
+		{
+			num_since_change++;
+		}
+		else
+		{
+			num_since_change = 0;
+		}
 	}
-	else
+	else if (level >= 1)
 	{
-		// Voltage limits for a "flying" type of state
-		voltage_when_empty = m_battery_threshold_lower_while_flying;
-		voltage_when_full  = m_battery_threshold_upper_while_flying;
+		if (battery_state == BATTERY_STATE_LOW)
+		{
+			num_since_change++;
+		}
+		else
+		{
+			num_since_change = 0;
+		}
 	}
 
-	// COMPUTE THE PERCENTAGE
-	float percentage = 100.0f * (voltage-voltage_when_empty)/(voltage_when_full-voltage_when_empty);
-
-	// CLIP THE PERCENTAGE TO BE BETWEEN [0,100]
-	// > This should not happen to often
-	if(percentage > 100.0f)
-	{
-		percentage = 100.0f;
-	}
-	if(percentage < 0.0f)
+	// Check if the "delay-to-change" threshold is reached
+	if (num_since_change >= yaml_battery_delay_threshold_to_change_state)
 	{
-		percentage = 0.0f;
+		if (battery_state == BATTERY_STATE_NORMAL)
+		{
+			battery_state = BATTERY_STATE_LOW;
+		}
+		else
+		{
+			battery_state = BATTERY_STATE_NORMAL;
+		}
+		// Publish the change
+		std_msgs::Int32 battery_state_msg;
+		battery_state_msg.data = battery_state;
+		batteryStateChangedPublisher.publish(battery_state_msg);
 	}
-
-	// RETURN THE PERCENTAGE
-	return percentage;
 }
 
 
+
+
+
+
 //    ----------------------------------------------------------------------------------
 //    M   M    A    III  N   N
 //    MM MM   A A    I   NN  N
@@ -251,9 +286,18 @@ int main(int argc, char* argv[])
 	// Advertise the service for loading Yaml Files
 	ros::ServiceServer service = nodeHandle.advertiseService("LoadYamlFiles", loadYamlFiles);
 
-	// Publish the battery level
-	batteryLevelPublisher = nodeHandle.advertise<std_msgs::Int32>("BatteryLevel",1);
+	// PUBLISHERS
+	// Publisher for the filtered battery voltage
+	ros::Publisher filteredBatteryVoltagePublisher = nodeHandle.advertise<std_msgs::Float32>("FilteredVoltage",1);
+
+	// Publisher for the battery level
+	batteryLevelPublisher = nodeHandle.advertise<std_msgs::Int32>("Level",1);
+
+	// Publisher for changes in the battery state
+	ros::Publisher batteryStateChangedPublisher = nodeHandle.advertise<std_msgs::Int32>("ChangedStateTo",1);
 
+
+	// SUBSCRIBERS
 	// Subscribe to the voltage of the battery
 	ros::Subscriber newBatteryVoltageSubscriber = nodeHandle.subscribe("CrazyRadio/CFBattery", 1, newBatteryVoltageCallback);
 
@@ -263,9 +307,6 @@ int main(int argc, char* argv[])
 	// Subscribe to the flying state of the agent
 	ros::Subscriber agentOperatingStateSubscriber = nodeHandle.subscribe("PPS_Client/flyingState", 1, agentOperatingStateCallback);
 
-	// Initialise the battery level
-	m_battery_level = BATTERY_LEVEL_UNAVAILABLE;
-
 	// Initialise the operating state
 	m_agent_operating_state = AGENT_OPERATING_STATE_MOTORS_OFF;
 
-- 
GitLab