From f4d06a623049084a48ad3a3fd4d6478ea3874fab Mon Sep 17 00:00:00 2001 From: Ethan <jiaao@student.unimelb.edu.au> Date: Wed, 17 Jul 2024 13:05:06 +0800 Subject: [PATCH] make forklift folder --- .../src/forklift/fcontroller1.cpp | 220 ++++++++++++++++++ .../asclinic_pkg/src/forklift/odometry.cpp | 80 +++++++ .../src/forklift/recieve_lidar.cpp | 40 ++++ 3 files changed, 340 insertions(+) create mode 100644 catkin_ws/src/asclinic_pkg/src/forklift/fcontroller1.cpp create mode 100644 catkin_ws/src/asclinic_pkg/src/forklift/odometry.cpp create mode 100644 catkin_ws/src/asclinic_pkg/src/forklift/recieve_lidar.cpp diff --git a/catkin_ws/src/asclinic_pkg/src/forklift/fcontroller1.cpp b/catkin_ws/src/asclinic_pkg/src/forklift/fcontroller1.cpp new file mode 100644 index 00000000..376db272 --- /dev/null +++ b/catkin_ws/src/asclinic_pkg/src/forklift/fcontroller1.cpp @@ -0,0 +1,220 @@ +#define _USE_MATH_DEFINES +#include "ros/ros.h" +#include "asclinic_pkg/vw.h" +#include <math.h> +#include <fstream> +#include <thread> +#include <mutex> +#include <chrono> +#include "asclinic_pkg/LeftRightFloat32.h" +#include "asclinic_pkg/position.h" // Assuming this is your custom message header +#include "asclinic_pkg/rotation.h" +#include <std_msgs/UInt32.h> + +class PIDController { +private: + float Kp, Ki, Kd; + float prev_error; + float integral; + +public: + PIDController(float p, float i, float d) : Kp(p), Ki(i), Kd(d), prev_error(0), integral(0) {} + + float compute(float error, float dt) { + float derivative = (error - prev_error) / dt; + integral += error * dt; // Proper integration over time + float output = Kp * error + Ki * integral + Kd * derivative; + prev_error = error; + return output; + } + void resetPrevError() { + prev_error = 0; + } +}; + + +PIDController pid(2, 0, 5); +PIDController pid1(40, 0, 0); +PIDController pid_v(1.5, 0, 0); + +ros::Subscriber vw_sub; +ros::Subscriber vw_r_sub; +ros::Subscriber odometry_sub; +ros::Subscriber position_sub; +ros::Subscriber kalman_back; + +ros::Publisher output_pub; +ros::Publisher state_pub; +ros::Publisher kalman_request; + +std::mutex mtx; + +float current_phi; +float ref_phi; +float time_sep = 0.1; +float ref_v = 0; +float ref_w = 0; +float w_now = 0; +float v_now = 0; +int state_value = 2; // 0 is forward, 1 is rotate , 2 is pending + +float initial_pwm = 25; +//initial 26.5 +void straightline(const asclinic_pkg::vw& vw_msg) { + + + ref_v = vw_msg.v; + ref_w = vw_msg.w; + + + if(ref_v==0 && ref_w == 0){ + state_value = 2; + ROS_INFO_STREAM("stopping"); + asclinic_pkg::LeftRightFloat32 output_msg; + output_msg.left = 0; + output_msg.right = 0; + output_pub.publish(output_msg); + output_pub.publish(output_msg); + + + } + else{ + state_value = 0; + } + +} + +void purerotation(const asclinic_pkg::rotation& rotation_msg) { + state_value = 1; + float flag = rotation_msg.direction; + ref_phi = rotation_msg.ref_phi; + + float rotating_pwm = 15; + float right; + float left; + if (flag > 0) { + right = rotating_pwm; + left = -rotating_pwm; + } else { + right = -rotating_pwm; + left = rotating_pwm; + } + + ROS_INFO_STREAM("The right rotation percentage is " << right); + asclinic_pkg::LeftRightFloat32 output_msg; + output_msg.left = left; + output_msg.right = right; + output_pub.publish(output_msg); + ROS_INFO_STREAM("First message of turning sent"); + + + + // Main rotation loop + bool condition = true; + while (condition) { + float current_phi_value; + { + std::lock_guard<std::mutex> lock(mtx); + current_phi_value = current_phi; + } + + float error = std::abs(ref_phi - current_phi_value); + ROS_INFO_STREAM("Current phi: " << current_phi_value << ", Ref phi: " << ref_phi << ", Error: " << error); + + if (error <= M_PI / 8) { + condition = false; + ROS_INFO("Reached desired rotation angle. Stopping rotation."); + + // Publish PWM signals to stop rotation + output_msg.left = 0; + output_msg.right = 0; + output_pub.publish(output_msg); + } + + ros::spinOnce(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + // Ensure motors are stopped + output_msg.left = 0; + output_msg.right = 0; + output_pub.publish(output_msg); + ROS_INFO_STREAM("Motors stopped after rotation"); + + std_msgs::UInt32 Umsg; + Umsg.data = 1; + kalman_request.publish(Umsg); + + + +} + +void kalman_change(const std_msgs::UInt32& Umsg){ + + // Publish state message + std_msgs::UInt32 state_msg; + state_msg.data = 1; + state_pub.publish(state_msg); + ROS_INFO_STREAM("State message published"); +} + +void updateO(const asclinic_pkg::vw& w_msg) { + w_now = w_msg.w; + v_now = w_msg.v; + + if (state_value != 0){ + return; + } + + //compute the error + float error = ref_w - w_now; + float error_v = ref_v - v_now; + //calculate the output of control + float control_output = pid.compute(error, time_sep); + float control_output_v = pid_v.compute(error_v, time_sep); + + float left = initial_pwm - control_output / 2; + float right = initial_pwm + control_output / 2; + if (right > 95) { + right = 90; + } else if (right < -95) { + right = -90; + } + if (left > 95) { + left = 90; + } else if (left < -95) { + left = -90; + } + asclinic_pkg::LeftRightFloat32 output_msg; + output_msg.left = left; + output_msg.right = right; + output_pub.publish(output_msg); + + + +} +void updatep(const asclinic_pkg::position& msg){ + std::lock_guard<std::mutex> lock(mtx); + current_phi = msg.phi; + +} + +int main(int argc, char** argv) { + ros::init(argc, argv, "fcontroller1"); + std::string ns_for_group = ros::this_node::getNamespace(); + ros::NodeHandle nh(ns_for_group); + ROS_INFO_STREAM("node started"); + + vw_sub = nh.subscribe("/vw_information", 1, straightline); + vw_r_sub = nh.subscribe("/vw_r_information", 3, purerotation); + odometry_sub = nh.subscribe("/angular_velocity_topic", 1, updateO); + position_sub = nh.subscribe("/current_position", 1, updatep); + kalman_back = nh.subscribe("/kalman_info", 1, kalman_change); + + output_pub = nh.advertise<asclinic_pkg::LeftRightFloat32>("/asc/set_motor_duty_cycle", 1, false); + state_pub = nh.advertise<std_msgs::UInt32>("/controller1_state", 3, false); + kalman_request = nh.advertise<std_msgs::UInt32>("/kalman_demand", 1, false); + ros::spin(); + + return 0; +} diff --git a/catkin_ws/src/asclinic_pkg/src/forklift/odometry.cpp b/catkin_ws/src/asclinic_pkg/src/forklift/odometry.cpp new file mode 100644 index 00000000..1d44517c --- /dev/null +++ b/catkin_ws/src/asclinic_pkg/src/forklift/odometry.cpp @@ -0,0 +1,80 @@ +#include "ros/ros.h" +#include <ros/package.h> +#include <cmath> +#include "asclinic_pkg/LeftRightInt32.h" +#include "asclinic_pkg/position.h" +#include "asclinic_pkg/vw.h" +// Robot's position and orientation variables +float x = 0.0, y = 0.0, phi = 0.0; +ros::Time time_previous, time_now; // Timing variables +ros::Duration elapsed_time; // Duration to calculate elapsed time +double time_float; // Floating-point representation of elapsed time + +// Physical and error parameters +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 + +ros::Subscriber m_subscriber; +ros::Publisher m_publisher; +ros::Publisher m_angular_velocity_publisher; // Publisher for angular velocity as a single float + +void answer(const asclinic_pkg::LeftRightInt32& msg) { + // Update times for elapsed time calculation + time_previous = time_now; + time_now = ros::Time::now(); + elapsed_time = time_now - time_previous; + time_float = elapsed_time.toSec(); + ROS_INFO_STREAM("the seperation in second is "<<time_float); + + // Calculate angular displacements for left and right wheels + float deltaThetaL = 0.000404 * msg.left / WHEEL_RADIUS_LEFT; // Calculate rotation angle for left wheel + float deltaThetaR = 0.000404 * msg.right / WHEEL_RADIUS_RIGHT; // Calculate rotation angle for right wheel + + // Calculate the linear displacement and change in orientation + float dS = (WHEEL_RADIUS_LEFT * deltaThetaL + WHEEL_RADIUS_RIGHT * deltaThetaR) / 2; + float dPhi = (WHEEL_RADIUS_RIGHT * deltaThetaR - WHEEL_RADIUS_LEFT * deltaThetaL) / (2 * HALF_WHEEL_BASE); + + // Update position and orientation based on movements + x += dS * cos(phi + 0.5 * dPhi); + y += dS * sin(phi + 0.5 * dPhi); + phi += dPhi; + + // Calculate angular velocity + float angular_velocity = dPhi / time_float; + + // Log current position and angular velocity + ROS_INFO_STREAM("Current Position - X:" << x << ", Y:" << y << ", Phi:" << phi << ", Angular Velocity:" << angular_velocity); + + // Publish position + asclinic_pkg::position position_msg; + position_msg.x = x; + position_msg.y = y; + position_msg.phi = phi; + m_publisher.publish(position_msg); + + // Publish angular velocity + asclinic_pkg::vw angular_velocity_msg; + angular_velocity_msg.w = angular_velocity; + m_angular_velocity_publisher.publish(angular_velocity_msg); +} + +int main(int argc, char **argv) { + ros::init(argc, argv, "receive_encoder"); + + std::string ns_for_group = ros::this_node::getNamespace(); + ros::NodeHandle nh(ns_for_group); + + // 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); + + ROS_INFO_STREAM("Node started"); + ros::spin(); + + return 0; +} + diff --git a/catkin_ws/src/asclinic_pkg/src/forklift/recieve_lidar.cpp b/catkin_ws/src/asclinic_pkg/src/forklift/recieve_lidar.cpp new file mode 100644 index 00000000..47e12cd2 --- /dev/null +++ b/catkin_ws/src/asclinic_pkg/src/forklift/recieve_lidar.cpp @@ -0,0 +1,40 @@ +#include "ros/ros.h" +#include "sensor_msgs/LaserScan.h" +#include <fstream> + +std::ofstream outputFile; +ros::Subscriber m_subscriber; + +void Answer(const sensor_msgs::LaserScan& msg) { + ROS_INFO_STREAM("Message received with angle_min = " << msg.angle_min << " [rad], angle_max = " << msg.angle_max << " [rad], range_min = " << msg.range_min << " [m], range_max = " << msg.range_max << " [m]"); + + if (outputFile.is_open()) { + for (size_t i = 0; i < msg.ranges.size(); ++i) { + outputFile << msg.ranges[i] << ","; + } + outputFile << std::endl; + } else { + ROS_ERROR_STREAM("Unable to write to file. File is not open."); + } +} + +int main(int argc, char* argv[]) { + ros::init(argc, argv, "receive_lidar"); + ros::NodeHandle nh; + + std::string outputFilePath = "/home/asc/lidar_data.csv"; + outputFile.open(outputFilePath, std::ios::out | std::ios::trunc); + if (!outputFile.is_open()) { + ROS_ERROR_STREAM("Unable to create/open file " << outputFilePath); + return 1; + } + + outputFile << "ranges" << std::endl; + + ROS_INFO_STREAM("Node started"); + m_subscriber = nh.subscribe("asc/scan", 1, Answer); + ros::spin(); + + outputFile.close(); + return 0; +} -- GitLab