From 5d734fc7b84a498ac0f610e9472148d785ecf908 Mon Sep 17 00:00:00 2001
From: Alopez <alopez@iri.upc.edu>
Date: Thu, 16 Dec 2021 10:02:08 +0100
Subject: [PATCH] Added angular velocity collision detector

---
 README.md                            | 10 +++-
 cfg/CollisionManager.cfg             | 27 ++++++----
 config/params.yaml                   | 13 +++--
 include/collision_manager_alg_node.h | 30 +++++++++--
 src/collision_manager_alg_node.cpp   | 79 ++++++++++++++++++++--------
 5 files changed, 116 insertions(+), 43 deletions(-)

diff --git a/README.md b/README.md
index 460d086..4f96e4d 100644
--- a/README.md
+++ b/README.md
@@ -26,15 +26,21 @@ It also provides a [default bno055 calibration file](./calibration/bno055.cal).
   - ~**icp** (iri_laser_scan_icp/icp.srv): ICP server.
 
 ### Parameters
+
+##### Generals
 - ~**rate** (Double; default: 10.0; min: 0.1; max: 1000): The main node thread loop rate in Hz. 
 - ~**debug** (Boolean; default: False): Boolean to publish debug information.
 - ~**fixed_frame** (String; default: base_link): Fixed frame id.
 - ~**tf_timeout** (Double; default: 0.2; min: 0.1; max: 2.0): Timeout to find a transform.
 - ~**err_msg_rate** (Double; default: 0.5; min: 0.1; max: 1.0): Rate to publish error messages.
-- ~**collision_transition_counter_en** (Boolean; default: False): Enable the collision counter. 
+
+##### Collision detection
 - ~**collision_timeout** (Double; default: 4.0; min: 1.0; max: 10.0): Timeout to detect an end of collision.
+- ~**collision_acc_transition_counter_en** (Boolean; default: False): Enable the collision counter. 
 - ~**collision_acc_th** (Double; default: 9.8; min: 0.1; max: 160.0): Threshold to detect a collision.
-- ~**collision_counter_limit** (Integer; default: 6; min: 1; max: 30): Number of low acc imu meassures to detect an end of collision.
+- ~**collision_acc_counter_limit** (Integer; default: 6; min: 1; max: 30): Number of low acc imu meassures to detect an end of collision.
+
+##### ICP data
 - ~**front_laser_en** (Boolean; default: True): Enable front laser for ICP.
 - ~**rear_laser_en** (Boolean; default: True): Enable rear laser for ICP.
 - ~**scan_buffer_size** (Integer; default: 3; min: 1; max: 10): Number of laser_scan buffered for the ICP.
diff --git a/cfg/CollisionManager.cfg b/cfg/CollisionManager.cfg
index ce786f9..f9f86ba 100755
--- a/cfg/CollisionManager.cfg
+++ b/cfg/CollisionManager.cfg
@@ -36,6 +36,8 @@ PACKAGE='iri_collision_manager'
 from dynamic_reconfigure.parameter_generator_catkin import *
 
 gen = ParameterGenerator()
+collision_detection = gen.add_group("Collision detection parameters")
+icp = gen.add_group("ICP data parameters")
 
 #       Name     Type       Reconf.level Description             Default Min   Max
 gen.add("rate",                                 double_t,   0,           "Main loop rate (Hz)",                                   10.0,   0.1, 1000.0)
