使用atan2()函数模拟时出现奇怪的“偏航”行为

5
我正在开发一个模拟器应用程序,其中四旋翼飞行器从航点到航点飞行。 在我的代码中,我实现了一个使用atan2函数计算yaw的函数。 但是当四旋翼飞行器转过360度时,它不会通过最短路径移动,而是绕着360度范围移动以达到新方向。

我在这里发布了一个视频。看一下它穿过360度时的行为。

好的,现在这是完整的函数:

geometry_msgs::Pose getYaw( double x1, double x2, double y1, double y2 ) {

geometry_msgs::Pose output_trajectory;

/* Extrapolate the yaw information between two contigous points */
double yaw = atan2( ( y2 - y1 ), ( x2 - x1 ) );

  if( yaw < 0.0f )  // * read later on
    yaw += 2.0f * M_PI;

 output_trajectory.orientation = tf::createQuaternionMsgFromYaw( yaw );

  return output_trajectory;
}

tf::createQuaternionMsgFromYaw是ROS框架中的一个库。这里是定义:link。 geometry_msgs :: Pose只是一个容器:link

*:我在stackoverflow上阅读了相关主题和问题,并发现此函数将atan2返回的输出映射到0°-360°

更新: 这里是yaw值的提取:

...
Yaw: 131.3678
Yaw: 133.3495
Yaw: 135.6426
Yaw: 138.3442
Yaw: 141.5859
Yaw: 145.5487
Yaw: 150.4813
Yaw: 156.7167
Yaw: 164.6657
Yaw: 174.7288
Goal reached
Moving to the 3 waypoint
Yaw: 174.7288
Yaw: 186.4225
Yaw: 196.3789
Yaw: 204.1349
Yaw: 210.1296
Yaw: 214.7946
Yaw: 218.4716
Yaw: 221.4110
Yaw: 223.7921
Yaw: 225.7431
Yaw: 227.3565
...

正如您所看到的,交叉点是“连续的”,但它从174度转到186度,而不是向右(最小)方向。

我期望的是四旋翼通过小调整和360度旋转而不是几度移动。

我该如何解决这个问题?我需要在我的应用程序中平稳的偏航运动。 谢谢。


这里你的问题不是很清楚。必须有一个交叉点。你期望什么行为? - Oliver Charlesworth
4
这段代码中的 yaw + 2.0f * M_PI; 部分没有任何意义,该值既未存储也未被使用。 - wilx
尝试这个:http://pastebin.com/7hf0U5Vu 使用方法如下:yaw = clampRadians(atan2(y2 - y1, x2 - x1)); - Brandon
1
@VáclavZeman 可能 OP 想要执行 +=。 - Borgleader
还有,为什么要通过引用传递double - wilx
显示剩余12条评论
2个回答

0

我认为 atan 不会给出正确的角度。Atan 给出 -pi/2 ~ +pi/2 的范围结果。

如果你想要得到精确的弧度角度,可能需要编写类似这样的代码(我之前就是这么做的,效果不错):

// First find the section in which your coordinate is, then add the needed (x*pi) value to result:
double result = atan2(..);
if((x2 - x1 > 0) && (y2 - y1 > 0)){
  //section = 1;
  result += 0;
}
else if((x2 - x1 < 0) && (y2 - y1 > 0)){
   //section = 2;
  result += pi;
}
else if((x2 - x1 < 0) && (y2 - y1 < 0)){
   //section = 3
  result += pi;
}
else if((x2 - x1 > 0) && (y2 - y1 > 0)){
   //section = 4
  result += 2*pi;
}
else if(x2 == x1){
    if(y2 > y1){result = pi/2);
    if(y1 > y2){result = -pi/2);
}
else if(y2 == y1){
   if(x2 > x1){result = 0;}
   if(x1 > x1){result = pi;}
}
else if((x1 == x2) && (y1 == y2)){
   std::cout << "This is not line, just a point\n"; // :P
}

抱歉,Kobay,但我不认为atan2是问题的根源:( 角度没问题,我觉得问题出在其他地方。 - Dave
希望你能找到答案。 - gokaysatir
如果我没记错的话,你正在尝试将路线切成相等的部分。如果第一对x-y坐标计算错误怎么办? - gokaysatir
:) 好的...那不是问题,因为调用我在这里发布的内容的函数会处理给定点的正确顺序。我现在非常确定问题不在我的代码中。 - Dave

0

好的。 我明白了。 经过数小时的调查,我意识到问题与atan2()函数或角度跨越180°或360°时的符号变化无关。

仔细阅读以下代码作为示例

#include <string>
#include <ros/ros.h>
#include <sensor_msgs/JointState.h>
#include <tf/transform_broadcaster.h>

int main(int argc, char** argv) {
    ros::init(argc, argv, "state_publisher");
    ros::NodeHandle n;
    ros::Publisher joint_pub = n.advertise<sensor_msgs::JointState>("joint_states", 1);
    tf::TransformBroadcaster broadcaster;
    ros::Rate loop_rate(30);

    const double degree = M_PI/180;

    // robot state
    double tilt = 0, tinc = degree, swivel=0, angle=0, height=0, hinc=0.005;

    // message declarations
    geometry_msgs::TransformStamped odom_trans;
    sensor_msgs::JointState joint_state;
    odom_trans.header.frame_id = "odom";
    odom_trans.child_frame_id = "axis";

    while (ros::ok()) {
        //update joint_state
        joint_state.header.stamp = ros::Time::now();
        joint_state.name.resize(3);
        joint_state.position.resize(3);
        joint_state.name[0] ="swivel";
        joint_state.position[0] = swivel;
        joint_state.name[1] ="tilt";
        joint_state.position[1] = tilt;
        joint_state.name[2] ="periscope";
        joint_state.position[2] = height;


        // update transform
        // (moving in a circle with radius=2)
        odom_trans.header.stamp = ros::Time::now();
        odom_trans.transform.translation.x = cos(angle)*2;
        odom_trans.transform.translation.y = sin(angle)*2;
        odom_trans.transform.translation.z = .7;
        odom_trans.transform.rotation = tf::createQuaternionMsgFromYaw(angle+M_PI/2);

        //send the joint state and transform
        joint_pub.publish(joint_state);
        broadcaster.sendTransform(odom_trans);

        // Create new robot state
        tilt += tinc;
        if (tilt<-.5 || tilt>0) tinc *= -1;
        height += hinc;
        if (height>.2 || height<0) hinc *= -1;
        swivel += degree;
        angle += degree/4;

        // This will adjust as needed per iteration
        loop_rate.sleep();
    }


    return 0;
}

我在这里发现,变量angle每次增加一小部分后就传递给四元数库tf::createQuaternionMsgFromYaw()

这意味着两件事情:
  1. 您从未考虑过跨越180°或360°的跳跃;
  2. 更重要的是,您从未传递绝对角度。例如,您从未在代码中调用tf::createQuaternionMsgFromYaw(degtorad(179)),然后再调用tf::createQuaternionMsgFromYaw(degtorad(182)),而是使用tf::createQuaternionMsgFromYaw(angle + delta_angle)。

此致


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接