AR 마커로 TurtleSim 제어하기
2019. 10. 29. 23:05ㆍ드론
전 포스팅에 이어서 작성해보려고 한다 https://noel-embedded.tistory.com/1175
카메라에 비친 AR마커 위치에 따라서 Turtlesim이 움직이도록 하는 코드를 작성해보려고 한다
따라서, 카메라 - AR마커 alvar - 새 작성 노드 - turtlesim으로 노드 구성을 하려고 한다
터틀심 속도를 publish를 하고,

속도 제어를 하면서, 동시에 pose를 실시간으로 체크한다

회전과 병진속도는 각각 z, x 축에 의해서만 움직인다. 즉 전방은 x축, yaw는 z축을 의미한다

pose 값은 다음과 같이 발행이 된다. 왼쪽 아래는 (0, 0), 오른쪽 위는 (11, 11)이다

다음은 AR 마커 토픽에 대한 내용이다. 이 토픽을 Subscribe를 할 것이다

$ catkin_create_pkg ar_marker_tts roscpp std_msgs geometry_msgs message_generation ar_track_alvar_msgs sensor_msgs
아래 내용을 CMakeList에 추가해준다
add_executable(control src/control.cpp)
add_dependencies(control ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(control
${catkin_LIBRARIES}
)
코드는 다음과 같다. 비례상수가 맞지 않는다면 조절해서 대입할 수 있다
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ros/ros.h" | |
#include "turtlesim/Pose.h" | |
#include "std_msgs/Float64.h" | |
#include "geometry_msgs/Twist.h" | |
#include "ar_track_alvar_msgs/AlvarMarker.h" | |
#include "ar_track_alvar_msgs/AlvarMarkers.h" | |
#include <cmath> | |
#include <cstdlib> | |
#define MARKER_ID 9 | |
geometry_msgs::Twist pub_msg; | |
turtlesim::Pose goal_pose, cur_pose; | |
void poseCallback(const turtlesim::Pose::ConstPtr& msg) | |
{ | |
#if 0 | |
ROS_INFO("x : [%f]", msg->x); | |
ROS_INFO("y : [%f]", msg->y); | |
ROS_INFO("theta : [%f]", msg->theta); | |
ROS_INFO("linear_velocity : [%f]", msg->linear_velocity); | |
ROS_INFO("angular_velocity : [%f]", msg->angular_velocity); | |
#endif | |
cur_pose.x = msg->x; | |
cur_pose.y = msg->y; | |
cur_pose.theta = msg->theta; | |
} | |
void arposeCallback(const ar_track_alvar_msgs::AlvarMarkers::ConstPtr& msg) | |
{ | |
for(int i=0; i<msg->markers.size(); i++) { | |
#if 0 | |
ROS_INFO("posex : [%f]", msg->markers[i].pose.pose.position.x); | |
ROS_INFO("posey : [%f]", msg->markers[i].pose.pose.position.y); | |
ROS_INFO("posez : [%f]", msg->markers[i].pose.pose.position.z); | |
ROS_INFO("quatx : [%f]", msg->markers[i].pose.pose.orientation.x); | |
ROS_INFO("quaty : [%f]", msg->markers[i].pose.pose.orientation.y); | |
ROS_INFO("quatz : [%f]", msg->markers[i].pose.pose.orientation.z); | |
ROS_INFO("quatw : [%f]", msg->markers[i].pose.pose.orientation.w); | |
#endif | |
if( i==0 && msg->markers[i].id == MARKER_ID) { | |
float x = msg->markers[i].pose.pose.position.x; | |
float y = msg->markers[i].pose.pose.position.y; | |
if(x < -0.2) { | |
if(y < -0.15) { | |
goal_pose.x = 2.0; | |
goal_pose.y = 8.0; | |
} | |
else if(y > 0.15) { | |
goal_pose.x = 2.0; | |
goal_pose.y = 2.0; | |
} | |
else { | |
goal_pose.x = 2.0; | |
goal_pose.y = 5.5; | |
} | |
} | |
else if(x <= 0.2 && x >= -0.2) { | |
if(y < -0.15) { | |
goal_pose.x = 5.5; | |
goal_pose.y = 8.0; | |
} | |
else if(y > 0.15) { | |
goal_pose.x = 5.5; | |
goal_pose.y = 2.0; | |
} | |
else { | |
goal_pose.x = 5.5; | |
goal_pose.y = 5.5; | |
} | |
} | |
else { | |
if(y < -0.15) { | |
goal_pose.x = 8.0; | |
goal_pose.y = 8.0; | |
} | |
else if(y > 0.15) { | |
goal_pose.x = 8.0; | |
goal_pose.y = 2.0; | |
} | |
else { | |
goal_pose.x = 8.0; | |
goal_pose.y = 5.5; | |
} | |
} | |
} | |
} | |
#if 0 | |
ROS_INFO("x : [%f]", msg->x); | |
ROS_INFO("y : [%f]", msg->y); | |
ROS_INFO("theta : [%f]", msg->theta); | |
ROS_INFO("linear_velocity : [%f]", msg->linear_velocity); | |
ROS_INFO("angular_velocity : [%f]", msg->angular_velocity); | |
#endif | |
} | |
double distanceToGoal(void) { | |
return sqrt(pow((goal_pose.x-cur_pose.x), 2) + pow((goal_pose.y-cur_pose.y), 2)); | |
} | |
int main(int argc, char **argv) { | |
double x, y, tolerance; | |
ros::init(argc, argv, "control"); | |
ros::NodeHandle nh; | |
ros::Rate loop_rate(10); | |
ros::Publisher cmdvel_pub = nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 100); | |
ros::Subscriber pose_sub = nh.subscribe("/turtle1/pose", 100, poseCallback); | |
ros::Subscriber ar_pose_sub = nh.subscribe("/ar_pose_marker", 100, arposeCallback); | |
goal_pose.x = cur_pose.x = 5.544445; | |
goal_pose.y = cur_pose.y = 5.544445; | |
geometry_msgs::Twist vel; | |
vel.linear.x = 0; | |
vel.linear.y = 0; | |
vel.linear.z = 0; | |
vel.angular.x = 0; | |
vel.angular.y = 0; | |
vel.angular.z = 0; | |
cmdvel_pub.publish(vel); | |
while(ros::ok()) { | |
#if 0 | |
ROS_INFO("cur_pose.x : [%f]", cur_pose.x); | |
ROS_INFO("cur_pose.y : [%f]", cur_pose.y); | |
ROS_INFO("goal_pose.x : [%f]", goal_pose.x); | |
ROS_INFO("goal_pose.y : [%f]", goal_pose.y); | |
#endif | |
loop_rate.sleep(); | |
ros::spinOnce(); | |
double kp1 = 0.5, kp2 = 3.0; | |
double e = distanceToGoal(); | |
ROS_INFO("e : [%lf]", e); | |
while(e >= 0.1) { | |
#if 1 | |
ROS_INFO("cur_pose.x : [%f]", cur_pose.x); | |
ROS_INFO("cur_pose.y : [%f]", cur_pose.y); | |
ROS_INFO("goal_pose.x : [%f]", goal_pose.x); | |
ROS_INFO("goal_pose.y : [%f]", goal_pose.y); | |
#endif | |
vel.linear.x = kp1*e; | |
vel.linear.y = 0; | |
vel.linear.z = 0; | |
vel.angular.x = 0; | |
vel.angular.y = 0; | |
vel.angular.z = kp2*(atan2(goal_pose.y-cur_pose.y, goal_pose.x-cur_pose.x)-cur_pose.theta); | |
cmdvel_pub.publish(vel); | |
loop_rate.sleep(); | |
ros::spinOnce(); | |
e = distanceToGoal(); | |
} | |
vel.linear.x = 0; | |
vel.angular.z = 0; | |
cmdvel_pub.publish(vel); | |
} | |
return 0; | |
} |
아래 명령어를 순차적으로 실행한다
$ roscore
$ rosrun turtlesim turtlesim_node
$ roslaunch ar_marker track_marker.launch
$ rosrun uvc_camera uvc_camera_node
$ rosrun ar_marker_tts control
$ rqt_image_view


'드론' 카테고리의 다른 글
git-ssh 키 등록 후 push가 되지 않을 때 (0) | 2019.10.28 |
---|---|
ROS AR_Marker 해석하기 (0) | 2019.10.28 |
roslaunch에서의 param tag 의미 (0) | 2019.10.26 |
CUDA 8.0 + openCV 3.4.0으로 darknet YOLO 실행 (0) | 2019.10.26 |
roslaunch에서 param 설정해서 노드 제어하기 (0) | 2019.10.25 |