C程序,从旋转角度获取笛卡尔坐标

3
我好像已经在业务应用程序上工作太长时间了...或许毕业也很久了 :) 最近,我被分配使用C语言编写一个小型机器人模拟(尽管这个问题更多涉及数学/算法而非C语言),其中有两个单位(坦克机器人)从玩耍场的X和Y坐标开始。
现在面板上有旋转它们的键,以及向前移动它们的键。我现在面临着将旋转角度转换为笛卡尔平面上下一个X,Y坐标的微小脑部崩溃。
由于硬件限制,只能使用固定点进行实际移动,但可以通过浮点值进行计算。
我刚才只是凭记忆写了以下代码:
/* Recalculate to radians */

int radians;



/* Use sin and cos to get a vector (new x and y coords). Translate from polar to   
   cartesian coordinates */
radians = (int) _tanks[0].rotationAngle * (M_PI / 180);
_tanks[0].x += _tanks[0].speed * cos(radians);
_tanks[0].y += _tanks[0].speed * sin(radians);

radians = (int) _tanks[1].rotationAngle * (M_PI / 180);
_tanks[1].x += _tanks[1].speed * cos(radians);
_tanks[1].y += _tanks[1].speed * sin(radians);

很不幸,似乎在写纯商业软件这么多年后,我的大脑并没有真正记忆极坐标数学和几何学,所以它似乎不能按预期工作。
例如,如果旋转角度为180度,则下一个x/y会向左移动,导致机器人翻倒 :)
我想要的是一种类似于旧版微型机器游戏的移动方案,如果您还记得,下一个点将位于对象面对的位置前面,因此它会向那里移动(速度)数量的步骤。
有人能建议我出错了吗...
此外,如果使用C进行此操作比我刚才编写的纯数学尝试更平稳,请给我提示。
编辑:
尝试添加:
 float radians;


 radians = (45 - _tanks[0].rotationAngle) * (M_PI / 180);
 _tanks[0].x += (int) (_tanks[0].speed * cos(radians));
 _tanks[0].y += (int) (_tanks[0].speed * sin(radians));

根据下面的答案,0度确实是正Y轴。但这也会导致错误的结果。现在,以180度为起点的移动是向左上方的。在180度时,应该沿着负Y轴移动。
更多代码:
_tank结构体的初始化 -
tanks[0].acc = 0;
tanks[0].dec = 0;
tanks[0].rotationAngle = 180;
tanks[0].speed = 0;
tanks[0].x = 400;
tanks[0].y = 150;
tanks[0].turretRotationAngle = 180;

旋转度数只是一个固定整数,我会根据360度的圆形将其包装起来,就像这样 -
switch(direction) {
case 0:
    tank->rotationAngle -= degrees;
    if(tank->rotationAngle < 1) {
        tank->rotationAngle = 360;
    }
break;
case 1:
    tank->rotationAngle += degrees;
        if(tank->rotationAngle > 360) {
        tank->rotationAngle = 0;
    }
break;

}

有一个用于顺时针旋转的按键,一个用于逆时针旋转。

旋转功能正常,但移动却不行,如所描述...

调试运行结果:

初始状态(由于速度为0而没有移动) -

radians = -2.3561945
x = 400
y = 150 
speed = 0

移动后(速度>0) -
radians = -2.3561945 (the same since i only press the move button)
x = 399
y = 149 
speed = 2

这似乎很奇怪。如果旋转角度为180度,X坐标不应该改变,对吧?只有Y坐标会改变,并且是相反的方向。我建议将更改翻译为:如果速度为2,则向量长度应为2,因此在物体面向的方向上,更改应为2步,即y = y + 2,x = x + 0,对于物体的180度旋转?
我感觉我接近成功了 :)
进一步编辑:
如果我这样做,似乎几乎符合我在游戏场地中所需要的要求:
 radians = (_tanks[0].rotationAngle - 90) * (M_PI / 180);

注意:-90...
即使速度降低,它似乎仍会出现故障,但至少它朝着正确的方向移动。

