不知道你是什么坐标系
我的猜测是你的地面是平面的(由你的常数引起,但你的位置暗示了其他东西)......所以我现在会坚持下去......你有两个问题:
-
牛顿/达朗贝尔物理学
你的很奇怪,因为你没有 dt 乘法,所以它只有在你的更新为 1 Hz 时才有效。看看这个:
您不需要限速器,因为空气摩擦会为您做到这一点,如果您也想考虑质量变化,您应该加速驾驶......或者 Force。
但是,当您使用地面/地面时,我假设大气飞行而不是牛顿飞行,因此在这种情况下,您需要通过转动积分速度而不是加速度来处理航向控制。主推进器仍应作为加速度处理。
在您的情况下不需要碰撞(除非您的地面不是平面或沿途有障碍物)。
-
火箭引导系统
我建议使用三态(马尔可夫模型)火箭控制。
-
启动
首先将火箭升到安全高度以避开障碍物、节省燃料并最大限度地提高速度
-
巡航
前往目标区域(同时保持其高度)。只需计算投影在地平面上的航向,并对火箭航向进行校正以匹配它(仍然平行于地面)。
-
命中
下降时击中目标。几乎和#2一样,但这次你也需要改变高度...
除此之外,您还可以添加策略来避免检测/破坏或障碍物等...您还可以从不同的航向伪造方法以隐藏发射位置...
这里是这种方法的一个简单 C++ 示例:
//---------------------------------------------------------------------------
void vector_one(double *c,double *a)
{
double l=sqrt((a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2]));
if (l>1e-10) l=1.0/l; else l=0.0;
c[0]=a[0]*l;
c[1]=a[1]*l;
c[2]=a[2]*l;
}
//---------------------------------------------------------------------------
// Z=0 plane is ground, Z+ is up
const double g=9.81; // [m/s^2] Earth's gravity
const double acc0=20.0; // [m/s^2] rocket main thruster acceleration
const double kv2 =0.002; // [-] rocket air friction coeff (speed limiter)
const double alt0=50.0; // [m] rocket safe altitude
const double dis0=100.0; // [m] rocket safe distance to target
const double dis1= 10.0; // [m] rocket explosion distance to target
const double dang0=375.0*M_PI/180.0;// [rad/s] rocket turn speed per yaw/roll/pitch
// Rocket
double dst[3]={+90.0,-50.0,0.0}; // [m] target position
double pos[3]={-100.0,200.0,0.0}; // [m] rocket position
double vel[3]={ 0.0, 0.0,0.0}; // [m/s] rocket velocity
double acc[3]={ 0.0, 0.0,0.0}; // [m/s^2] rocket acceleration
enum{
_state_none=0,
_state_launch, // rise to alt0
_state_cruise, // get near target but maintain alt0
_state_hit, // descend and hit
};
int state=_state_launch;
void update(double dt) // update rocket after dt [sec] has passed
{
int i;
double v,a,hdg[3],tar[3];
// guiding system
if (state==_state_none)
{
for (i=0;i<3;i++) vel[i]=0.0;
for (i=0;i<3;i++) acc[i]=0.0;
return;
}
if (state==_state_launch)
{
// init heading to Up
for (i=0;i<3;i++) hdg[i]=0.0; hdg[2]=1.0;
if (pos[2]>=alt0) state=_state_cruise;
}
v=sqrt((vel[0]*vel[0])+(vel[1]*vel[1])+(vel[2]*vel[2]));// |vel|
if ((state==_state_cruise)||(state==_state_hit))
{
vector_one(hdg,vel); // heading
for (i=0;i<3;i++) tar[i]=dst[i]-pos[i]; // to target
a=sqrt((tar[0]*tar[0])+(tar[1]*tar[1])+(tar[2]*tar[2])); // distance to target
if (state==_state_cruise)
{
tar[2]=0; // no altitude change
if (a<=dis0) state=_state_hit;
}
else{
if (a<=dis1) state=_state_none; // here you shoul add exlosion code
}
vector_one(tar,tar);
// a = angle between hdg and tar [rad]
for (a=0.0,i=0;i<3;i++) a+=hdg[i]*tar[i];
a=fabs(acos(a));
// approximate turn up to dang0
if (a>1e-10) a=dt*dang0/a; else a=0.0;
for (i=0;i<3;i++) hdg[i]=hdg[i]+a*(tar[i]-hdg[i]);
vector_one(hdg,hdg); // new heading
for (i=0;i<3;i++) vel[i]=v*hdg[i]; // new vel
}
// physics
for (i=0;i<3;i++) acc[i] =-kv2*vel[i]*v; // air friction (k*|vel|^2)
for (i=0;i<3;i++) acc[i]+=hdg[i]*acc0; // rocket thrust
acc[2]-=g; // gravity
// Newton/D'Alembert simulation
for (i=0;i<3;i++) vel[i]+=acc[i]*dt;
for (i=0;i<3;i++) pos[i]+=vel[i]*dt;
}
//---------------------------------------------------------------------------
您可能需要稍微调整常量以匹配您的尺寸和游戏需求。如您所见,您可以自定义很多火箭,非常适合游戏(技术升级)。
物理学是直截了当的 Newton/D'Alembert(除了 vel 因机翼而转向),并且引导系统按上述方式工作。在第一种状态下,火箭刚刚上升到alt0,然后它尝试以dang0 的转弯速度转向目标,同时保持高度,当接近dis0 时它也开始下降。如果比dis1 更近,火箭应该会爆炸......
这里预览(顶视图):
白线是距离地面的线,用于验证火箭的高度......火箭是蓝色的,目标是红色的。
车削数学是这样的:
所以我只是将tar-hdg 缩放到大致匹配dang0*dt 并将其添加到原始hdg。现在新航向转向目标最多dang0*dt 所以我将它归一化回单位大小并重新计算这个新方向的速度(因为机翼正在转动速度而不是加速)
注意单位
所有使用的单位必须兼容我使用的是SI。您的9.81 常量建议相同,但如果以米为单位,您的位置和目标值毫无意义......如果目标距离只有几米远,为什么要发射火箭?此外,这些值表明您的坐标不是笛卡尔坐标,或者地面不是平面/平面。这些值还建议整数希望你有浮点数/双精度数...