From b61ea55314cf63de777f055a72699504d867b5b4 Mon Sep 17 00:00:00 2001
From: guanxuany <guanxuany@student.unimelb.edu.au>
Date: Tue, 23 Jul 2024 15:53:44 +1000
Subject: [PATCH] odometry_new update

---
 .../asclinic_pkg/src/ascr/odometry _new.cpp   | 184 ++++++++++++++++--
 1 file changed, 163 insertions(+), 21 deletions(-)

diff --git a/catkin_ws/src/asclinic_pkg/src/ascr/odometry _new.cpp b/catkin_ws/src/asclinic_pkg/src/ascr/odometry _new.cpp
index e7069045..d0ec5693 100644
--- a/catkin_ws/src/asclinic_pkg/src/ascr/odometry _new.cpp	
+++ b/catkin_ws/src/asclinic_pkg/src/ascr/odometry _new.cpp	
@@ -14,12 +14,32 @@ double time_float; // Floating-point representation of elapsed time
 constexpr float WHEEL_RADIUS_LEFT = 0.072;  // Left wheel radius in meters
 constexpr float WHEEL_RADIUS_RIGHT = 0.072; // Right wheel radius in meters
 constexpr float HALF_WHEEL_BASE = 0.125;    // Half of the wheelbase in meters
+constexpr float k_l = 0.00023;  // Uncertainty in the left wheel
+constexpr float k_r = 0.0001;  // Uncertainty in the right wheel
+int authority =0;
+
+// Covariance matrix for pose
+MatrixXd pose_covariance(3, 3); // Initialize a 3x3 matrix for pose covariance
+MatrixXd z_cov(3, 3);
 
 ros::Subscriber m_subscriber;
+ros::Subscriber image_subscriber;
+ros::Subscriber pwm_subscriber;
+ros::Subscriber kalman_subscriber;
+
 ros::Publisher m_publisher;
 ros::Publisher m_angular_velocity_publisher; // Publisher for angular velocity as a single float
 ros::Publisher m_odometry_publisher; // Publisher for odometry
 
