• 【SE】导弹实现思路


    其实是挺久以前弄的......

      ——序

    要实现导弹,首先就是要制导。

    所以,不能傻乎乎的直接撞过去,所以我们要设计一些算法,来让他直直的撞过去!

    那么如何瞄准呢?SE提供了转向的设备(陀螺仪),相信聪明的读者已然想到!!!我们要通过陀螺仪转向,对准目标!!然后给他一炮!!!

    ......先等会,我们连如何控制转向都不知道呢(┬_┬)......

    接下来查阅资料,大佬的实验!!!https://tieba.baidu.com/p/6226176333?pn=2

    知道了陀螺仪的三个参数分别是反向的yaw,pitch,roll轴的目标角速度(科学是挺科学的...可是为啥要反过来啊啊啊啊啊)

    懂得了原理...接下来设计算法......

    显然,只要得到我们与目标的相对角度,然后算一下我们的角速度,让陀螺仪只要不能刹车了就刹车,其余时间全部加速!!!

    但是怎么获得相对角度呢......?

    原来的想法是用逆三角函数根据XZ,YZ坐标求出相应的yaw,pitch轴,但是感觉挺麻烦而且不切实际(老觉得自己的想法不行)

    于是查阅资料( 获得这篇神奇博客!!!https://www.kancloud.cn/kylilimin/mea-ship/1003204

    里面的代码,告诉了我怎么获得相对角度,它先转换世界坐标系为局部坐标系(用法线变换,说实话这玩意我也不知道是啥,矩阵变换这玩意我也不是很懂)

    然后将目标点在局部坐标系中分别投影到XZ,YZ!!!!

    这样一来就很清晰明了,实际上与我的思路差不多,但是看起来更可靠一些(

    然后用点积求平面上两向量(Z轴与投影到XZ,YZ上的标准向量)的夹角的cos(cos = |A · B| / |A|*|B| ),然后再用逆三角函数求得角......

    是不是很科学......但是经过群里的大佬点拨,其实特么的直接用逆tan就可以了!!!傻了傻了(其实用点积比较有逼格)

    这份代码中也有许多问题......不细说了,看下文。

    解决了获取相对坐标的方式,就可以求解角速度了。

    我们知道,v = Δv * t

    则 t = v / Δv (1)

    我们知道, t = s/v (2)

    我们通过垃圾K社提供的垃圾API(    ,得到飞船的角速度v,和我们求出的相对角度s,通过这个公式t1 = s/v(2),可以得到我们要走的时间!!!

    我们又可以通过将所有陀螺仪开到最大,两帧相减算出其可提供的最大角加速度 Δv,注意,这个 Δv不是目标角加速度,只是陀螺仪一帧可以达到的最大角加速度,

    所以实际上我们是不关心所谓的目标角加速度的,我们只关心一帧能有多少角加速度。

    所以,刹车时间就是 t2 = v / Δv(1),即可求得刹车时间。

    所以,我们根据得到的t1和t2,显然可以得到如下关系

    若t1 > t2,则时间足够刹车,可以尽情开动陀螺仪。

    若t1 < t2,则时间不够刹车,需要尽力反向开动陀螺仪。

    通过这两个关系的控制,我们可以控制时间是否足够刹车,也就完成了这个系统。(总感觉意犹未尽)

    上面说的博客,提供了这种算法的特点:

    1. 绝不会错过目标
    2. 获得了抵达目标的时间最优解,即在不错过的情况下,用时最短
    3. 精确无震荡
    4. 存在动态误差,而且在圆周运动时候,动态误差会逐渐扩大到无法控制的程度

    实际上,只要掌握了获取相对坐标的方法,同时记得请陀螺仪的加速是反的,其实也可以上个PID。

    另外,需要注意的是,最好使用atan2这个函数,因为atan函数的值域只有-90~90,意味着只能处理两个象限的情况。

    但是我们的目标可不会乖乖的呆在这两个象限,所以使用范围更大的atan2(-180~180)可以避免出现有两个位置拥有相同的相对角度导致不停往复。

    推进器:直接无脑上个缓冲器,把Z轴(Forward)方向的缓冲控制去掉!!!Forward方向直接越级控制拉满!!!目标如果转移就是另外上下左右四个方向的推进器的事儿了!!!!我特么直接冲!!!

    上个PID就完事儿了。

    附代码(不完善,有些许bug,之后有时间再修改)

      1 //by dudujerry
      2 //5.28.导弹
      3 
      4 
      5 //算法变量
      6 double _AimTargetRatio = 1;//精度
      7 List<Vector2D> _AimTarget_Data = new List<Vector2D>();
      8 Vector2D _MaxAngleAcceleration;//最大角加速度,X=Yaw;y=Pitch
      9 Vector2D _InitAngleVelocity;
     10 int _BeforeAim = 60;//1秒出膛
     11 int _TimeGoesBy = 0;
     12 
     13 //设备变量
     14 List<IMyGyro> _gyros = new List<IMyGyro>();
     15 List<IMyRemoteControl> _remoteControls = new List<IMyRemoteControl>();
     16 List<IMyLargeGatlingTurret> _gatlings = new List<IMyLargeGatlingTurret>();
     17 IMyRemoteControl cp;
     18 List<IMyThrust> _thrusts = new List<IMyThrust>();
     19 
     20 //实际变量
     21 MyDetectedEntityInfo _enemy = new MyDetectedEntityInfo();
     22 
     23 void SetGyros(double yaw,double pitch){
     24     
     25     foreach(var gyro in _gyros){
     26         gyro.Enabled = true;
     27         gyro.GyroOverride = true;
     28         gyro.Yaw = (float)yaw;
     29         gyro.Pitch = (float)pitch;
     30     }
     31     
     32 }
     33 
     34 Vector3D SubVector3D(Vector3D a,Vector3D b){
     35     return new Vector3D(a.X - b.X,a.Y - b.Y, a.Z - b.Z);
     36     
     37 }
     38 
     39 bool InitGyros(){//测陀螺仪最大角加速度
     40     if(_MaxAngleAcceleration.Length() != 0){
     41         //若已经测过了,返回
     42         return true;
     43     }
     44     
     45     Vector3D angularVelocity = cp.GetShipVelocities().AngularVelocity;
     46     
     47     MatrixD refLookAtMatrix = MatrixD.CreateLookAt(new Vector3D(), cp.WorldMatrix.Forward, cp.WorldMatrix.Up);
     48     Vector3D meAngleVelocityToMe = Vector3D.TransformNormal(angularVelocity, refLookAtMatrix);
     49     //(*)-
     50     double meYawAngleVelocity = meAngleVelocityToMe.Y*180/Math.PI; //当前角速度
     51     double mePitchAngleVelocity = meAngleVelocityToMe.X*180/Math.PI;
     52     //得到当前帧的角速度(*)-
     53     
     54     if(_InitAngleVelocity.Length() == 0){
     55         _InitAngleVelocity = new Vector2D(meYawAngleVelocity,mePitchAngleVelocity);
     56         
     57         //陀螺仪全开
     58         //gys.SetOnOff(true);
     59         //gys.SetOverride(true);
     60         //gys.Yaw = gys.Pitch = 60;
     61         //(*)-
     62         SetGyros(60,60);
     63     }
     64     else{
     65         _MaxAngleAcceleration = new Vector2D((meYawAngleVelocity - _InitAngleVelocity.X)*60, (mePitchAngleVelocity - _InitAngleVelocity.Y)*60);
     66         //计算最大角加速度,由于一秒60帧所以乘60
     67         
     68         //gys.SetOverride(false);
     69         //gys.Yaw = gys.Pitch = 0;
     70         //返回原状态(*)-
     71         SetGyros(0,0);
     72     }
     73     return false;
     74 }
     75 
     76 void AimTarget(Vector3D targetPosition){
     77     double yaw = 0;//陀螺仪输出
     78     double pitch = 0;
     79     
     80     
     81     MatrixD refLookAtMatrix = MatrixD.CreateLookAt(new Vector3D() , cp.WorldMatrix.Forward, cp.WorldMatrix.Up);
     82     Vector3D positionToMe = Vector3D.TransformNormal(SubVector3D(targetPosition,cp.CenterOfMass),refLookAtMatrix);//[1]-cp.Position
     83     //转换坐标系 (*)-
     84     
     85     //Echo(positionToMe.ToString());
     86     double targetYawAngle = TargetAngleToMe(positionToMe,"Yaw");
     87     double targetPitchAngle = TargetAngleToMe(positionToMe,"Pitch");
     88     
     89     Echo("A:" + ((int)targetYawAngle).ToString() + " " + ((int)targetPitchAngle).ToString());
     90     
     91     //算出基于自己坐标系的相对角度
     92     
     93     while(_AimTarget_Data.Count > 30)//周期:30
     94     {
     95         _AimTarget_Data.RemoveAt(0);
     96     }
     97     while(_AimTarget_Data.Count < 30){
     98         _AimTarget_Data.Add(new Vector2D(targetYawAngle,targetPitchAngle));
     99     }
    100     _AimTarget_Data.RemoveAt(0);
    101     _AimTarget_Data.Add(new Vector2D(targetYawAngle,targetPitchAngle));
    102     //统计误差数据
    103     
    104     double meYawAngleVelocity = cp.GetShipVelocities().AngularVelocity.Y;
    105     double mePitchAngleVelocity = cp.GetShipVelocities().AngularVelocity.X;
    106     
    107     
    108     double effectYawVelocity = (_AimTarget_Data[_AimTarget_Data.Count - 1] .X - _AimTarget_Data[_AimTarget_Data.Count - 2] .X) * 60;
    109     double effectPitchVelocity = (_AimTarget_Data[_AimTarget_Data.Count - 1] .Y - _AimTarget_Data[_AimTarget_Data.Count - 2] .Y) * 60;
    110     Echo("合速度V:" + ((int)effectYawVelocity).ToString() + " " + ((int)effectPitchVelocity).ToString());
    111     //算合速度 (*)-
    112     
    113     if(effectYawVelocity*targetYawAngle > 0){
    114         //目标角度和合速度符号不同,即正朝着目标靠近
    115         if(Math.Abs(targetYawAngle) > _AimTargetRatio){
    116             //距离目标还有距离
    117             
    118             double stopTime = Math.Abs(effectYawVelocity / _MaxAngleAcceleration.X);
    119             //刹车时间
    120             double arriveTime = Math.Abs(targetYawAngle / effectYawVelocity);
    121             //抵达目标所用时间
    122         
    123             //yaw = -60 * (targetYawAngle >= 0 ? 1 : (-1));
    124         
    125         
    126             if(stopTime <= arriveTime){
    127                 //刹车时间足够
    128                 yaw = 60 * (targetYawAngle >= 0 ? 1 : (-1));
    129                 //控制方向
    130                 Echo("刹车时间足够:是");
    131             }
    132             else{
    133                 yaw = -60 * (targetYawAngle >= 0 ? 1 : (-1));
    134                 //控制方向
    135                 Echo("刹车时间足够:否");
    136             }
    137         
    138         }
    139         else{
    140             //Echo("?:" + Math.Abs((int)targetYawAngle).ToString() +"-" + ((int)_AimTargetRatio).ToString());
    141             yaw = targetYawAngle*60/180;
    142             Echo("刹车时间足够:已到达");
    143         }
    144         
    145     }
    146     else {
    147             //正在远离目标
    148             yaw = 60 * (targetYawAngle >= 0 ? 1 : (-1));
    149             Echo("刹车时间足够:反方向");
    150     }
    151         
    152     if(effectPitchVelocity*targetPitchAngle > 0){
    153         //目标pitch速度和合速度符号不同,即正朝着目标靠近
    154         if(Math.Abs(targetPitchAngle) > _AimTargetRatio){
    155             //距离目标还有距离
    156             
    157             double stopTime = Math.Abs(effectPitchVelocity / _MaxAngleAcceleration.Y);
    158             //刹车时间
    159             double arriveTime = Math.Abs(targetPitchAngle / effectPitchVelocity);
    160             //抵达目标所用时间
    161         
    162             //pitch = -60 * (targetPitchAngle >= 0 ? 1 : (-1));
    163         
    164             if(stopTime <= arriveTime){
    165                 //刹车时间足够
    166                 Echo("刹车时间足够:是");
    167                 pitch = -60 * (targetPitchAngle >= 0 ? 1 : (-1));
    168                 //控制方向
    169             }
    170             else{
    171                 pitch = 60 * (targetPitchAngle >= 0 ? 1 : (-1));
    172                 Echo("刹车时间足够:否");
    173                 //控制方向
    174             }
    175         
    176         }
    177         else{
    178             pitch = -targetPitchAngle*60/180;
    179             Echo("刹车时间足够:已到达");
    180 
    181         }
    182         
    183     }
    184     else {
    185             //正在远离目标
    186             pitch = -60 * (targetPitchAngle >= 0 ? 1 : (-1));
    187             Echo("刹车时间足够:反方向");
    188             
    189         }
    190     Echo("Yaw:" + yaw.ToString() + " Pitch:" + pitch.ToString());
    191     
    192     //gys.SetOverride(true);
    193     //gys.Yaw = yaw;
    194     //gys.Pitch = pitch;
    195     //控制陀螺仪(*)-
    196     SetGyros(yaw,pitch);
    197     
    198     Echo("自己的V:" + ((int)meYawAngleVelocity).ToString()+((int)mePitchAngleVelocity).ToString());
    199     Echo("陀螺仪的V:" + ((int)_gyros[0].Yaw).ToString()+((int)_gyros[0].Pitch).ToString());
    200 }
    201 
    202 public static double TargetAngleToMe(Vector3D targetToMe,string direction){
    203     targetToMe = Vector3D.Normalize(targetToMe);
    204     Vector3D zForward = new Vector3D(0,0,-1);
    205     if(direction == "Yaw"){
    206         
    207         Vector3D targetYawVector = new Vector3D(targetToMe.X,0,targetToMe.Z);
    208         
    209         return Math.Atan2(targetToMe.X,targetToMe.Z) * 180/Math.PI;
    210         
    211     }
    212     else if (direction == "Pitch"){
    213         Vector3D targetYawVector = new Vector3D(0,targetToMe.Y,targetToMe.Z);
    214         return Math.Atan2(targetToMe.Y,targetToMe.Z) * 180/Math.PI;
    215         
    216         
    217     }
    218     return 0;
    219 }
    220 
    221 
    222 
    223 
    224 public Program(){
    225     Runtime.UpdateFrequency = UpdateFrequency.Update1;
    226     
    227     GridTerminalSystem.GetBlocksOfType<IMyGyro>(_gyros);
    228     GridTerminalSystem.GetBlocksOfType<IMyRemoteControl>(_remoteControls);
    229     GridTerminalSystem.GetBlocksOfType<IMyLargeGatlingTurret>(_gatlings);
    230     GridTerminalSystem.GetBlocksOfType<IMyThrust>(_thrusts);
    231     
    232     cp = _remoteControls[0];
    233     Echo("Programed");
    234     
    235 }
    236 
    237 public void ControlThrusts(){
    238     
    239     MatrixD refLookAtMatrix = MatrixD.CreateLookAt(new Vector3D() , cp.WorldMatrix.Forward, cp.WorldMatrix.Up);
    240     
    241     foreach(var thrust in _thrusts){
    242         var maxThrust = thrust.MaxEffectiveThrust;
    243         
    244         Echo("in");
    245         
    246         switch (cp.WorldMatrix.GetClosestDirection(thrust.WorldMatrix.Backward)){
    247             case Base6Directions.Direction.Forward:
    248                 thrust.ThrustOverride = maxThrust;
    249                 thrust.ThrustOverridePercentage = 1;
    250                 
    251             break;
    252             
    253             case Base6Directions.Direction.Right:
    254             
    255                 float velocity1 = (float)-(Vector3D.TransformNormal(cp.GetShipVelocities().LinearVelocity,refLookAtMatrix)).X;
    256                 thrust.ThrustOverridePercentage = (velocity1 > 0) ? velocity1 : 0; 
    257             break;
    258              
    259             case Base6Directions.Direction.Left:
    260                 float velocity2 = (float)-(Vector3D.TransformNormal(cp.GetShipVelocities().LinearVelocity,refLookAtMatrix)).X;
    261                 thrust.ThrustOverridePercentage = (velocity2 < 0) ? -velocity2 : 0; 
    262             break;
    263             
    264             case Base6Directions.Direction.Up:
    265                 float velocity3 = (float)-(Vector3D.TransformNormal(cp.GetShipVelocities().LinearVelocity,refLookAtMatrix)).Y;
    266                 thrust.ThrustOverridePercentage = (velocity3 > 0) ? velocity3 : 0; 
    267             break;
    268              
    269             case Base6Directions.Direction.Down:
    270                 float velocity4 = (float)-(Vector3D.TransformNormal(cp.GetShipVelocities().LinearVelocity,refLookAtMatrix)).Y;
    271                 thrust.ThrustOverridePercentage = (velocity4 < 0) ? -velocity4 : 0; 
    272             break;
    273         }
    274     }
    275     
    276 }
    277 
    278 
    279 public void Main(string argument, UpdateType updateSource)
    280 {
    281     if(_TimeGoesBy <= _BeforeAim)
    282         _TimeGoesBy ++;
    283     if(InitGyros() == false)
    284         return;
    285     
    286     MyDetectedEntityInfo enemy = _gatlings[0].GetTargetedEntity();
    287     //Echo(enemy.Position.ToString());
    288     if(enemy.IsEmpty() == false){
    289         _enemy = enemy;
    290     }
    291     
    292     //Echo( "rel:" + _enemy.Relationship.Enemies + _enemy.Relationship.Neutral);
    293     //&& (_enemy.Type == MyDetectedEntityType.SmallGrid || _enemy.Type == MyDetectedEntityType.LargeGrid)
    294     
    295     
    296     if(_enemy.IsEmpty() == false && _TimeGoesBy > _BeforeAim && (_enemy.Relationship == MyRelationsBetweenPlayerAndBlock.Enemies || _enemy.Relationship == MyRelationsBetweenPlayerAndBlock.Neutral) ){
    297         AimTarget(_enemy.Position);
    298         Echo("Aimed");
    299     }
    300     else if (_enemy.IsEmpty() == true)
    301     {
    302         Echo("Can't Find Entity");
    303     }
    304     //Echo(TargetAngleToMe(new Vector3D(4,2,2),"Yaw").ToString());
    305     //ControlThrusts();
    306     
    307     
    308     
    309     return;
    310 }
    神奇代码!!!

    二营长,你他娘的意大利炮呢?给我拉上来!

  • 相关阅读:
    PAT《数据结构学习与实验指导》实验项目集 2-09 2-10 2-11 2-12 2-13
    codeblocks+Mingw 下配置开源c++单元测试工具 google test
    编程之美 1.16 24点游戏
    PAT 1065 1066 1067 1068
    多线程批量执行等待全部结果
    使用Git和远程代码库
    CentOS下Crontab安装使用详细说明(转)
    安装和测试Kafka(转)
    MapReduce任务参数调优(转)
    Maven构建应用程序常用配置(转)
  • 原文地址:https://www.cnblogs.com/dudujerry/p/13059205.html
Copyright © 2020-2023  润新知