diff --git a/catkin_ws/src/asclinic_pkg/CMakeLists.txt b/catkin_ws/src/asclinic_pkg/CMakeLists.txt index fdac4ef559db578507c0cc41a7ce556f4e62cacf..e682b6fb1796b0663ad67081fb8bb5224d046405 100644 --- a/catkin_ws/src/asclinic_pkg/CMakeLists.txt +++ b/catkin_ws/src/asclinic_pkg/CMakeLists.txt @@ -13,12 +13,12 @@ find_package(catkin REQUIRED COMPONENTS rospy std_msgs geometry_msgs + tf sensor_msgs cv_bridge genmsg roslib nav_msgs - geometry_msgs ) ## System dependencies are found with CMake's conventions @@ -220,6 +220,7 @@ add_executable(Kalman src/ascr/Kalman.cpp) add_executable(fcontroller1 src/ascr/fcontroller1.cpp) add_executable(final_controller src/ascr/final_controller.cpp) add_executable(control_node src/forklift/control_node.cpp) +add_executable(odometry_new src/forklift/odometry_new.cpp) ## Rename C++ executable without prefix ## The above recommended prefix causes long target names, the following renames the @@ -255,6 +256,7 @@ add_dependencies(Kalman asclinic_pkg_generate_mes add_dependencies(fcontroller1 asclinic_pkg_generate_messages_cpp ${catkin_EXPORTED_TARGETS}) add_dependencies(final_controller asclinic_pkg_generate_messages_cpp ${catkin_EXPORTED_TARGETS}) add_dependencies(control_node asclinic_pkg_generate_messages_cpp ${catkin_EXPORTED_TARGETS}) +add_dependencies(odometry_new asclinic_pkg_generate_messages_cpp ${catkin_EXPORTED_TARGETS}) @@ -287,6 +289,7 @@ target_link_libraries(Kalman ${catkin_LIBRARIES} target_link_libraries(fcontroller1 ${catkin_LIBRARIES}) target_link_libraries(final_controller ${catkin_LIBRARIES}) target_link_libraries(control_node ${catkin_LIBRARIES}) +target_link_libraries(odometry_new ${catkin_LIBRARIES}) diff --git a/catkin_ws/src/asclinic_pkg/launch/forklift.launch b/catkin_ws/src/asclinic_pkg/launch/forklift.launch new file mode 100644 index 0000000000000000000000000000000000000000..a3e61bc031901881b53167c94b13dd7713d41bcd --- /dev/null +++ b/catkin_ws/src/asclinic_pkg/launch/forklift.launch @@ -0,0 +1,102 @@ +<launch> + + <!-- START A GROUP WITH A NAMESPACE --> + <group ns="asc"> + + <!-- LAUNCH A "I2C for Motors" NODE --> + <node + pkg = "asclinic_pkg" + name = "i2c_for_motors" + output = "screen" + type = "i2c_for_motors" + > + <param + name = "motor_driver_verbosity" + value = "1" + /> + <param + name = "motor_driver_current_limit_in_milliamps" + value = "5000" + /> + <param + name = "motor_driver_max_duty_cycle_limit_in_percent" + value = "100.0" + /> + <param + name = "motor_driver_max_accel_limit_in_percent_per_millisecond" + value = "0.04" + /> + <param + name = "motor_driver_max_decel_limit_in_percent_per_millisecond" + value = "0.16" + /> + <param + name = "motor_driver_left_side_multiplier" + value = "1" + /> + <param + name = "motor_driver_right_side_multiplier" + value = "1" + /> + </node> + + <node + pkg = "asclinic_pkg" + name = "encoder_read_multi_threaded" + output = "screen" + type = "encoder_read_multi_threaded" + > + <param + name = "encoder_read_verbosity" + value = "1" + /> + <param + name = "gpio_chip_number_for_encoder_lines" + value = "1" + /> + <param + name = "should_monitor_left_side_encoder_channel_a" + value = "true" + /> + <param + name = "should_monitor_left_side_encoder_channel_b" + value = "false" + /> + <param + name = "should_monitor_right_side_encoder_channel_a" + value = "true" + /> + <param + name = "should_monitor_right_side_encoder_channel_b" + value = "false" + /> + <param + name = "line_number_for_left_side_encoder_channel_a" + value = "105" + /> + <param + name = "line_number_for_left_side_encoder_channel_b" + value = "106" + /> + <param + name = "line_number_for_right_side_encoder_channel_a" + value = "84" + /> + <param + name = "line_number_for_right_side_encoder_channel_b" + value = "130" + /> + <!-- NOTE: options for event monitoring are: "rising", "falling", "both" --> + <param + name = "encoder_events_to_monitor" + value = "rising" + /> + <param + name = "delta_t_for_publishing_encoder_counts" + value = "0.1" + /> + </node> + + </group> + +</launch> \ No newline at end of file diff --git a/catkin_ws/src/asclinic_pkg/src/forklift/control_node.cpp b/catkin_ws/src/asclinic_pkg/src/forklift/control_node.cpp index a82925d68bcec79c62eb268407c7603b6c31a3b1..8732ade64fa59fb1ebaeacc1f423b2710e18f6eb 100644 --- a/catkin_ws/src/asclinic_pkg/src/forklift/control_node.cpp +++ b/catkin_ws/src/asclinic_pkg/src/forklift/control_node.cpp @@ -30,7 +30,7 @@ public: }; -PIDController pid(2, 0, 5); +PIDController pid(3, 0, 5); PIDController pid1(40, 0, 0); PIDController pid_v(1.5, 0, 0); diff --git a/catkin_ws/src/asclinic_pkg/src/forklift/odometry.cpp b/catkin_ws/src/asclinic_pkg/src/forklift/odometry.cpp deleted file mode 100644 index 1d44517cef39a8cc21d3d519043c2bb6c6f2b4ab..0000000000000000000000000000000000000000 --- a/catkin_ws/src/asclinic_pkg/src/forklift/odometry.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#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/ascr/odometry _new.cpp b/catkin_ws/src/asclinic_pkg/src/forklift/odometry_new.cpp similarity index 53% rename from catkin_ws/src/asclinic_pkg/src/ascr/odometry _new.cpp rename to catkin_ws/src/asclinic_pkg/src/forklift/odometry_new.cpp index d0ec56934546fe3dee594f670e5597dac0afb0ee..e6952a51c0b691d5721ae4938b9ad0958bac58b3 100644 --- a/catkin_ws/src/asclinic_pkg/src/ascr/odometry _new.cpp +++ b/catkin_ws/src/asclinic_pkg/src/forklift/odometry_new.cpp @@ -2,33 +2,40 @@ #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; +#include "asclinic_pkg/LeftRightFloat32.h" +#include <eigen3/Eigen/Core> +#include <eigen3/Eigen/Dense> +#include <nav_msgs/Odometry.h> +#include <geometry_msgs/Twist.h> +#include <tf/transform_datatypes.h> // For tf::createQuaternionMsgFromYaw + ros::Time time_previous, time_now; // Timing variables ros::Duration elapsed_time; // Duration to calculate elapsed time + +// Robot's position and orientation variables +float x = 0.0, y = 0.0, phi = 0.0; 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 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; +int left_p = 1, right_p = 1; + +using Eigen::MatrixXd; + // 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) { @@ -39,7 +46,20 @@ float normalize_angle(float angle) { return 2 * M_PI - value; } } - +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 answer(const asclinic_pkg::LeftRightInt32& msg) { // Update times for elapsed time calculation @@ -50,8 +70,8 @@ void answer(const asclinic_pkg::LeftRightInt32& msg) { 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 + float deltaThetaL = 0.000404 * msg.left*left_p / WHEEL_RADIUS_LEFT; // Calculate rotation angle for left wheel + float deltaThetaR = 0.000404 * msg.right*right_p / 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; @@ -89,17 +109,7 @@ void answer(const asclinic_pkg::LeftRightInt32& msg) { // 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); + // Publish odometry nav_msgs::Odometry odom; @@ -114,17 +124,21 @@ void answer(const asclinic_pkg::LeftRightInt32& msg) { odom.pose.pose.orientation = tf::createQuaternionMsgFromYaw(phi); // Set the velocity - odom.twist.twist.linear.x = dS / time_float; - odom.twist.twist.linear.y = 0.0; + odom.twist.twist.linear.x = dS * cos(phi + 0.5 * dPhi) / time_float; + odom.twist.twist.linear.y = dS * sin(phi + 0.5 * dPhi) / time_float; odom.twist.twist.angular.z = angular_velocity; // Covariance Matrix initialization // Pose Covariance - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - odom.pose.covariance[i * 6 + j] = pose_covariance(i, j); - } - } + odom.pose.covariance[0] = pose_covariance(0, 0); // x-x + odom.pose.covariance[1] = pose_covariance(0, 1); // x-y + odom.pose.covariance[5] = pose_covariance(0, 2); // x-yaw + odom.pose.covariance[6] = pose_covariance(1, 0); // y-x + odom.pose.covariance[7] = pose_covariance(1, 1); // y-y + odom.pose.covariance[11] = pose_covariance(1, 2); // y-yaw + odom.pose.covariance[30] = pose_covariance(2, 0); // yaw-x + odom.pose.covariance[31] = pose_covariance(2, 1); // yaw-y + odom.pose.covariance[35] = pose_covariance(2, 2); // yaw-yaw // Twist covariance for (int i = 0; i < 36; ++i) { @@ -133,108 +147,11 @@ void answer(const asclinic_pkg::LeftRightInt32& msg) { m_odometry_publisher.publish(odom); } -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"); + ros::init(argc, argv, "odometry_new"); 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(); @@ -242,19 +159,11 @@ int main(int argc, char **argv) { 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); + m_odometry_publisher = nh.advertise<nav_msgs::Odometry>("/odom", 10); ROS_INFO_STREAM("Node started"); ros::spin(); diff --git a/catkin_ws/src/asclinic_pkg/src/forklift/ppf.py b/catkin_ws/src/asclinic_pkg/src/forklift/ppf.py new file mode 100755 index 0000000000000000000000000000000000000000..ee5ecfa979e10f2389ef5d4565010fa44ca72cb5 --- /dev/null +++ b/catkin_ws/src/asclinic_pkg/src/forklift/ppf.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +import rospy + +from nav_msgs.msg import Odometry +from geometry_msgs.msg import Twist +import matplotlib.pyplot as plt + +# Global variables to store position data +x_data = [] +y_data = [] + +# Obstacle coordinates +ox = [] +oy = [] + +# Define obstacles +for i in range(-4, 6): + ox.append(-2) + oy.append(i) +for i in range(-4, 6): + ox.append(8) + oy.append(i) +for i in range(-2, 9): + ox.append(i) + oy.append(5) +for i in range(-2, 9): + ox.append(i) + oy.append(-4) +# Table obstacles +for i in range(25, 36, 5): # Range from 2.5 to 3.4 (exclusive), multiplied by 10 for integer range + ox.append(i / 10) # Divide by 10 to get the actual floating-point value + oy.append(-3.25) +for i in range(25, 36, 5): + ox.append(i / 10) + oy.append(-2.75) +for i in range(-325, -275, 50): # Range from -3.25 to 2.74 (exclusive), multiplied by 100 for integer range + ox.append(2.5) + oy.append(i / 100) # Divide by 100 to get the actual floating-point value +for i in range(-325, -275, 50): + ox.append(3.5) + oy.append(i / 100) + +# Additional obstacles +ox1 =[1.973, 2.033, 3.982, 3.982, 5.953, 6.013, 7.956, 7.956, 7.986, 7.986, 0.0, 0.0, -1.99, -1.99, 0.0, 2.315, 3.0, 3.687, 5.045, 7.712, 5.983, 3.982, 2.003, 0.0, -1.99, 7.712] + +oy1 =[0.0, 0.0, 0.955, 1.015, 0.0, 0.0, 0.955, 1.015, -0.106, 2.0, 0.955, 1.015, 0.0, -3.0, -4.523, -3.1, -2.696, -3.1, -4.523, 4.0, 5.474, 5.474, 5.474, 5.474, 3.0, -2.0] +ox.extend(ox1) +oy.extend(oy1) + +def position_callback(msg): + global x_data, y_data + x_data.append(msg.pose.pose.position.x) + y_data.append(msg.pose.pose.position.y) + +def main(): + rospy.init_node('ppf') + rospy.Subscriber('/odom', Odometry, position_callback) + + plt.ion() # Enable interactive mode + fig, ax = plt.subplots() + rate = rospy.Rate(5) # Adjust the rate as needed + + while not rospy.is_shutdown(): + ax.clear() + ax.plot(ox, oy, 'ro', label='Obstacles') # Plot obstacles + ax.plot(x_data, y_data, 'b-', label='Path') + + ax.set_xlabel('X Position') + ax.set_ylabel('Y Position') + ax.set_title('Robot Position Plot') + ax.grid(True) + ax.legend() + plt.pause(0.1) + rate.sleep() + + plt.ioff() + plt.show() + +if __name__ == '__main__': + try: + main() + except rospy.ROSInterruptException: + pass diff --git a/catkin_ws/src/teleop_twist_keyboard/CHANGELOG.rst b/catkin_ws/src/teleop_twist_keyboard/CHANGELOG.rst new file mode 100644 index 0000000000000000000000000000000000000000..8d8d204ce41a19687ce7049dc4c5341633d18e23 --- /dev/null +++ b/catkin_ws/src/teleop_twist_keyboard/CHANGELOG.rst @@ -0,0 +1,40 @@ +1.0.0 (2020-06-26) +------------------ +* Implement repeat rate and key timeout +* Update readme about publishing to another topic. +* Contributors: Austin, trainman419 + +0.6.2 (2018-10-21) +------------------ +* Replace tabs with spaces, fixes `#15 <https://github.com/ros-teleop/teleop_twist_keyboard/issues/15>`_ +* Merge pull request `#13 <https://github.com/ros-teleop/teleop_twist_keyboard/issues/13>`_ from asukiaaa/patch-3 + Add rosrun command to specify values +* Add rosrun command to specify values +* Contributors: Asuki Kono, Austin, trainman419 + +0.6.1 (2018-05-02) +------------------ +* Merge pull request `#11 <https://github.com/ros-teleop/teleop_twist_keyboard/issues/11>`_ from MatthijsBurgh/patch-1 + Correct exception handling; Python3 print compatible +* import print from future +* Print python3 compatible +* correct Exception handling +* Merge pull request `#7 <https://github.com/ros-teleop/teleop_twist_keyboard/issues/7>`_ from lucasw/speed_params + set linear and turn speed via rosparams +* Using tabs instead of spaces to match rest of file +* set linear and turn speed via rosparams +* Contributors: Austin, Lucas Walter, Matthijs van der Burgh + +0.6.0 (2016-03-21) +------------------ +* Better instruction formatting +* support holonomic base, send commmand with keyboard down +* Fixing queue_size warning +* Create README.md +* Update the description string in package.xml +* Contributors: Austin, Kei Okada, LiohAu, Mike Purvis, kk6axq, trainman419 + +0.5.0 (2014-02-11) +------------------ +* Initial import from brown_remotelab +* Convert to catkin diff --git a/catkin_ws/src/teleop_twist_keyboard/CMakeLists.txt b/catkin_ws/src/teleop_twist_keyboard/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..86d90cb1be78fd87efc158078d6b7265248b26dc --- /dev/null +++ b/catkin_ws/src/teleop_twist_keyboard/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8.3) +project(teleop_twist_keyboard) + +find_package(catkin REQUIRED) + +catkin_package() + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +catkin_install_python(PROGRAMS + teleop_twist_keyboard.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + diff --git a/catkin_ws/src/teleop_twist_keyboard/README.md b/catkin_ws/src/teleop_twist_keyboard/README.md new file mode 100644 index 0000000000000000000000000000000000000000..000d050901274f62507ae495215d8e9d85277666 --- /dev/null +++ b/catkin_ws/src/teleop_twist_keyboard/README.md @@ -0,0 +1,74 @@ +# teleop_twist_keyboard +Generic Keyboard Teleop for ROS + +# Launch +Run. +``` +rosrun teleop_twist_keyboard teleop_twist_keyboard.py +``` + +With custom values. +``` +rosrun teleop_twist_keyboard teleop_twist_keyboard.py _speed:=0.9 _turn:=0.8 +``` + +Publishing to a different topic (in this case `my_cmd_vel`). +``` +rosrun teleop_twist_keyboard teleop_twist_keyboard.py cmd_vel:=my_cmd_vel +``` + +# Usage +``` +Reading from the keyboard and Publishing to Twist! +--------------------------- +Moving around: + u i o + j k l + m , . + +For Holonomic mode (strafing), hold down the shift key: +--------------------------- + U I O + J K L + M < > + +t : up (+z) +b : down (-z) + +anything else : stop + +q/z : increase/decrease max speeds by 10% +w/x : increase/decrease only linear speed by 10% +e/c : increase/decrease only angular speed by 10% + +CTRL-C to quit +``` + +# Repeat Rate + +If your mobile base requires constant updates on the cmd\_vel topic, teleop\_twist\_keyboard can be configured to repeat the last command at a fixed interval, using the `repeat_rate` private parameter. + +For example, to repeat the last command at 10Hz: + +``` +rosrun teleop_twist_keyboard teleop_twist_keyboard.py _repeat_rate:=10.0 +``` + +It is _highly_ recommened that the repeat rate be used in conjunction with the key timeout, to prevent runaway robots. + +# Key Timeout + +Teleop\_twist\_keyboard can be configured to stop your robot if it does not receive any key presses in a configured time period, using the `key_timeout` private parameter. + +For example, to stop your robot if a keypress has not been received in 0.6 seconds: +``` +rosrun teleop_twist_keyboard teleop_twist_keyboard.py _key_timeout:=0.6 +``` + +It is recommended that you set `key_timeout` higher than the initial key repeat delay on your system (This delay is 0.5 seconds by default on Ubuntu, but can be adjusted). + +# Twist with header +Publishing a `TwistStamped` message instead of `Twist` can be enabled with the `stamped` private parameter. Additionally the `frame_id` of the `TwistStamped` message can be set with the `frame_id` private parameter. +``` +rosrun teleop_twist_keyboard teleop_twist_keyboard.py _stamped:=True _frame_id:=base_link +``` \ No newline at end of file diff --git a/catkin_ws/src/teleop_twist_keyboard/package.xml b/catkin_ws/src/teleop_twist_keyboard/package.xml new file mode 100644 index 0000000000000000000000000000000000000000..84add0221dc56865e5c80751a7f413d92c15979f --- /dev/null +++ b/catkin_ws/src/teleop_twist_keyboard/package.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<package> + <name>teleop_twist_keyboard</name> + <version>1.0.0</version> + <description>Generic keyboard teleop for twist robots.</description> + + <maintainer email="namniart@gmail.com">Austin Hendrix</maintainer> + + <license>BSD</license> + + <url type="website">http://wiki.ros.org/teleop_twist_keyboard</url> + + <author>Graylin Trevor Jay</author> + + <buildtool_depend>catkin</buildtool_depend> + <run_depend>geometry_msgs</run_depend> + <run_depend>rospy</run_depend> +</package> diff --git a/catkin_ws/src/teleop_twist_keyboard/teleop_twist_keyboard.py b/catkin_ws/src/teleop_twist_keyboard/teleop_twist_keyboard.py new file mode 100755 index 0000000000000000000000000000000000000000..a85e1cc5c0c6bd10fa8779bf6ad6b4ed18c36f2a --- /dev/null +++ b/catkin_ws/src/teleop_twist_keyboard/teleop_twist_keyboard.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import threading + +import roslib; roslib.load_manifest('teleop_twist_keyboard') +import rospy + +from geometry_msgs.msg import Twist +from geometry_msgs.msg import TwistStamped + +import sys +from select import select + +if sys.platform == 'win32': + import msvcrt +else: + import termios + import tty + + +TwistMsg = Twist + +msg = """ +Reading from the keyboard and Publishing to Twist! +--------------------------- +Moving around: + u i o + j k l + m , . + +For Holonomic mode (strafing), hold down the shift key: +--------------------------- + U I O + J K L + M < > + +t : up (+z) +b : down (-z) + +anything else : stop + +q/z : increase/decrease max speeds by 10% +w/x : increase/decrease only linear speed by 10% +e/c : increase/decrease only angular speed by 10% + +CTRL-C to quit +""" + +moveBindings = { + 'i':(1,0,0,0), + 'o':(1,0,0,-1), + 'j':(0,0,0,1), + 'l':(0,0,0,-1), + 'u':(1,0,0,1), + ',':(-1,0,0,0), + '.':(-1,0,0,1), + 'm':(-1,0,0,-1), + 'O':(1,-1,0,0), + 'I':(1,0,0,0), + 'J':(0,1,0,0), + 'L':(0,-1,0,0), + 'U':(1,1,0,0), + '<':(-1,0,0,0), + '>':(-1,-1,0,0), + 'M':(-1,1,0,0), + 't':(0,0,1,0), + 'b':(0,0,-1,0), + } + +speedBindings={ + 'q':(1.1,1.1), + 'z':(.9,.9), + 'w':(1.1,1), + 'x':(.9,1), + 'e':(1,1.1), + 'c':(1,.9), + } + +class PublishThread(threading.Thread): + def __init__(self, rate): + super(PublishThread, self).__init__() + self.publisher = rospy.Publisher('cmd_vel', TwistMsg, queue_size = 1) + self.x = 0.0 + self.y = 0.0 + self.z = 0.0 + self.th = 0.0 + self.speed = 0.0 + self.turn = 0.0 + self.condition = threading.Condition() + self.done = False + + # Set timeout to None if rate is 0 (causes new_message to wait forever + # for new data to publish) + if rate != 0.0: + self.timeout = 1.0 / rate + else: + self.timeout = None + + self.start() + + def wait_for_subscribers(self): + i = 0 + while not rospy.is_shutdown() and self.publisher.get_num_connections() == 0: + if i == 4: + print("Waiting for subscriber to connect to {}".format(self.publisher.name)) + rospy.sleep(0.5) + i += 1 + i = i % 5 + if rospy.is_shutdown(): + raise Exception("Got shutdown request before subscribers connected") + + def update(self, x, y, z, th, speed, turn): + self.condition.acquire() + self.x = x + self.y = y + self.z = z + self.th = th + self.speed = speed + self.turn = turn + # Notify publish thread that we have a new message. + self.condition.notify() + self.condition.release() + + def stop(self): + self.done = True + self.update(0, 0, 0, 0, 0, 0) + self.join() + + def run(self): + twist_msg = TwistMsg() + + if stamped: + twist = twist_msg.twist + twist_msg.header.stamp = rospy.Time.now() + twist_msg.header.frame_id = twist_frame + else: + twist = twist_msg + while not self.done: + if stamped: + twist_msg.header.stamp = rospy.Time.now() + self.condition.acquire() + # Wait for a new message or timeout. + self.condition.wait(self.timeout) + + # Copy state into twist message. + twist.linear.x = self.x * self.speed + twist.linear.y = self.y * self.speed + twist.linear.z = self.z * self.speed + twist.angular.x = 0 + twist.angular.y = 0 + twist.angular.z = self.th * self.turn + + self.condition.release() + + # Publish. + self.publisher.publish(twist_msg) + + # Publish stop message when thread exits. + twist.linear.x = 0 + twist.linear.y = 0 + twist.linear.z = 0 + twist.angular.x = 0 + twist.angular.y = 0 + twist.angular.z = 0 + self.publisher.publish(twist_msg) + + +def getKey(settings, timeout): + if sys.platform == 'win32': + # getwch() returns a string on Windows + key = msvcrt.getwch() + else: + tty.setraw(sys.stdin.fileno()) + # sys.stdin.read() returns a string on Linux + rlist, _, _ = select([sys.stdin], [], [], timeout) + if rlist: + key = sys.stdin.read(1) + else: + key = '' + termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings) + return key + +def saveTerminalSettings(): + if sys.platform == 'win32': + return None + return termios.tcgetattr(sys.stdin) + +def restoreTerminalSettings(old_settings): + if sys.platform == 'win32': + return + termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) + +def vels(speed, turn): + return "currently:\tspeed %s\tturn %s " % (speed,turn) + +if __name__=="__main__": + settings = saveTerminalSettings() + + rospy.init_node('teleop_twist_keyboard') + + speed = rospy.get_param("~speed", 0.5) + turn = rospy.get_param("~turn", 1.0) + speed_limit = rospy.get_param("~speed_limit", 1000) + turn_limit = rospy.get_param("~turn_limit", 1000) + repeat = rospy.get_param("~repeat_rate", 0.0) + key_timeout = rospy.get_param("~key_timeout", 0.5) + stamped = rospy.get_param("~stamped", False) + twist_frame = rospy.get_param("~frame_id", '') + if stamped: + TwistMsg = TwistStamped + + pub_thread = PublishThread(repeat) + + x = 0 + y = 0 + z = 0 + th = 0 + status = 0 + + try: + pub_thread.wait_for_subscribers() + pub_thread.update(x, y, z, th, speed, turn) + + print(msg) + print(vels(speed,turn)) + while(1): + key = getKey(settings, key_timeout) + if key in moveBindings.keys(): + x = moveBindings[key][0] + y = moveBindings[key][1] + z = moveBindings[key][2] + th = moveBindings[key][3] + elif key in speedBindings.keys(): + speed = min(speed_limit, speed * speedBindings[key][0]) + turn = min(turn_limit, turn * speedBindings[key][1]) + if speed == speed_limit: + print("Linear speed limit reached!") + if turn == turn_limit: + print("Angular speed limit reached!") + print(vels(speed,turn)) + if (status == 14): + print(msg) + status = (status + 1) % 15 + else: + # Skip updating cmd_vel if key timeout and robot already + # stopped. + if key == '' and x == 0 and y == 0 and z == 0 and th == 0: + continue + x = 0 + y = 0 + z = 0 + th = 0 + if (key == '\x03'): + break + + pub_thread.update(x, y, z, th, speed, turn) + + except Exception as e: + print(e) + + finally: + pub_thread.stop() + restoreTerminalSettings(settings)