+float normalize_angle(float angle) {
+    if (angle >= 0) {
+        return fmod(angle, 2 * M_PI);
+    } else {
+        float value = fmod(angle, 2 * M_PI);
+        return 2 * M_PI - value;
+    }
+}
+
 
 void answer(const asclinic_pkg::LeftRightInt32& msg) {
     // Update times for elapsed time calculation
@@ -41,7 +61,28 @@ void answer(const asclinic_pkg::LeftRightInt32& msg) {
     x += dS * cos(phi + 0.5 * dPhi);
     y += dS * sin(phi + 0.5 * dPhi);
     phi += dPhi;
+    phi = normalize_angle(phi);
+    
+    // Compute Covariance
+    MatrixXd jacob_p(3, 3);
+    jacob_p << 1, 0, -dS * sin(phi + 0.5 * dPhi),
+               0, 1, dS * cos(phi + 0.5 * dPhi),
+               0, 0, 1;
 
+    MatrixXd theta_covariance(2, 2);
+    theta_covariance << k_l * std::abs(deltaThetaL), 0,
+                     	 0, k_r * std::abs(deltaThetaR);
+
+    float r = WHEEL_RADIUS_RIGHT; // Moved this declaration here for consistency
+
+    MatrixXd jacob_phi(3, 2);
+    jacob_phi << r/2 * cos(phi + 0.5 * dPhi) + r/4 / HALF_WHEEL_BASE * dS * sin(phi + 0.5 * dPhi), r/2 * cos(phi + 0.5 * dPhi) - r/4 / HALF_WHEEL_BASE * dS * sin(phi + 0.5 * dPhi),
+    r/2 * sin(phi + 0.5 * dPhi) - r/4 / HALF_WHEEL_BASE * dS * cos(phi + 0.5 * dPhi), r/2 * sin(phi + 0.5 * dPhi) + r/4 / HALF_WHEEL_BASE * dS * cos(phi + 0.5 * dPhi),
+    -r / (2 * HALF_WHEEL_BASE), r / (2 * HALF_WHEEL_BASE);
+
+    MatrixXd pose_covariance_update = jacob_p * pose_covariance * jacob_p.transpose() + jacob_phi * theta_covariance * jacob_phi.transpose();
+    pose_covariance = pose_covariance_update;
+    
     // Calculate angular velocity
     float angular_velocity = dPhi / time_float;
 
@@ -79,40 +120,141 @@ void answer(const asclinic_pkg::LeftRightInt32& msg) {
     
     // Covariance Matrix initialization
     // Pose Covariance
-    for (int i = 0; i < 36; ++i) {
-        if (i == 0 || i == 7 || i == 14) { // Covariance for x, y, z positions
-            odom.pose.covariance[i] = 0.01;
-        } else if (i == 21 || i == 28 || i == 35) { // Covariance for roll, pitch, yaw
-            odom.pose.covariance[i] = 0.1;
-        } else {
-            odom.pose.covariance[i] = 0.0;
+    for (int i = 0; i < 3; ++i) {
+        for (int j = 0; j < 3; ++j) {
+            odom.pose.covariance[i * 6 + j] = pose_covariance(i, j);
         }
     }
-    // Twist Covariance
+
+    // Twist covariance
     for (int i = 0; i < 36; ++i) {
-        if (i == 0 || i == 7 || i == 14) { // Covariance for linear velocities
-            odom.twist.covariance[i] = 0.01;
-        } else if (i == 21 || i == 28 || i == 35) { // Covariance for angular velocities
-            odom.twist.covariance[i] = 0.1;
-        } else {
-            odom.twist.covariance[i] = 0.0;
-        }
+        odom.twist.covariance[i] = 0.1;
     }
     m_odometry_publisher.publish(odom);
 }
 
-int main(int argc, char **argv) {
-    ros::init(argc, argv, "receive_encoder");
+void ImageAnswer(const asclinic_pkg::position& msg) {
+    constrain_time = ros::Time::now();
+    constrain_duration = constrain_time - begin_time;
+    float temp_value = constrain_duration.toSec();
+    if (temp_value < 50) {
+        return;
+    }
+    // Check if elapsed time is less than 0.5 seconds
+    if (authority ==0) {
+        return;
+    }
+
+    // Update the last time to the current time
+
+    MatrixXd z_position(3, 1);
+    z_position << msg.x,
+                  msg.y,
+                  msg.phi;
+
+    MatrixXd K = pose_covariance * (pose_covariance + z_cov).inverse();
+    MatrixXd odo_position(3, 1);
+    odo_position << x,
+                    y,
+                    phi;
+
+    //ROS_INFO_STREAM("odo_position: " << odo_position);
+    //ROS_INFO_STREAM("z_position: " << z_position);
+    //ROS_INFO_STREAM("K: " << K);
+
+    MatrixXd new_pose = odo_position + K * (z_position - odo_position);
+
+    //ROS_INFO_STREAM("new_pose: " << new_pose);
 
+    if (std::isnan(new_pose(0)) || std::isnan(new_pose(1)) || std::isnan(new_pose(2))||new_pose(0)<-2 ||new_pose(1)<-4||std::abs(odo_position(0)-new_pose(0))>1.5||std::abs(odo_position(1)-new_pose(1)>1.5)) {
+        x = odo_position(0);
+        y = odo_position(1);
+        phi = odo_position(2);
+        ROS_WARN("Fail: new_pose contains NaN values");
+    } else {
+        x = new_pose(0);
+        y = new_pose(1);
+        phi = new_pose(2);
+        pose_covariance = pose_covariance - K * (pose_covariance + z_cov) * K.transpose();
+        ROS_INFO_STREAM("Updated pose: X:" << x << ", Y:" << y << ", Phi:" << phi);
+    }
+
+    phi = normalize_angle(phi);
+    //ROS_INFO_STREAM("Normalized Phi: " << phi);
+
+    ROS_INFO("Image updated");
+    authority = 0;
+
+    std_msgs::UInt32 Umsg;
+    Umsg.data = 1;
+    kalman_output.publish(Umsg);
+}
+
+
+void pwmAnswer(const asclinic_pkg::LeftRightFloat32& msg){
+    if(msg.left<0){
+        left_p = -1;
+    }
+    else{
+        left_p = 1;
+    }
+    if(msg.right<0){
+        right_p = -1;
+    }
+    else{
+        right_p = 1;
+    }
+}
+
+void update_authority(const std_msgs::UInt32& msg) {
+    authority = 1;
+    ros::Time last_time = ros::Time::now();
+    ros::Time current_time = ros::Time::now();
+    ros::Duration lastest_duration;
+    float duration_authority;
+    ROS_INFO_STREAM("Authority updated to: " << authority);
+    while(authority){
+        current_time = ros::Time::now();
+        lastest_duration = current_time - last_time;
+        duration_authority = lastest_duration.toSec();
+        if(duration_authority > 2){
+            authority = 0;
+            std_msgs::UInt32 Umsg;
+            Umsg.data = 1;
+            kalman_output.publish(Umsg);
+            ROS_INFO_STREAM("go with no update");
+        }
+        
+        ros::spinOnce();
+        std::this_thread::sleep_for(std::chrono::milliseconds(100));
+    }
+}
+
+int main(int argc, char **argv) {
+    ros::init(argc, argv, "Kalman");
     std::string ns_for_group = ros::this_node::getNamespace();
     ros::NodeHandle nh(ns_for_group);
-
+    begin_time = ros::Time::now();
     // Initialize time_now to current time
     time_now = ros::Time::now();
 
-    m_subscriber = nh.subscribe("asc/encoder_counts", 1, answer);
-    m_publisher = nh.advertise<asclinic_pkg::position>("current_position", 1);
-    m_angular_velocity_publisher = nh.advertise<asclinic_pkg::vw>("angular_velocity_topic", 1);
+    pose_covariance << 1, 1, 1,
+                       1, 1, 1,
+                       1, 1, 1;
+
+    z_cov << 10, 10, 10,
+             10, 10, 10,
+             10, 10, 10;
+
+    m_subscriber = nh.subscribe("/asc/encoder_counts", 1, answer);
+    image_subscriber = nh.subscribe("/image_estimation", 1, ImageAnswer);
+    pwm_subscriber = nh.subscribe("/asc/current_motor_duty_cycle", 1, pwmAnswer);
+    kalman_subscriber = nh.subscribe("/kalman_demand", 1, update_authority);
+
+    m_publisher = nh.advertise<asclinic_pkg::position>("/current_position", 10);
+    m_angular_velocity_publisher = nh.advertise<asclinic_pkg::vw>("/angular_velocity_topic", 10);
+    kalman_output = nh.advertise<std_msgs::UInt32>("/kalman_info", 1);
+    m_odometry_publisher = nh.advertise<nav_msgs/Odometry>("/odom", 10);
 
     ROS_INFO_STREAM("Node started");
     ros::spin();
-- 
GitLab