diff --git a/ch5_pkg/launch/ch5_3.launch b/ch5_pkg/launch/ch5_3.launch index cb30d34..95821e7 100644 --- a/ch5_pkg/launch/ch5_3.launch +++ b/ch5_pkg/launch/ch5_3.launch @@ -3,7 +3,7 @@ -   + diff --git a/ch7_pkg/CMakeLists.txt b/ch7_pkg/CMakeLists.txt new file mode 100644 index 0000000..915851b --- /dev/null +++ b/ch7_pkg/CMakeLists.txt @@ -0,0 +1,207 @@ +cmake_minimum_required(VERSION 3.0.2) +project(ch7_pkg) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + roscpp + rospy + std_msgs + tf +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES ch7_pkg +# CATKIN_DEPENDS roscpp rospy std_msgs tf +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/ch7_pkg.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/ch7_pkg_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# catkin_install_python(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_ch7_pkg.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/ch7_pkg/launch/ch7_1.launch b/ch7_pkg/launch/ch7_1.launch new file mode 100644 index 0000000..e927de1 --- /dev/null +++ b/ch7_pkg/launch/ch7_1.launch @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ch7_pkg/map.pgm b/ch7_pkg/map.pgm new file mode 100644 index 0000000..4663137 --- /dev/null +++ b/ch7_pkg/map.pgm @@ -0,0 +1,5 @@ +P5 +# CREATOR: map_saver.cpp 0.050 m/pix +384 384 +255 + \ No newline at end of file diff --git a/ch7_pkg/map.yaml b/ch7_pkg/map.yaml new file mode 100644 index 0000000..6ad3381 --- /dev/null +++ b/ch7_pkg/map.yaml @@ -0,0 +1,7 @@ +image: map.pgm +resolution: 0.050000 +origin: [-10.000000, -10.000000, 0.000000] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.196 + diff --git a/ch7_pkg/mymap.pgm b/ch7_pkg/mymap.pgm new file mode 100644 index 0000000..0d675c5 --- /dev/null +++ b/ch7_pkg/mymap.pgm @@ -0,0 +1,5 @@ +P5 +# CREATOR: map_saver.cpp 0.050 m/pix +384 384 +255 + \ No newline at end of file diff --git a/ch7_pkg/mymap.yaml b/ch7_pkg/mymap.yaml new file mode 100644 index 0000000..0b1cfac --- /dev/null +++ b/ch7_pkg/mymap.yaml @@ -0,0 +1,7 @@ +image: mymap.pgm +resolution: 0.050000 +origin: [-10.000000, -10.000000, 0.000000] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.196 + diff --git a/ch7_pkg/package.xml b/ch7_pkg/package.xml new file mode 100644 index 0000000..5123358 --- /dev/null +++ b/ch7_pkg/package.xml @@ -0,0 +1,71 @@ + + + ch7_pkg + 0.0.0 + The ch7_pkg package + + + + + joy + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + roscpp + rospy + std_msgs + tf + roscpp + rospy + std_msgs + tf + roscpp + rospy + std_msgs + tf + + + + + + + + diff --git a/my_turtle/src/MoveTurtle.cpp b/my_turtle/src/MoveTurtle.cpp index 34ddeb1..79b660f 100644 --- a/my_turtle/src/MoveTurtle.cpp +++ b/my_turtle/src/MoveTurtle.cpp @@ -1,119 +1,202 @@ #include "ros/ros.h" #include "geometry_msgs/Twist.h" #include "turtlesim/Pose.h" +#include +#include -double pos_x; -double pos_y; -double theta; -// Topic messages callback +// Define a simple structure for a 2D point (waypoint) +struct Point { + double x; + double y; +}; + +// Global variables to store the turtle's current pose +double pos_x = 0.0; +double pos_y = 0.0; +double theta = 0.0; + +// Waypoints definition: A sequence of (x, y) points for the turtle to follow +std::vector waypoints = { + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0}, + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0}, + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0}, + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0}, + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0}, + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0}, + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0}, + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0}, + {5.0, 1.0}, + {1.0, 5.0}, + {5.0, 9.0}, + {9.0, 5.0} + + // {5.54, 5.54} // Center +}; + +// Control parameters +const double ANGULAR_SPEED_GAIN = 2.0; +const double LINEAR_SPEED = 2.0; +const double DISTANCE_THRESHOLD = 0.1; +const double ANGLE_THRESHOLD_RAD = 0.01; +// New parameter: Time to pause at each waypoint +const double WAIT_TIME_SECONDS = 0.0; + +// State variables for waypoint tracking +int current_target_index = 0; +double target_x = waypoints[0].x; +double target_y = waypoints[0].y; + +// --- State Machine --- +enum State { + NAVIGATE, // Actively moving or turning towards the target + WAITING, // Paused at the target waypoint + FINISHED // All waypoints reached +}; + +State current_state = NAVIGATE; +ros::Time wait_start_time; // To track when the waiting period began + +// --- Callback Function --- void poseCallback(const turtlesim::PoseConstPtr& msg) { - pos_x=msg->x; - pos_y=msg->y; - theta=msg->theta; - // ROS_INFO("x: %.2f, y: %.2f, theta: %.2f", msg->x, msg->y, msg->theta); + pos_x = msg->x; + pos_y = msg->y; + theta = msg->theta; } +// Function to normalize an angle to the range [-pi, pi] +double normalizeAngle(double angle) +{ + while (angle > M_PI) angle -= 2.0 * M_PI; + while (angle < -M_PI) angle += 2.0 * M_PI; + return angle; +} + +// --- Main Program --- int main(int argc, char **argv) { - const double FORWARD_SPEED_MPS = 0; - - // Initialize the node - ros::init(argc, argv, "move_turtle"); + // Initialize the ROS node + ros::init(argc, argv, "move_turtle_waypoints"); ros::NodeHandle node; - // A publisher for the movement data + // Publisher and Subscriber setup ros::Publisher pub = node.advertise("turtle1/cmd_vel", 10); - - // A listener for pose ros::Subscriber sub = node.subscribe("turtle1/pose", 10, poseCallback); - // Drive forward at a given speed. The robot points up the x-axis. - // The default constructor will set all commands to 0 - geometry_msgs::Twist msg; - msg.linear.x = FORWARD_SPEED_MPS; - - // Loop at 10Hz, publishing movement commands until we shut down - ros::Rate rate(10); - ROS_INFO("Starting to move forward"); - int flag1=0; - int flag2=0; - int flag3=0; - int init =1; - int p0 = 0; - int p1 =0; - int p2=0; - while (ros::ok()) { - - if(flag1 == 0){ - if(theta < 6.25/4){ - msg.angular.z=1; - }else{ - if(init == 1){ - ROS_INFO("x: %.2f, y: %.2f, theta: %.2f", pos_x,pos_y,theta); - init = 0; - } - msg.angular.z=0; - msg.linear.x=1; - flag1=1; - flag3=0; - } - }else{ - if(pos_y > 10){ - if(p0==0){ - ROS_INFO("x: %.2f, y: %.2f, theta: %.2f", pos_x,pos_y,theta); - p0=1; - } - msg.linear.x=0; - flag2 = 2; - } - } - - - - if(flag2 == 2){ - if(theta > -0.6 || theta > 0){ - msg.angular.z=-1; - }else{ - - flag2 = 1; - msg.angular.z=0; - msg.linear.x=1; - } - }else if(flag1 == 1 && flag2 == 1){ - if(pos_y < 5){ - if(p1 == 0){ - ROS_INFO("x: %.2f, y: %.2f, theta: %.2f", pos_x,pos_y,theta); - p1=1; - } - flag3 =3; - flag2=0; - msg.angular.z=-1; - msg.linear.x=0; - } - } - if(flag3==3){ - if(theta > 3){ - - msg.angular.z=0; - msg.linear.x=1; - flag3=5; - } - - } - - if(flag3==5){ - if(pos_x < 5){ - if(p2==0){ - ROS_INFO("x: %.2f, y: %.2f, theta: %.2f", pos_x,pos_y,theta); - p2=1; - } - - msg.linear.x=0; - } - } + // Set the loop rate + ros::Rate rate(10); + ROS_INFO("Starting waypoint navigation with %zu points. Pausing for %.1f seconds at each.", + waypoints.size(), WAIT_TIME_SECONDS); + + // Main control loop + while (ros::ok()) { + geometry_msgs::Twist msg; // Command message, all fields set to 0 initially + + switch (current_state) { + case NAVIGATE: { + // 1. Calculate the distance and angle to the current target + double dx = target_x - pos_x; + double dy = target_y - pos_y; + double distance = std::sqrt(dx * dx + dy * dy); + + // 2. Check if the target is reached + if (distance < DISTANCE_THRESHOLD) { + ROS_INFO("Waypoint %d reached: (%.2f, %.2f). Starting %.1fs wait.", + current_target_index + 1, target_x, target_y, WAIT_TIME_SECONDS); + + // Transition to the WAITING state + current_state = WAITING; + wait_start_time = ros::Time::now(); + msg.linear.x = 0.0; + msg.angular.z = 0.0; + break; // Move to the next state check immediately + } + + // 3. Navigation logic (Turn and Move) + double target_angle = std::atan2(dy, dx); + double angle_error = normalizeAngle(target_angle - theta); + + msg.angular.z = ANGULAR_SPEED_GAIN * angle_error; + + if (std::abs(angle_error) < ANGLE_THRESHOLD_RAD) { + // Facing target, move forward + msg.linear.x = LINEAR_SPEED; + msg.angular.z = 0.0; + } else { + // Not facing target, just turn + msg.linear.x = 0.0; + } + break; + } + + case WAITING: { + // 1. Remain stopped (msg already 0.0 from previous step) + + // 2. Check if the wait time is over + if ((ros::Time::now() - wait_start_time).toSec() >= WAIT_TIME_SECONDS) { + + // 3. Advance to the next waypoint + current_target_index++; + + if (current_target_index < waypoints.size()) { + // There are more points, set the new target + target_x = waypoints[current_target_index].x; + target_y = waypoints[current_target_index].y; + ROS_INFO("Resuming navigation to next point: (%2.f, %2.f)", target_x, target_y); + current_state = NAVIGATE; // Transition back to NAVIGATE + } else { + // All points complete + ROS_INFO("All waypoints have been processed. Task finished."); + current_state = FINISHED; // Transition to FINISHED + } + } + break; + } + + case FINISHED: { + // Keep publishing zero velocity to ensure it stays stopped + msg.linear.x = 0.0; + msg.angular.z = 0.0; + break; + } + } + + // Publish the movement commands pub.publish(msg); - ros::spinOnce(); // Allow processing of incoming messages + + // Allow ROS to process events + ros::spinOnce(); rate.sleep(); + + // Exit the loop if finished + if (current_state == FINISHED) { + break; + } } + + return 0; } \ No newline at end of file diff --git a/pluginlib_11463144/CMakeLists.txt b/pluginlib_11463144/CMakeLists.txt new file mode 100644 index 0000000..6f11c90 --- /dev/null +++ b/pluginlib_11463144/CMakeLists.txt @@ -0,0 +1,214 @@ +cmake_minimum_required(VERSION 3.0.2) +project(pluginlib_11463144) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + pluginlib + roscpp +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs # Or other packages containing msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES pluginlib_11463144 +# CATKIN_DEPENDS pluginlib roscpp +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( + include + ${catkin_INCLUDE_DIRS} +) + +add_library(polygon_plugins src/polygon_plugins.cpp) +add_executable(polygon_loader src/polygon_loader.cpp) + +# Link the executable to roscpp and pluginlib +target_link_libraries(polygon_loader ${catkin_LIBRARIES}) + +# ⭐ ADD THIS LINE: Link your plugin library to roscpp and pluginlib +# This is required for PLUGINLIB_EXPORT_CLASS to work. +target_link_libraries(polygon_plugins ${catkin_LIBRARIES}) +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/pluginlib_11463144.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/pluginlib_11463144_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# catkin_install_python(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_pluginlib_11463144.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/pluginlib_11463144/include/pluginlib_11463144/polygon_base.h b/pluginlib_11463144/include/pluginlib_11463144/polygon_base.h new file mode 100644 index 0000000..64914d7 --- /dev/null +++ b/pluginlib_11463144/include/pluginlib_11463144/polygon_base.h @@ -0,0 +1,15 @@ +#ifndef PLUGINLIB_TUTORIALS__POLYGON_BASE_H_ +#define PLUGINLIB_TUTORIALS__POLYGON_BASE_H_ +namespace polygon_base +{ + class RegularPolygon + { + public: + virtual void initialize(double side_length) = 0; + virtual double area() = 0; + virtual ~RegularPolygon(){} + protected: + RegularPolygon(){} + }; +}; +#endif diff --git a/pluginlib_11463144/include/pluginlib_11463144/polygon_plugins.h b/pluginlib_11463144/include/pluginlib_11463144/polygon_plugins.h new file mode 100644 index 0000000..1a6bb41 --- /dev/null +++ b/pluginlib_11463144/include/pluginlib_11463144/polygon_plugins.h @@ -0,0 +1,198 @@ +#ifndef PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_ +#define PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_ +#include // 假設你的路徑是這個,ROS 教學中通常是 +#include //cmath標頭檔為特殊運算語法, + //沒有寫的話無法執行pow(,)平方運算語法 +#include // 用於拋出例外 + +namespace polygon_plugins +{ + // --- 3 邊形 (Triangle) --- + class Triangle : public polygon_base::RegularPolygon + { + public: + Triangle(){} + + void initialize(double side_length) + { + side_length_ = side_length; + } + + double area() + { + return 0.5 * side_length_ * getHeight(); + } + + double getHeight() + { + // 等邊三角形的高: h = sqrt(a^2 - (a/2)^2) = sqrt(3)/2 * a + return sqrt((side_length_ * side_length_) - ((side_length_ / 2) * (side_length_ / 2))); + } + + private: + double side_length_; + }; + + // --- 4 邊形 (Square) --- + class Square : public polygon_base::RegularPolygon + { + public: + Square(){} + + void initialize(double side_length) + { + side_length_ = side_length; + } + + double area() + { + return side_length_ * side_length_; + } + + private: + double side_length_; + + }; + + // --- N 邊形 (N-Sided Polygon) (通用實現) --- + // 為了處理 5 到 10 邊,我們實現一個通用的 RegularPolygon 類, + // 這樣就不需要為每個邊數都寫一個類。 + class RegularPolygonN : public polygon_base::RegularPolygon +{ + public: + // 修正: 構造函數現在可以正確初始化成員變數 + RegularPolygonN() : num_sides_(0), side_length_(0.0) {} + + // 修正: 實現基類的純虛擬函數 initialize + void initialize(double side_length) override // 使用 override 確保正確覆寫 + { + side_length_ = side_length; + // ⚠️ 注意:由於 initialize 只接受邊長,num_sides_ 必須在外部設定或在這個類中固定 + // 我們將假設這個類將被用於一個固定的 N (例如 Octagon) + // 若 num_sides_ 為 0,area() 將會返回 0。 + } + + // 新增 setter (非 pluginlib 標準,用於外部調試或測試) + void set_num_sides(int n) + { + if (n >= 3) num_sides_ = n; + } + inline double calculate_polygon_area(int n, double s) + { + if (n < 3) return 0.0; + return (n * s * s) / (4.0 * tan(M_PI / n)); + } + // 修正: 實現基類的純虛擬函數 area + double area() override + { + if (num_sides_ > 10) + { + // 當 N > 10 時,視為圓形,side_length_ 為半徑 + double radius = side_length_; + return M_PI * radius * radius; + } + else if (num_sides_ >= 3 && num_sides_ <= 10) + { + // N = 3 到 10 時,計算多邊形面積 + return calculate_polygon_area(num_sides_, side_length_); + } + else + { + return 0.0; + } + } + + private: + // ⭐ 修正: 新增 side_length_ 和 num_sides_ 的宣告 + double side_length_; + int num_sides_; +}; + + // --- 5 邊形 (Pentagon) 到 10 邊形 (Decagon) --- + // 使用通用面積公式:Area = (n * s^2) / (4 * tan(pi/n)) + + // 協助計算面積的通用函數 + inline double calculate_area(int n, double s) + { + // M_PI 是 cmath (或 math.h) 中定義的 π 值 + double apothem = s / (2.0 * tan(M_PI / n)); // 邊心距 + return (0.5 * n * s) * apothem; // 面積 = 1/2 * 周長 * 邊心距 + } + + + class Pentagon : public polygon_base::RegularPolygon + { + public: + Pentagon(){} + void initialize(double side_length) { side_length_ = side_length; } + double area() { return calculate_area(5, side_length_); } + private: + double side_length_; + }; + + class Hexagon : public polygon_base::RegularPolygon + { + public: + Hexagon(){} + void initialize(double side_length) { side_length_ = side_length; } + double area() { return calculate_area(6, side_length_); } + private: + double side_length_; + }; + + class Heptagon : public polygon_base::RegularPolygon + { + public: + Heptagon(){} + void initialize(double side_length) { side_length_ = side_length; } + double area() { return calculate_area(7, side_length_); } + private: + double side_length_; + }; + + class Octagon : public polygon_base::RegularPolygon + { + public: + Octagon(){} + void initialize(double side_length) { side_length_ = side_length; } + double area() { return calculate_area(8, side_length_); } + private: + double side_length_; + }; + + class Nonagon : public polygon_base::RegularPolygon + { + public: + Nonagon(){} + void initialize(double side_length) { side_length_ = side_length; } + double area() { return calculate_area(9, side_length_); } + private: + double side_length_; + }; + + class Decagon : public polygon_base::RegularPolygon + { + public: + Decagon(){} + void initialize(double side_length) { side_length_ = side_length; } + double area() { return calculate_area(10, side_length_); } + private: + double side_length_; + }; + class Circle : public polygon_base::RegularPolygon + { + public: + Circle(){} + void initialize(double radius) { radius_ = radius; } + double area() { return M_PI * radius_ * radius_; } + private: + double radius_; + }; +}; // end namespace polygon_plugins + +// 確保 M_PI 在某些環境下可用 +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#endif // PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_ \ No newline at end of file diff --git a/pluginlib_11463144/package.xml b/pluginlib_11463144/package.xml new file mode 100644 index 0000000..ea608b3 --- /dev/null +++ b/pluginlib_11463144/package.xml @@ -0,0 +1,64 @@ + + + pluginlib_11463144 + 0.0.0 + The pluginlib_11463144 package + + + + + joy + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + pluginlib + roscpp + pluginlib + roscpp + pluginlib + roscpp + + + + + + + diff --git a/pluginlib_11463144/polygon_plugins.xml b/pluginlib_11463144/polygon_plugins.xml new file mode 100644 index 0000000..ead9b99 --- /dev/null +++ b/pluginlib_11463144/polygon_plugins.xml @@ -0,0 +1,33 @@ + + + + A regular triangle plugin. + + + A regular square plugin. + + + + Circle approximation plugin. + + + + A regular pentagon plugin. + + + A regular hexagon plugin. + + + A regular heptagon plugin. + + + A regular octagon plugin. + + + A regular nonagon plugin. + + + A regular decagon plugin. + + + \ No newline at end of file diff --git a/pluginlib_11463144/src/polygon_loader.cpp b/pluginlib_11463144/src/polygon_loader.cpp new file mode 100644 index 0000000..2e80254 --- /dev/null +++ b/pluginlib_11463144/src/polygon_loader.cpp @@ -0,0 +1,111 @@ +#include +#include // 替換為你的實際路徑 +#include // 引入 ROS/ROS_INFO +#include +#include +#include // 用於 std::atoi 和 std::stod + +int main(int argc, char** argv) +{ + // 1. 檢查參數數量 + if (argc != 3) + { + ROS_ERROR("Usage: polygon_plugin_tester "); + return 1; + } + + // 2. 解析參數 + int num_sides = 0; + double length = 0.0; // 可能是邊長 S 或半徑 R + std::string class_name; + + try + { + // argv[1] 是邊數 N + num_sides = std::atoi(argv[1]); + + // argv[2] 是邊長 S 或半徑 R + length = std::stod(argv[2]); + } + catch (const std::exception& e) + { + ROS_ERROR("Invalid input for number of sides or length: %s", e.what()); + return 1; + } + + // 3. 根據 N 動態選擇插件類名 + if (num_sides <= 2) + { + ROS_ERROR("A polygon must have at least 3 sides. Input N=%d is invalid.", num_sides); + return 1; + } + else if (num_sides == 3) + { + class_name = "polygon_plugins::Triangle"; + } + else if (num_sides == 4) + { + class_name = "polygon_plugins::Square"; + } + // 處理 5 到 10 邊的標準多邊形 + else if (num_sides >= 5 && num_sides <= 10) + { + // ⭐ FIX: Load the specific classes you defined in polygon_plugins.h + switch (num_sides) + { + case 5: class_name = "polygon_plugins::Pentagon"; break; + case 6: class_name = "polygon_plugins::Hexagon"; break; + case 7: class_name = "polygon_plugins::Heptagon"; break; + case 8: class_name = "polygon_plugins::Octagon"; break; + case 9: class_name = "polygon_plugins::Nonagon"; break; + case 10: class_name = "polygon_plugins::Decagon"; break; + default: break; + } + } + // 核心邏輯:如果邊數超過 10 邊,則視為圓形 + else // num_sides > 10 + { + class_name = "polygon_plugins::Circle"; + ROS_WARN("Number of sides (%d) is over 10. Calculating area as a circle (Radius = %.2f).", num_sides, length); + } + + // 初始化 ROS (用於 ROS_INFO 和 ROS_ERROR) + ros::init(argc, argv, "polygon_plugin_tester", ros::init_options::AnonymousName); + + // 4. 加載插件並計算 + // ⭐ FIX: Change "pluginlib_tutorials_" to your actual package name + pluginlib::ClassLoader poly_loader( + "pluginlib_11463144", + "polygon_base::RegularPolygon" + ); + + boost::shared_ptr polygon; + + try + { + // 加載動態決定的類 + polygon = poly_loader.createInstance(class_name); + + // 初始化邊長 (對於圓形來說就是半徑) + polygon->initialize(length); + + double area = polygon->area(); + + // 輸出結果 + if (num_sides > 10) { + ROS_INFO("Shape: Circle (N=%d, R=%.2f). Area: %.4f", num_sides, length, area); + } else { + ROS_INFO("Shape: %s (N=%d, S=%.2f). Area: %.4f", class_name.c_str(), num_sides, length, area); + } + } + catch(pluginlib::PluginlibException& ex) + { + ROS_ERROR("Failed to load plugin '%s'. Error: %s", class_name.c_str(), ex.what()); + } + catch(const std::exception& e) + { + ROS_ERROR("An unexpected error occurred: %s", e.what()); + } + + return 0; +} \ No newline at end of file diff --git a/pluginlib_11463144/src/polygon_plugins.cpp b/pluginlib_11463144/src/polygon_plugins.cpp new file mode 100644 index 0000000..056bbb3 --- /dev/null +++ b/pluginlib_11463144/src/polygon_plugins.cpp @@ -0,0 +1,17 @@ +#include +#include +#include + +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon) +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon) +// ⭐ REMOVED: RegularPolygonN is no longer used +// PLUGINLIB_EXPORT_CLASS(polygon_plugins::RegularPolygonN, polygon_base::RegularPolygon) +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Circle, polygon_base::RegularPolygon) + +// ⭐ ADDED: Export all the new polygon classes +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Pentagon, polygon_base::RegularPolygon) +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Hexagon, polygon_base::RegularPolygon) +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Heptagon, polygon_base::RegularPolygon) +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Octagon, polygon_base::RegularPolygon) +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Nonagon, polygon_base::RegularPolygon) +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Decagon, polygon_base::RegularPolygon) \ No newline at end of file diff --git a/pluginlib_tutorials_/CMakeLists.txt b/pluginlib_tutorials_/CMakeLists.txt new file mode 100644 index 0000000..8ca4684 --- /dev/null +++ b/pluginlib_tutorials_/CMakeLists.txt @@ -0,0 +1,205 @@ +cmake_minimum_required(VERSION 3.0.2) +project(pluginlib_tutorials_) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + pluginlib + roscpp +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs # Or other packages containing msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES pluginlib_tutorials_ +# CATKIN_DEPENDS pluginlib roscpp +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations + +include_directories(include ${catkin_INCLUDE_DIRS}) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/pluginlib_tutorials_.cpp +# ) +add_library(polygon_plugins src/polygon_plugins.cpp) +add_executable(polygon_loader src/polygon_loader.cpp) +target_link_libraries(polygon_loader ${catkin_LIBRARIES}) +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/pluginlib_tutorials__node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# catkin_install_python(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_pluginlib_tutorials_.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/pluginlib_tutorials_/include/pluginlib_tutorials_/polygon_base.h b/pluginlib_tutorials_/include/pluginlib_tutorials_/polygon_base.h new file mode 100644 index 0000000..64914d7 --- /dev/null +++ b/pluginlib_tutorials_/include/pluginlib_tutorials_/polygon_base.h @@ -0,0 +1,15 @@ +#ifndef PLUGINLIB_TUTORIALS__POLYGON_BASE_H_ +#define PLUGINLIB_TUTORIALS__POLYGON_BASE_H_ +namespace polygon_base +{ + class RegularPolygon + { + public: + virtual void initialize(double side_length) = 0; + virtual double area() = 0; + virtual ~RegularPolygon(){} + protected: + RegularPolygon(){} + }; +}; +#endif diff --git a/pluginlib_tutorials_/include/pluginlib_tutorials_/polygon_plugins.h b/pluginlib_tutorials_/include/pluginlib_tutorials_/polygon_plugins.h new file mode 100644 index 0000000..5078316 --- /dev/null +++ b/pluginlib_tutorials_/include/pluginlib_tutorials_/polygon_plugins.h @@ -0,0 +1,53 @@ +#ifndef PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_ +#define PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_ +#include +#include //cmath標頭檔為特殊運算語法, + //沒有寫的話無法執行pow(,)平方運算語法 + +namespace polygon_plugins +{ + class Triangle : public polygon_base::RegularPolygon + { + public: + Triangle(){} + + void initialize(double side_length) + { + side_length_ = side_length; + } + + double area() + { + return 0.5 * side_length_ * getHeight(); + } + + double getHeight() + { + return sqrt((side_length_ * side_length_) - ((side_length_ / 2) * (side_length_ / 2))); + } + + private: + double side_length_; + }; + + class Square : public polygon_base::RegularPolygon + { + public: + Square(){} + + void initialize(double side_length) + { + side_length_ = side_length; + } + + double area() + { + return side_length_ * side_length_; + } + + private: + double side_length_; + + }; +}; +#endif diff --git a/pluginlib_tutorials_/package.xml b/pluginlib_tutorials_/package.xml new file mode 100644 index 0000000..0afe6e8 --- /dev/null +++ b/pluginlib_tutorials_/package.xml @@ -0,0 +1,64 @@ + + + pluginlib_tutorials_ + 0.0.0 + The pluginlib_tutorials_ package + + + + + joy + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + pluginlib + roscpp + pluginlib + roscpp + pluginlib + roscpp + + + + + + + diff --git a/pluginlib_tutorials_/polygon_plugins.xml b/pluginlib_tutorials_/polygon_plugins.xml new file mode 100644 index 0000000..1578cbd --- /dev/null +++ b/pluginlib_tutorials_/polygon_plugins.xml @@ -0,0 +1,8 @@ + + + This is a triangle plugin. + + + This is a square plugin. + + \ No newline at end of file diff --git a/pluginlib_tutorials_/src/polygon_loader.cpp b/pluginlib_tutorials_/src/polygon_loader.cpp new file mode 100644 index 0000000..7adf02f --- /dev/null +++ b/pluginlib_tutorials_/src/polygon_loader.cpp @@ -0,0 +1,23 @@ +#include +#include + +int main(int argc, char** argv) +{ + pluginlib::ClassLoader poly_loader("pluginlib_tutorials_", "polygon_base::RegularPolygon"); + +try + { + boost::shared_ptr triangle = poly_loader.createInstance("polygon_plugins::Triangle"); + triangle->initialize(10.0); + boost::shared_ptr square = poly_loader.createInstance("polygon_plugins::Square"); + square->initialize(10.0); + ROS_INFO("Triangle area: %.2f", triangle->area()); + ROS_INFO("Square area: %.2f", square->area()); + } + + catch(pluginlib::PluginlibException& ex) + { + ROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what()); + } + return 0; +} \ No newline at end of file diff --git a/pluginlib_tutorials_/src/polygon_plugins.cpp b/pluginlib_tutorials_/src/polygon_plugins.cpp new file mode 100644 index 0000000..8b2a263 --- /dev/null +++ b/pluginlib_tutorials_/src/polygon_plugins.cpp @@ -0,0 +1,6 @@ +#include +#include +#include + +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon) +PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon) \ No newline at end of file diff --git a/simple_layers/CMakeLists.txt b/simple_layers/CMakeLists.txt new file mode 100644 index 0000000..98ee7c3 --- /dev/null +++ b/simple_layers/CMakeLists.txt @@ -0,0 +1,209 @@ +cmake_minimum_required(VERSION 3.0.2) +project(simple_layers) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + costmap_2d + dynamic_reconfigure + roscpp + rospy + std_msgs +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES simple_layers +# CATKIN_DEPENDS costmap_2d dynamic_reconfigure roscpp rospy std_msgs +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) +include_directories(include ${catkin_INCLUDE_DIRS}) +add_library(simple_layer src/simple_layer.cpp) +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/simple_layers.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/simple_layers_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# catkin_install_python(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html +# install(TARGETS ${PROJECT_NAME}_node +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark libraries for installation +## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html +# install(TARGETS ${PROJECT_NAME} +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_simple_layers.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/simple_layers/include/simple_layers/simple_layer.h b/simple_layers/include/simple_layers/simple_layer.h new file mode 100644 index 0000000..99fa081 --- /dev/null +++ b/simple_layers/include/simple_layers/simple_layer.h @@ -0,0 +1,28 @@ +#ifndef SIMPLE_LAYER_H_ +#define SIMPLE_LAYER_H_ +#include +#include +#include +#include +#include + +namespace simple_layer_namespace +{ + +class SimpleLayer : public costmap_2d::Layer +{ +public: + SimpleLayer(); + + virtual void onInitialize(); + virtual void updateBounds(double origin_x, double origin_y, double origin_yaw, double* min_x, double* min_y, double* max_x, double* max_y); + virtual void updateCosts(costmap_2d::Costmap2D& master_grid, int min_i, int min_j, int max_i, int max_j); + +private: + void reconfigureCB(costmap_2d::GenericPluginConfig &config, uint32_t level); + + double mark_x_, mark_y_; + dynamic_reconfigure::Server *dsrv_; +}; +} +#endif diff --git a/simple_layers/ostmap_plugins.xml b/simple_layers/ostmap_plugins.xml new file mode 100644 index 0000000..692bc43 --- /dev/null +++ b/simple_layers/ostmap_plugins.xml @@ -0,0 +1,5 @@ + + + Demo Layer that adds a point 1 meter in front of the robot + + diff --git a/simple_layers/package.xml b/simple_layers/package.xml new file mode 100644 index 0000000..1769c1f --- /dev/null +++ b/simple_layers/package.xml @@ -0,0 +1,73 @@ + + + simple_layers + 0.0.0 + The simple_layers package + + + + + joy + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + costmap_2d + dynamic_reconfigure + roscpp + rospy + std_msgs + costmap_2d + dynamic_reconfigure + roscpp + rospy + std_msgs + costmap_2d + dynamic_reconfigure + roscpp + rospy + std_msgs + + + + + + + diff --git a/simple_layers/src/simple_layer.cpp b/simple_layers/src/simple_layer.cpp new file mode 100644 index 0000000..ecb74bf --- /dev/null +++ b/simple_layers/src/simple_layer.cpp @@ -0,0 +1,54 @@ +#include +#include + +PLUGINLIB_EXPORT_CLASS(simple_layer_namespace::SimpleLayer, costmap_2d::Layer) + +using costmap_2d::LETHAL_OBSTACLE; + +namespace simple_layer_namespace +{ + +SimpleLayer::SimpleLayer() {} + +void SimpleLayer::onInitialize() +{ + ros::NodeHandle nh("~/" + name_); + current_ = true; + + dsrv_ = new dynamic_reconfigure::Server(nh); + dynamic_reconfigure::Server::CallbackType cb = boost::bind( + &SimpleLayer::reconfigureCB, this, _1, _2); + dsrv_->setCallback(cb); +} +void SimpleLayer::reconfigureCB(costmap_2d::GenericPluginConfig &config, uint32_t level) +{ + enabled_ = config.enabled; +} + +void SimpleLayer::updateBounds(double origin_x, double origin_y, double origin_yaw, double* min_x, + double* min_y, double* max_x, double* max_y) +{ + if (!enabled_) + return; + + mark_x_ = origin_x + cos(origin_yaw); + mark_y_ = origin_y + sin(origin_yaw); + + *min_x = std::min(*min_x, mark_x_); + *min_y = std::min(*min_y, mark_y_); + *max_x = std::max(*max_x, mark_x_); + *max_y = std::max(*max_y, mark_y_); +} + +void SimpleLayer::updateCosts(costmap_2d::Costmap2D& master_grid, int min_i, int min_j, int max_i, int max_j) +{ + if (!enabled_) + return; + unsigned int mx; + unsigned int my; + if(master_grid.worldToMap(mark_x_, mark_y_, mx, my)){ + master_grid.setCost(mx, my, LETHAL_OBSTACLE); + } +} + +} // end namespace diff --git a/tf_demo/CMakeLists.txt b/tf_demo/CMakeLists.txt index 2c944fa..f72c89a 100644 --- a/tf_demo/CMakeLists.txt +++ b/tf_demo/CMakeLists.txt @@ -147,6 +147,11 @@ add_executable(tf_broadcaster src/tf_broadcaster.cpp) # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) ## Specify libraries to link a library or executable target against +add_executable(tf_listener src/tf_listener.cpp) +# add_executable(tf_mainrobot src/tf_mainrobot.cpp) +add_executable(robot_location src/robot_location.cpp) +target_link_libraries(robot_location ${catkin_LIBRARIES}) +target_link_libraries(tf_listener ${catkin_LIBRARIES}) target_link_libraries(tf_broadcaster ${catkin_LIBRARIES} ) diff --git a/tf_demo/launch/ch5_1.launch b/tf_demo/launch/ch5_1.launch deleted file mode 100644 index 64b9292..0000000 --- a/tf_demo/launch/ch5_1.launch +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/tf_demo/launch/tf_demo.launch b/tf_demo/launch/tf_demo.launch new file mode 100644 index 0000000..325bdae --- /dev/null +++ b/tf_demo/launch/tf_demo.launch @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tf_demo/launch/tf_demo2.launch b/tf_demo/launch/tf_demo2.launch new file mode 100644 index 0000000..90bf571 --- /dev/null +++ b/tf_demo/launch/tf_demo2.launch @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tf_demo/src/robot_location.cpp b/tf_demo/src/robot_location.cpp new file mode 100644 index 0000000..6b6457f --- /dev/null +++ b/tf_demo/src/robot_location.cpp @@ -0,0 +1,25 @@ +#include +#include +using namespace std; +int main(int argc, char** argv){ +ros::init(argc, argv, "robot_location"); +ros::NodeHandle node; +tf::TransformListener listener; +ros::Rate rate(2.0); +listener.waitForTransform("/odom", "/base_footprint", ros::Time(0), +ros::Duration(10.0)); +while (ros::ok()){ +tf::StampedTransform transform; +try { +listener.lookupTransform("/odom", "/base_footprint", +ros::Time(0), transform); +double x = transform.getOrigin().x(); +double y = transform.getOrigin().y(); +cout << "Current position: (" << x << "," << y << ")" << endl; +} catch (tf::TransformException &ex) { +ROS_ERROR("%s",ex.what()); +} +rate.sleep(); +} +return 0; +} \ No newline at end of file diff --git a/tf_demo/src/tf_listener.cpp b/tf_demo/src/tf_listener.cpp new file mode 100644 index 0000000..34cd987 --- /dev/null +++ b/tf_demo/src/tf_listener.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include +int main(int argc, char** argv) { +ros::init(argc, argv, "my_tf_listener"); +ros::NodeHandle node; +ros::service::waitForService("spawn"); +ros::ServiceClient add_turtle = +node.serviceClient("spawn"); +turtlesim::Spawn srv; +add_turtle.call(srv); +ros::Publisher turtle_vel = +node.advertise("turtle2/cmd_vel", 10); +tf::TransformListener listener; +ros::Rate rate(10.0); +while (node.ok()) { +tf::StampedTransform transform; +try { +listener.waitForTransform("/turtle2", "/turtle1", ros::Time(0), ros::Duration(10.0)); +listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform); +} catch (tf::TransformException ex) { +ROS_ERROR("%s",ex.what()); +} +geometry_msgs::Twist vel_msg; +vel_msg.angular.z = 4 * atan2(transform.getOrigin().y(), +transform.getOrigin().x()); +vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) + +pow(transform.getOrigin().y(), 2)); +turtle_vel.publish(vel_msg); +rate.sleep(); +} +return 0; +}; \ No newline at end of file diff --git a/tf_demo/src/tf_mainrobot.cpp b/tf_demo/src/tf_mainrobot.cpp new file mode 100644 index 0000000..10827ac --- /dev/null +++ b/tf_demo/src/tf_mainrobot.cpp @@ -0,0 +1,130 @@ +#include "ros/ros.h" +#include "geometry_msgs/Twist.h" +#include "turtlesim/Pose.h" +#include +#include + +// Define a simple structure for a 2D point (waypoint) +struct Point { + double x; + double y; +}; + +// Global variables to store the turtle's current pose +double pos_x = 0.0; +double pos_y = 0.0; +double theta = 0.0; + +// Waypoints definition: A sequence of (x, y) points for the turtle to follow +// NOTE: Turtlesim's max coordinates are 11.08 x 11.08. +std::vector waypoints = { + {0.0, 5.0}, // Start by turning to this point + {5.0, 0.0}, // Move across + {10.0, 5.0},// Move up + {5.0, 5.0} // Move back +}; + +// Control parameters +const double ANGULAR_SPEED_GAIN = 1.0; // How fast to turn (P-gain for angle) +const double LINEAR_SPEED = 1.0; // Constant forward speed +const double DISTANCE_THRESHOLD = 0.1; // How close to the target is 'close enough' +const double ANGLE_THRESHOLD_RAD = 0.01; // How straight to be before moving forward + +// State variables for waypoint tracking +int current_target_index = 0; +double target_x = waypoints[0].x; +double target_y = waypoints[0].y; + +// --- Callback Function --- +void poseCallback(const turtlesim::PoseConstPtr& msg) +{ + pos_x = msg->x; + pos_y = msg->y; + theta = msg->theta; +} + +// Function to normalize an angle to the range [-pi, pi] +double normalizeAngle(double angle) +{ + while (angle > M_PI) angle -= 2.0 * M_PI; + while (angle < -M_PI) angle += 2.0 * M_PI; + return angle; +} + +// --- Main Program --- +int main(int argc, char **argv) +{ + // Initialize the ROS node + ros::init(argc, argv, "move_turtle_waypoints"); + ros::NodeHandle node; + + // Publisher and Subscriber setup + ros::Publisher pub = node.advertise("turtle1/cmd_vel", 10); + ros::Subscriber sub = node.subscribe("turtle1/pose", 10, poseCallback); + + // Set the loop rate + ros::Rate rate(10); + ROS_INFO("Starting waypoint navigation with %zu points.", waypoints.size()); + + // Main control loop + while (ros::ok()) { + geometry_msgs::Twist msg; // Command message, all fields set to 0 initially + + // 1. Check if all waypoints have been reached + if (current_target_index >= waypoints.size()) { + ROS_INFO("All waypoints reached. Stopping."); + pub.publish(msg); // Publish 0 velocity to stop + break; // Exit the loop + } + + // 2. Calculate the distance to the current target + double dx = target_x - pos_x; + double dy = target_y - pos_y; + double distance = std::sqrt(dx * dx + dy * dy); + + // 3. Check if the target is reached + if (distance < DISTANCE_THRESHOLD) { + ROS_INFO("Waypoint %d reached: (%.2f, %.2f)", + current_target_index, target_x, target_y); + + // Advance to the next waypoint + current_target_index++; + if (current_target_index < waypoints.size()) { + target_x = waypoints[current_target_index].x; + target_y = waypoints[current_target_index].y; + } + // Stop and continue the loop to re-evaluate the distance for the new target + msg.linear.x = 0.0; + msg.angular.z = 0.0; + } else { + // 4. Calculate the desired angle to the target + double target_angle = std::atan2(dy, dx); + + // 5. Calculate the angle error + double angle_error = normalizeAngle(target_angle - theta); + + // 6. Set angular velocity (Turn towards the target) + msg.angular.z = ANGULAR_SPEED_GAIN * angle_error; + + // 7. Set linear velocity (Move forward only if we are facing the target) + // Use the absolute value of the error for comparison + if (std::abs(angle_error) < ANGLE_THRESHOLD_RAD) { + msg.linear.x = LINEAR_SPEED; + msg.angular.z = 0.0; // Stop turning while moving straight + } else { + msg.linear.x = 0.0; // Stop moving while turning + } + } + + // Publish the movement commands + pub.publish(msg); + + // Allow ROS to process events (like receiving the pose) + ros::spinOnce(); + + // Wait until the next loop cycle + rate.sleep(); + } + + return 0; +} \ No newline at end of file