728x90
1. Using nav_msgs/Odometry
=> Publishing odometry information over ROS
reference: http://wiki.ros.org/navigation/Tutorials/RobotSetup/Odom
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>
int main(int argc, char** argv){
ros::init(argc, argv, "odometry_publisher");
ros::NodeHandle n;
ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50);
tf::TransformBroadcaster odom_broadcaster;
double x = 0.0;
double y = 0.0;
double th = 0.0;
double vx = 0.1;
double vy = -0.1;
double vth = 0.1;
ros::Time current_time, last_time;
current_time = ros::Time::now();
last_time = ros::Time::now();
ros::Rate r(1.0);
while(n.ok()){
ros::spinOnce(); // check for incoming messages
current_time = ros::Time::now();
//compute odometry in a typical way given the velocities of the robot
double dt = (current_time - last_time).toSec();
double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
double delta_th = vth * dt;
x += delta_x;
y += delta_y;
th += delta_th;
//since all odometry is 6DOF we'll need a quaternion created from yaw
geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);
//first, we'll publish the transform over tf
geometry_msgs::TransformStamped odom_trans;
odom_trans.header.stamp = current_time;
odom_trans.header.frame_id = "odom";
odom_trans.child_frame_id = "base_link";
odom_trans.transform.translation.x = x;
odom_trans.transform.translation.y = y;
odom_trans.transform.translation.z = 0.0;
odom_trans.transform.rotation = odom_quat;
//send the transform
odom_broadcaster.sendTransform(odom_trans);
//next, we'll publish the odometry message over ROS
nav_msgs::Odometry odom;
odom.header.stamp = current_time;
odom.header.frame_id = "odom";
//set the position
odom.pose.pose.position.x = x;
odom.pose.pose.position.y = y;
odom.pose.pose.position.z = 0.0;
odom.pose.pose.orientation = odom_quat;
//set the velocity
odom.child_frame_id = "base_link";
odom.twist.twist.linear.x = vx;
odom.twist.twist.linear.y = vy;
odom.twist.twist.angular.z = vth;
//publish the message
odom_pub.publish(odom);
last_time = current_time;
r.sleep();
}
}
2. Using cmd_vel
example => If it meets obstacle, turn right.
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <std_msgs/Float32.h>
#include <std_msgs/Int32.h>
#include <nav_msgs/Odometry.h>
ros::Publisher cmd_vel_publisher;
geometry_msgs::Twist cmd_vel;
double current_x,current_y,current_ori_z,current_ori_w;
float laser_distance;
void pose_callback(const nav_msgs::Odometry data)
{
current_x = data.pose.pose.position.x;
current_y = data.pose.pose.position.y;
current_ori_z = data.pose.pose.orientation.z;
current_ori_w = data.pose.pose.orientation.w;
//ROS_INFO("x:%lf y:%lf z:%lf",current_x,current_y,current_ori_z);
}
void laser_distance_callback(const std_msgs::Float32 msg)
{
laser_distance = msg.data;
}
int rotation()
{
ROS_INFO("rotate!");
cmd_vel.linear.x = 0;
cmd_vel.linear.y = 0;
cmd_vel.linear.z = 0;
cmd_vel.angular.x = 0;
cmd_vel.angular.y = 0;
cmd_vel.angular.z = 1;
ros::Rate rate(10);
double time = 0;
while(time<1.57)
{
cmd_vel_publisher.publish(cmd_vel);
time += 0.1;
rate.sleep();
}
return 0;
}
int go()
{
ROS_INFO("go!");
cmd_vel.linear.x = 0.1;
cmd_vel.linear.y = 0.1;
cmd_vel.linear.z = 0;
cmd_vel.angular.x = 0;
cmd_vel.angular.y = 0;
cmd_vel.angular.z = 0;
cmd_vel_publisher.publish(cmd_vel);
}
int main(int argc, char** argv){
ros::init(argc, argv, "simple_navigation_goals");
ros::NodeHandle n;
cmd_vel_publisher = n.advertise<geometry_msgs::Twist>("/cmd_vel",100,true);
ros::Subscriber pose_sub = n.subscribe("/t265/odom/sample",10, pose_callback);
ros::Subscriber min_distance_sub = n.subscribe("/min_distance",10, laser_distance_callback);
while(ros::ok()){
ROS_INFO("laser_distance: %f curreent_ori_z: %lf",laser_distance,current_ori_z);
go();
if(laser_distance>0 && laser_distance < 40){
rotation();
}
ros::spinOnce(); //callback
}
return 0;
}
3. using move_base
example => using send() on move_base.
straight(X) => foward X meter
turn_right() => turn right
turn_left() => turn left
#include <ros/ros.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <actionlib/client/simple_action_client.h>
typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;
void straight(double m)
{
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
goal.target_pose.header.frame_id = "base_link";
goal.target_pose.header.stamp = ros::Time::now();
goal.target_pose.pose.position.x = m;
goal.target_pose.pose.orientation.w = m;
ROS_INFO("Sending goal");
ac.sendGoal(goal);
ac.waitForResult();
if(ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
ROS_INFO("Hooray, the base moved 0.5 meter forward");
else
ROS_INFO("The base failed to move forward 0.5 meter for some reason");
}
void turn_left()
{
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
goal.target_pose.header.frame_id = "base_link";
goal.target_pose.header.stamp = ros::Time::now();
goal.target_pose.pose.orientation.y = 0.0;
goal.target_pose.pose.orientation.z = 0.53;
goal.target_pose.pose.orientation.w = 0.5;
ROS_INFO("Sending goal");
ac.sendGoal(goal);
ac.waitForResult();
if(ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
ROS_INFO("Hooray, the base turned left");
else
ROS_INFO("The base failed to turn left for some reason");
}
void turn_right()
{
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
goal.target_pose.header.frame_id = "base_link";
goal.target_pose.header.stamp = ros::Time::now();
goal.target_pose.pose.orientation.z = -0.53;
goal.target_pose.pose.orientation.w = 0.5;
ROS_INFO("Sending goal");
ac.sendGoal(goal);
ac.waitForResult();
if(ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
ROS_INFO("Hooray, the base turned right");
else
ROS_INFO("The base failed to turn left for some reason");
}
int main(int argc, char** argv){
ros::init(argc, argv, "simple_navigation_goals");
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
straight(2.5);
turn_right();
straight(0.5);
turn_right();
straight(1);
turn_left();
straight(0.5);
turn_left();
straight(1);
turn_right();
straight(0.5);
turn_right();
straight(0.5);
turn_left();
straight(0.5);
turn_left();
straight(2);
return 0;
}
3-2 Using tf2::Quaternion quat
It's not running. But good for reference.
#include <ros/ros.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <actionlib/client/simple_action_client.h>
#include <tf2/LinearMath/Quaternion.h>
typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;
void straight(double m)
{
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
goal.target_pose.header.frame_id = "map";
goal.target_pose.header.stamp = ros::Time::now();
goal.target_pose.pose.position.x = m;
goal.target_pose.pose.orientation.w = m;
ROS_INFO("Sending goal");
ac.sendGoal(goal);
ac.waitForResult();
if(ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
ROS_INFO("Hooray, the base moved 0.5 meter forward");
else
ROS_INFO("The base failed to move forward 0.5 meter for some reason");
}
void turn_right()
{
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
goal.target_pose.header.frame_id = "map";
goal.target_pose.header.stamp = ros::Time::now();
tf2::Quaternion quat;
quat.setRPY(0,0,1.5708);
goal.target_pose.pose.orientation.x = quat.x();
goal.target_pose.pose.orientation.y = quat.y();
goal.target_pose.pose.orientation.z = quat.z();
goal.target_pose.pose.orientation.w = quat.w();
ROS_INFO("Sending goal");
ac.sendGoal(goal);
ac.waitForResult();
if(ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
ROS_INFO("Hooray, the base turned right");
else
ROS_INFO("The base failed to turn right for some reason");
}
int main(int argc, char** argv){
ros::init(argc, argv, "simple_navigation_goals");
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
//straight(2.5);
turn_right();
//straight(0.5);
return 0;
}
3-3 uisng poseStamped
It's not running. But good for reference too.
#include <ros/ros.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <actionlib/client/simple_action_client.h>
#include <tf2/LinearMath/Quaternion.h>
#include <geometry_msgs/PoseStamped.h>
typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;
void straight(double m)
{
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
goal.target_pose.header.frame_id = "map";
goal.target_pose.header.stamp = ros::Time::now();
goal.target_pose.pose.position.x = m;
goal.target_pose.pose.orientation.w = m;
ROS_INFO("Sending goal");
ac.sendGoal(goal);
ac.waitForResult();
if(ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
ROS_INFO("Hooray, the base moved 0.5 meter forward");
else
ROS_INFO("The base failed to move forward 0.5 meter for some reason");
}
void turn_right()
{
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
goal.target_pose.header.frame_id = "map";
goal.target_pose.header.stamp = ros::Time::now();
geometry_msgs::PoseStamped poseStamped;
poseStamped.header.frame_id = "map";
poseStamped.pose.orientation.z = 0.707;
poseStamped.pose.orientation.w = 0.707;
goal.target_pose = poseStamped;
ROS_INFO("Sending goal");
ac.sendGoal(goal);
ac.waitForResult();
if(ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
ROS_INFO("Hooray, the base turned right");
else
ROS_INFO("The base failed to turn left for some reason");
}
int main(int argc, char** argv){
ros::init(argc, argv, "simple_navigation_goals");
//tell the action client that we want to spin a thread by default
MoveBaseClient ac("move_base", true);
//wait for the action server to come up
while(!ac.waitForServer(ros::Duration(5.0))){
ROS_INFO("Waiting for the move_base action server to come up");
}
move_base_msgs::MoveBaseGoal goal;
//straight(2.5);
turn_right();
//straight(0.5);
return 0;
}
728x90
'ROS' 카테고리의 다른 글
[ROS] BNO055 IMU with I2C (0) | 2023.02.14 |
---|---|
[ROS] How to use RPLidar (0) | 2023.02.12 |
[ROS] full coverage path planning (0) | 2023.02.09 |
[ROS] custom msg (0) | 2023.02.01 |
[ROS] rviz 없이 navigation (0) | 2023.01.20 |