@@ -44,16 +46,21 @@ gen.add("err_msg_rate",                         double_t,   0,           "Rate t
 gen.add("fixed_frame",                          str_t,      0,           "Fixed frame",                                           "map")
 gen.add("base_link_frame",                      str_t,      0,           "Base_link frame",                                       "base_link")
 gen.add("tf_timeout",                           double_t,   0,           "Timeout to find a transform",                           0.2, 0.1, 2.0)
-gen.add("collision_transition_counter_en",      bool_t,     0,           "Enable the collision counter",                          False)
-gen.add("collision_timeout",                    double_t,   0,           "Timeout to detect an end of collision",                 2.0, 1.0, 10.0)
-gen.add("collision_acc_th",                     double_t,   0,           "Threshold to detect a collision",                       9.8,    0.1, 160.0)
-gen.add("collision_counter_limit",              int_t,      0,           "Number of low acc imu meassures to detect an end of collision",    6, 1, 30)
-gen.add("scan_buffer_size",                     int_t,      0,           "Number of laser_scan buffered for the ICP",             3, 1, 10)
-gen.add("scan_diff_t_from_collision",           double_t,   0,           "Time to subtract from collision time stamp to ensure a clean scan",   0.0,    0.0, 0.5)
-gen.add("front_laser_en",                       bool_t,     0,           "Enable front laser for ICP",                            True)
-gen.add("rear_laser_en",                        bool_t,     0,           "Enable rear laser for ICP",                             True)
-gen.add("icp_min_points",                       int_t,      0,           "Minimum ICP points thershold",                          300,    0, 2000)
-gen.add("icp_max_err_by_points",                double_t,   0,           "Maximum ICP average error per point",                   0.1,    0.0, 10.0)
+
+collision_detection.add("collision_timeout",                        double_t,   0,           "Timeout to detect an end of collision",                            2.0, 1.0, 10.0)
+collision_detection.add("collision_acc_transition_counter_en",      bool_t,     0,           "Enable the collision counter for the acc detection",               False)
+collision_detection.add("collision_acc_th",                         double_t,   0,           "Acceleration threshold to detect a collision",                     9.8,    0.1, 160.0)
+collision_detection.add("collision_acc_counter_limit",              int_t,      0,           "Number of low acc imu meassures to detect an end of collision",    6, 1, 30)
+collision_detection.add("collision_ang_vel_transition_counter_en",  bool_t,     0,           "Enable the collision counter",                                     False)
+collision_detection.add("collision_ang_vel_th",                     double_t,   0,           "Angular velocity threshold to detect a collision",                 0.3,    0.1, 1)
+collision_detection.add("collision_ang_vel_counter_limit",          int_t,      0,           "Number of low acc imu meassures to detect an end of collision",    3, 1, 30)
+
+icp.add("scan_buffer_size",                     int_t,      0,           "Number of laser_scan buffered for the ICP",             3, 1, 10)
+icp.add("scan_diff_t_from_collision",           double_t,   0,           "Time to subtract from collision time stamp to ensure a clean scan",   0.0,    0.0, 0.5)
+icp.add("front_laser_en",                       bool_t,     0,           "Enable front laser for ICP",                            True)
+icp.add("rear_laser_en",                        bool_t,     0,           "Enable rear laser for ICP",                             True)
+icp.add("icp_min_points",                       int_t,      0,           "Minimum ICP points thershold",                          300,    0, 2000)
+icp.add("icp_max_err_by_points",                double_t,   0,           "Maximum ICP average error per point",                   0.1,    0.0, 10.0)
 
 
 exit(gen.generate(PACKAGE, "CollisionManagerAlgorithm", "CollisionManager"))
\ No newline at end of file
diff --git a/config/params.yaml b/config/params.yaml
index 1d24aa7..47cf45a 100644
--- a/config/params.yaml
+++ b/config/params.yaml
@@ -4,10 +4,17 @@ fixed_frame: map
 base_link_frame: base_link
 tf_timeout: 0.2
 err_msg_rate: 0.5
-collision_transition_counter_en: True
+
 collision_timeout: 4.0
-collision_acc_th: 2.5
-collision_counter_limit: 12
+collision_acc_transition_counter_en: True
+collision_acc_th: 3.0
+#collision_acc_th: 2.0
+collision_acc_counter_limit: 12
+collision_ang_vel_transition_counter_en: True
+collision_ang_vel_th: 0.4
+#collision_ang_vel_th: 0.2
+collision_ang_vel_counter_limit: 4
+
 front_laser_en: True
 rear_laser_en: True
 scan_buffer_size: 6
diff --git a/include/collision_manager_alg_node.h b/include/collision_manager_alg_node.h
index 52b38f4..1993cbd 100644
--- a/include/collision_manager_alg_node.h
+++ b/include/collision_manager_alg_node.h
@@ -79,6 +79,7 @@ class CollisionManagerAlgNode : public algorithm_base::IriBaseAlgorithm<Collisio
     // ros::Time collision_end_stamp_; ///< Time stamp at the end of collision.
     Eigen::Vector3d max_acc_; ///< The linear accelerations meassured from base_link frame reference at maximum acceleration module.
     int low_acc_count_; ///< Low acceleration meassures counter to detect the end of a collision.
+    int low_ang_vel_count_; ///< Low angular velocities meassures counter to detect the end of a collision.
     std::list<RangesWithStamp> front_ranges_; ///< Front laser ranges buffer.
     std::list<RangesWithStamp> rear_ranges_; ///< Rear laser ranges buffer.
     bool is_front_icp_input_data_ok_; ///<Boolean to know of all the necessary data has been saved on the service request.
@@ -182,7 +183,7 @@ class CollisionManagerAlgNode : public algorithm_base::IriBaseAlgorithm<Collisio
     bool get_base_link_imu_data(Eigen::Vector3d& _global_acc, Eigen::Vector3d& _global_ang_vel);
 
     /**
-     * \brief Function to check if is a collision transition.
+     * \brief Function to check if is an acceleration collision transition.
      * 
      * It checks if the current acceleration meassured is behind or above the threshold  
      * (depending on _start param) updates the counter and checks if the limit has been reached. 
@@ -193,18 +194,35 @@ class CollisionManagerAlgNode : public algorithm_base::IriBaseAlgorithm<Collisio
      * 
      * \return True if the conditions has been met.
      */
-    bool check_collision_transition(double _acc_norm_2d, bool _start);
+    bool check_acc_collision_transition(double _acc_norm_2d, bool _start);
+
+    /**
+     * \brief Function to check if is an acceleration collision transition.
+     * 
+     * It checks if the current acceleration meassured is behind or above the threshold  
+     * (depending on _start param) updates the counter and checks if the limit has been reached. 
+     * 
+     * \param _ang_vel The current angular velocity.
+     * 
+     * \param _start If it must check the star transition.
+     * 
+     * \return True if the conditions has been met.
+     */
+    bool check_ang_vel_collision_transition(double _ang_vel, bool _start);
 
     /**
      * \brief Function to check the end of a collision.
      * 
-     * It calls check_collision_transition with _start to false.
+     * It calls check_acc_collision_transition and check_ang_vel_collision_transition
+     * with _start to false.
      * 
      * \param _acc_norm_2d The current global linear acceleration norm.
      * 
+     * \param _ang_vel The current angular velocity.
+     * 
      * \return True if the condition has been met.
      */
-    bool check_end_of_collision(double _acc_norm_2d);
+    bool check_end_of_collision(double _acc_norm_2d, double _ang_vel);
 
     /**
      * \brief Function to check the end of a collision.
@@ -213,9 +231,11 @@ class CollisionManagerAlgNode : public algorithm_base::IriBaseAlgorithm<Collisio
      * 
      * \param _acc_norm_2d The current global linear acceleration norm.
      * 
+     * \param _ang_vel The current angular velocity.
+     * 
      * \return True if the condition has been met.
      */
-    bool check_start_of_collision(double _acc_norm_2d);
+    bool check_start_of_collision(double _acc_norm_2d, double _ang_vel);
 
     /**
      * \brief Function to find the last scan before a collision.
diff --git a/src/collision_manager_alg_node.cpp b/src/collision_manager_alg_node.cpp
index 536e18b..1d163d6 100644
--- a/src/collision_manager_alg_node.cpp
+++ b/src/collision_manager_alg_node.cpp
@@ -31,6 +31,7 @@ CollisionManagerAlgNode::CollisionManagerAlgNode(void) :
   this->tf_base_link_imu_loaded_ = false;
   this->in_collision_ = false;
   this->low_acc_count_ = 0;
+  this->low_ang_vel_count_ = 0;
   this->is_front_icp_input_data_ok_ = false;
   this->is_rear_icp_input_data_ok_ = false;
   this->tf_base_link_front_laser_loaded_ = false;
@@ -94,18 +95,18 @@ void CollisionManagerAlgNode::mainNodeThread(void)
   this->imu_mutex_enter();
   this->rear_laser_scan_mutex_enter();
   this->front_laser_scan_mutex_enter();
-  Eigen::Vector3d global_acc, global_ang_vel, rear_blink_pose, front_blink_pose, new_laser_pose;
+  Eigen::Vector3d blink_acc, blink_ang_vel, rear_blink_pose, front_blink_pose, new_laser_pose;
   Eigen::Matrix3d rear_cov, front_cov, covariances;
 
   if (this->new_imu_input_)
   {
-    if (get_base_link_imu_data(global_acc, global_ang_vel))//Transform data to fixed frame coordinates
+    if (get_base_link_imu_data(blink_acc, blink_ang_vel))//Transform data to fixed frame coordinates
     {
-      double acc_norm_2d = std::sqrt(std::pow(global_acc(0),2) + std::pow(global_acc(1),2));
+      double acc_norm_2d = std::sqrt(std::pow(blink_acc(0),2) + std::pow(blink_acc(1),2));
       if (this->in_collision_)
       {
         double max_acc_norm_2d = std::sqrt(std::pow(this->max_acc_(0),2) + std::pow(this->max_acc_(1),2));
-        if (check_end_of_collision(acc_norm_2d))
+        if (check_end_of_collision(acc_norm_2d, std::fabs(blink_ang_vel(2))))
         {
           double collision_angle = std::atan2(this->max_acc_(1), this->max_acc_(0));
           while (collision_angle >= M_PI)
@@ -116,8 +117,12 @@ void CollisionManagerAlgNode::mainNodeThread(void)
           ROS_INFO_STREAM("CollisionManagerAlgNode::mainNodeThread -> collision detected: acc = " << max_acc_norm_2d << "; angle = " << collision_angle);
 
           //update rot_angle_estimated
-          this->front_icp_srv_.request.rot_angle_estimation += global_ang_vel(2)*(this->imu_stamp_ - this->last_imu_t_).toSec();
+          this->front_icp_srv_.request.rot_angle_estimation += blink_ang_vel(2)*(this->imu_stamp_ - this->last_imu_t_).toSec();
+
+          //rotate angle when fixed tf
+
           this->rear_icp_srv_.request.rot_angle_estimation = this->front_icp_srv_.request.rot_angle_estimation;
+
           ROS_INFO_STREAM("CollisionManagerAlgNode::mainNodeThread -> collision detected: angle estimated = " << this->front_icp_srv_.request.rot_angle_estimation);
 
           // Call the service
@@ -206,6 +211,7 @@ void CollisionManagerAlgNode::mainNodeThread(void)
           //restart variables
           this->in_collision_ = false;
           this->low_acc_count_ = 0;
+          this->low_ang_vel_count_ = 0;
           this->is_front_icp_input_data_ok_ = false;
           this->is_rear_icp_input_data_ok_ = false;
         }
@@ -213,10 +219,10 @@ void CollisionManagerAlgNode::mainNodeThread(void)
         {
           //Update max_acc
           if (acc_norm_2d > max_acc_norm_2d)
-            this->max_acc_ = global_acc;
+            this->max_acc_ = blink_acc;
 
           //Update angle rotated
-          this->front_icp_srv_.request.rot_angle_estimation += global_ang_vel(2)*(this->imu_stamp_ - this->last_imu_t_).toSec();
+          this->front_icp_srv_.request.rot_angle_estimation += blink_ang_vel(2)*(this->imu_stamp_ - this->last_imu_t_).toSec();
           this->last_imu_t_ = this->imu_stamp_;
 
           //Check collision timeout
@@ -225,10 +231,11 @@ void CollisionManagerAlgNode::mainNodeThread(void)
             ROS_WARN_STREAM("CollisionManagerAlgNode::mainNodeThread -> No end of collision detected after " << this->config_.collision_timeout << " seconds.");
             this->in_collision_ = false;
             this->low_acc_count_ = 0;
+            this->low_ang_vel_count_ = 0;
           }
         }
       }
-      else if (check_start_of_collision(acc_norm_2d))
+      else if (check_start_of_collision(acc_norm_2d, std::fabs(blink_ang_vel(2))))
       {
         ROS_INFO_STREAM("CollisionManagerAlgNode::mainNodeThread -> collision start detected.");
         this->collision_start_stamp_ = this->imu_stamp_;
@@ -244,7 +251,7 @@ void CollisionManagerAlgNode::mainNodeThread(void)
 
         //init variables
         this->in_collision_ = true;
-        this->max_acc_ = global_acc;
+        this->max_acc_ = blink_acc;
         this->last_imu_t_ = this->collision_start_stamp_;
         this->front_icp_srv_.request.rot_angle_estimation = 0.0;
         this->rear_icp_srv_.request.rot_angle_estimation = 0.0;
@@ -383,30 +390,56 @@ bool CollisionManagerAlgNode::get_base_link_imu_data(Eigen::Vector3d& _global_ac
   return true;
 }
 
-bool CollisionManagerAlgNode::check_collision_transition(double _acc_norm_2d, bool _start)
+bool CollisionManagerAlgNode::check_acc_collision_transition(double _acc_norm_2d, bool _start)
 {
-  if (this->config_.collision_transition_counter_en)
+  if (!this->config_.collision_acc_transition_counter_en)
+    return true;
+  if ((_start && (_acc_norm_2d > this->config_.collision_acc_th)) || (!_start && (_acc_norm_2d < this->config_.collision_acc_th)))
+    this->low_acc_count_++;
+  else
   {
-    if ((_start && (_acc_norm_2d > this->config_.collision_acc_th)) || (!_start && (_acc_norm_2d < this->config_.collision_acc_th)))
-      this->low_acc_count_++;
-    else
-    {
-      this->low_acc_count_ = 0;
-      return false;
-    }
+    this->low_acc_count_ = 0;
+    return false;
   }
   return ((_start && (_acc_norm_2d > this->config_.collision_acc_th)) || (!_start && (_acc_norm_2d < this->config_.collision_acc_th)))  
-         && (_start || (!_start && (!this->config_.collision_transition_counter_en || (this->low_acc_count_ >= this->config_.collision_counter_limit))));
+         && (_start || (!_start && (!this->config_.collision_acc_transition_counter_en || (this->low_acc_count_ >= this->config_.collision_acc_counter_limit))));
+}
+
+bool CollisionManagerAlgNode::check_ang_vel_collision_transition(double _ang_vel, bool _start)
+{
+  if (!this->config_.collision_ang_vel_transition_counter_en)
+    return true;
+  if ((_start && (_ang_vel > this->config_.collision_ang_vel_th)) || (!_start && (_ang_vel < this->config_.collision_ang_vel_th)))
+    this->low_ang_vel_count_++;
+  else
+  {
+    this->low_ang_vel_count_ = 0;
+    return false;
+  }
+  return ((_start && (_ang_vel > this->config_.collision_ang_vel_th)) || (!_start && (_ang_vel < this->config_.collision_ang_vel_th)))  
+         && (_start || (!_start && (!this->config_.collision_ang_vel_transition_counter_en || (this->low_ang_vel_count_ >= this->config_.collision_ang_vel_counter_limit))));
 }
 
-bool CollisionManagerAlgNode::check_end_of_collision(double _acc_norm_2d)
+bool CollisionManagerAlgNode::check_end_of_collision(double _acc_norm_2d, double _ang_vel)
 {
-  return check_collision_transition(_acc_norm_2d, false);
+  bool acc_true = check_acc_collision_transition(_acc_norm_2d, false);
+  bool ang_vel_true = check_ang_vel_collision_transition(_ang_vel, false);
+  if (acc_true)
+    ROS_INFO_STREAM("CollisionManagerAlgNode::check_end_of_collision -> (END) Acc true. acc: " << _acc_norm_2d << "; vel: " << _ang_vel);
+  if (ang_vel_true)
+    ROS_INFO_STREAM("CollisionManagerAlgNode::check_end_of_collision -> (END) Angular vel true. acc: " << _acc_norm_2d << "; vel: " << _ang_vel);
+  return acc_true && ang_vel_true;
 }
 
-bool CollisionManagerAlgNode::check_start_of_collision(double _acc_norm_2d)
+bool CollisionManagerAlgNode::check_start_of_collision(double _acc_norm_2d, double _ang_vel)
 {
-  return check_collision_transition(_acc_norm_2d, true);
+  bool acc_true = check_acc_collision_transition(_acc_norm_2d, true);
+  bool ang_vel_true = check_ang_vel_collision_transition(_ang_vel, true);
+  if (acc_true)
+    ROS_INFO_STREAM("CollisionManagerAlgNode::check_start_of_collision -> (START) Acc true. acc: " << _acc_norm_2d << "; vel: " << _ang_vel);
+  if (ang_vel_true)
+    ROS_INFO_STREAM("CollisionManagerAlgNode::check_start_of_collision -> (START) Angular vel true. acc: " << _acc_norm_2d << "; vel: " << _ang_vel);
+  return acc_true || ang_vel_true;
 }
 
 bool CollisionManagerAlgNode::set_ref_ranges(ros::Time _stamp, bool _front)
-- 
GitLab