2
"radians" 将是一个介于 0 和 2PI 之间的数字,即 0 到 6.28。因此,radians 必须是一个浮点数。 - user3386109
旋转角度为180度时,下一个x/y应该向左。你期望什么?cos(180度)= -1,sin(180度)=0。 - Henrik Carlqvist
...这似乎是代码中唯一的功能问题。您还可以考虑使用“double”,因为“M_PI”等于1。 - Tommy
单步执行代码并查看“radians”的值。正如@user3386109已经指出的那样,“int”值不会很好地工作。如果您无法单步执行,请添加“printf()”语句以查看计算过程中的值。当您知道这些值时,它将帮助您弄清代码为什么没有按照您的预期运行。 - steveha
2个回答

4
例如,如果旋转角度为180,则下一个x / y将移到左侧,导致机器人翻倒 :)。
是的,这就是你的代码所做的:除了user3386109上面提到的int弧度问题之外,你的代码是正确的,前提是0°是正x轴,90°是正y轴,180°是负x轴,270°(或-90°)是负y轴。
我猜你想要0°成为正y轴?并且- 你想让90°成为正x轴(因此你的角度沿着圆形顺时针进行),还是负x轴(因此它们逆时针进行)?对于前者(顺时针)情况,只需将_tanks [ ...]。rotationAngle更改为(90- _tanks [ ...]。rotationAngle)(以“翻转”45°线);对于后者(逆时针)情况,只需将其更改为(_tanks [ ...]。rotationAngle + 90)(以关于原点旋转90°)。

尝试按以下方式更改,但仍然无法工作...在问题中添加了一些代码。 - Richard Tyregrim
弧度 = (_tanks[0].rotationAngle - 90) * (M_PI / 180);这似乎给出了我需要的正确路径移动,但在速度转换时会有一些小问题... 但现在它沿着所需的对象路径移动... 只是通过试验,我记得为什么-90是正确的对齐值。 - Richard Tyregrim
@RichardEriksson:非常抱歉,我犯了一个愚蠢的错误:要将图像“翻转”到45°线的另一侧,需要从“90”中减去,而不是从“45”中减去!我已经纠正了我的答案。 - ruakh
现在我终于成功纠正了最后的小故障...现在似乎可以正常工作了,只要我在我的常规快速台式电脑上保持一些计算时间的限制,移动更新现在似乎是正确的。将其标记为已接受的答案。 - Richard Tyregrim

1

@ruakh 和 @user3386109 将讨论有关角度单位和相位的问题。

此外,为了实现更加流畅的C语言编程方式,请考虑:

  1. Use round(), else code will introduce a bias. (Assuming _tanks[1].x is some integer)

    double radians = _tanks[0].rotationAngle * (M_PI / 180);
    _tanks[0].x += (int) round(_tanks[0].speed * cos(radians));
    
  2. Use float rather than double as the extra precision with its longer calculation time are not needed.

    float radians = _tanks[0].rotationAngle * (float)((M_PI / 180));
    _tanks[0].x += (int) roundf(_tanks[0].speed * cosf(radians));  // note function names
    
  3. If processing time is limited, an integer look-up-table could be used with 360 int scaled sine and cosine values rather than all the floating point math.

    _tanks[0].x += (_tanks[0].speed * LUT_cos[_tanks[0].rotationAngle])/scale;
    

一旦我把基础部分搞定了,我就会研究这个问题。处理时间确实相当有限,在我正在编写的模拟中不是问题,但在实际的硬件上会有所不同。查找的想法似乎是一个不错的折衷方案。 - Richard Tyregrim
了解 .speed.x.rotationAngle的范围等细节将会有所帮助。建议将它们发布出来。 - chux - Reinstate Monica
速度范围(每步的移动距离,速度)在游戏场地上是0-4个单位。X、Y轴的范围为800x600,在计算机模拟部分没有负数(原点0,0位于模拟游戏场地的左上角)。旋转角度的范围是一个完整的圆,从0到360。实际步骤代码中不使用小数,因为后面的硬件将缺乏对它的支持(伺服控制器单元)。然而,它们支持32位整数。 - Richard Tyregrim

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