支架仿真系统的实现

耗时一个多月,完成了放顶煤、薄煤层液压支架仿真程序的编写。

主要思想:

偶也是菜鸟,刚开始想用骨骼动画实现,但是没有人可给帮我做机械的骨骼动画,只好放弃。

第二种思路,想用Max导出的关键帧动画来实现,每个支架有非常多的动作,十几种,每种动作与其他动作都有可能同时发生,用Max做好关键帧动画之后,导出时分段导出动画,对每个动作分别进行导出,导出后导入程序,当两个动作同时播放时发现模型裂了,如图:2011072200023481,纠结起原因,读OgreMax导入场景的代码,发现当播放两个动作时,此时模型的每个mesh都做了两次位移、旋转、等等,肯定会裂开,同时播放几个动画,此时模型就会位移几次~~,研究了将近一周的时间,美工没有用过OgreMax,加上我是个菜鸟~~最后多方求友,不得不放弃,(如果那位网友知道如何避免这个问题,请不吝赐教)。

最后不得不采用控制节点,使用节点动画来实现,通过一个controller来实现,因为最终模型需要通过硬件来控制,控制器与PC是通过串口进行通讯的,所以本程序共分为三个部分:

1、通讯部分

           通过串口,不同的支架传输不同字节长度的数据,根据数据的某一位控制支架做相应的动作。在数据传输过程中使用CRC校验。

示例代码如下:

   1: unsigned short CRC16(unsigned char * puchMsg, unsigned short usDataLen)
   2: {
   3:     unsigned char uchCRCHi = 0xFF ; /* 高CRC 字节初始化 */
   4:     unsigned char uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
   5:     unsigned uIndex ; /* CRC 循环中的索引 */
   6:     while (usDataLen--) /* 传输消息缓冲区 */
   7:     {
   8:         uIndex = uchCRCHi ^ *(puchMsg++) ; /* 计算CRC */
   9:         uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
  10:         uchCRCLo = auchCRCLo[uIndex] ;
  11:     }
  12:     return (uchCRCHi << 8 | uchCRCLo) ;
  13: }
  14:  
  15: //构造液压支架通信命令
  16: int make_support_command(const char * buf, int cnt, std::vector<char>& result)
  17: {
  18:     result.resize(cnt+3);
  19:     result[0] = 0xaf;
  20:  
  21:     memcpy(&result[1], buf, cnt);
  22:  
  23:     unsigned short crc = CRC16((unsigned char *)&result[0], cnt+1);
  24:     result[cnt + 1] = crc >> 8;
  25:     result[cnt + 2] = crc & 0xff;
  26:  
  27:     return cnt+3;
  28: }
  29:  
  30: //CRC校验
  31: int check_support_command(const char * buf, int cnt, std::vector<char>& result)
  32: {
  33:     //if(cnt != 9)
  34:     //{
  35:     //    TRACE(_T("数据长度错误!\n"));
  36:     //    //AfxMessageBox(_T("数据长度错误!"));
  37:     //}
  38:  
  39:     unsigned short recv_crc = CRC16((unsigned char *)(buf+0), cnt-2);
  40:     unsigned short send_crc = *((unsigned char *)(buf+1 + cnt-3));
  41:     send_crc <<= 8;
  42:     send_crc |= *((unsigned char *)(buf+2 + cnt-3));
  43:     if(send_crc != recv_crc)
  44:     {
  45:         TRACE(_T("校验码错误!\n"));
  46:         //AfxMessageBox(_T("校验码错误!"));
  47:         return -1;
  48:     }
  49:  
  50:     result.resize(cnt-3);
  51:     memcpy(&result[0], buf+1, cnt-3);
  52:  
  53:     return cnt-3;
  54: }

2、支架组装,定义部分

   此部分将支架组装,使用了一种极其笨拙的方法,将支架的各个部分使用OgreMax导出后,然后根据OgreMax导出的scene文件的坐标值,然后在程序中组装支架。定义的变量相当繁琐,有很大缺陷,当换一个支架的时候,程序的数据需要重写。就是根据支架的结构创建支架,将支架的各个部分一一组装起来。代码如下:

   1: mSupportRoot = mSManager->getRootSceneNode()->createChildSceneNode(mName);
   2:     mFulcrum     = mSupportRoot->createChildSceneNode(mName + "supportFulrum", Vector3(0, 0, 0));
   3:  
   4:     //推溜节点
   5:     mMoveSupport = mSupportRoot->createChildSceneNode(mName + "moveSupport", Vector3(-1.18005, 0.115254, 0));
   6:     Entity *e = mSManager->createEntity(mName + "moveSupport", "TSmoveSupport.mesh");
   7:     mMoveSupport->attachObject(e);
   8:  
   9:     mScraper = mMoveSupport->createChildSceneNode(mName + "scraper", Vector3(-1.03653, -0.0424172, 0));
  10:     e = mSManager->createEntity(mName + "scraper", "TSscraper.mesh");
  11:     mScraper->attachObject(e);
  12:     mScraper->setVisible(mIsShowScraper);
  13:  
  14:     //底座节点
  15:     mBase = mFulcrum->createChildSceneNode(mName + "supportBase");
  16:     e = mSManager->createEntity(mName + "base", "TSbase.mesh");
  17:     mBase->attachObject(e);
  18:     mBasePillar = mBase->createChildSceneNode(mName + "basePillar", Vector3(-1.05936, 0.141, 0));
  19:  
  20:     //抬底节点
  21:     mLiftBase = mFulcrum->createChildSceneNode(mName + "liftBase", Vector3(-1.26348, 0.30187, 0));
  22:     e = mSManager->createEntity(mName + "liftBase", "TSliftBase.mesh");
  23:     mLiftBase->attachObject(e);
  24:  
  25:     //下立柱节点
  26:     mDownPillar = mBase->createChildSceneNode(mName + "downPillar", Vector3(-1.07193, 0.538018, 0));
  27:     e = mSManager->createEntity(mName + "downPillar", "TSdownPillar.mesh");
  28:     mDownPillar->attachObject(e);
  29:     mDownPillar->setOrientation(0.989742, 0, 0, 0.142869);
  30:  
  31:     //上立柱节点
  32:     //mUpPillar = mDownPillar->createChildSceneNode(mName + "upPillar", Vector3(-0.13854,0.961672, 0));
  33:     //mUpPillar = mDownPillar->createChildSceneNode(mName + "upPillar", Vector3(0, 0.961672, 0));
  34:     mUpPillar = mDownPillar->createChildSceneNode(mName + "upPillar", Vector3(0, 1.181672, 0));
  35:     e = mSManager->createEntity(mName + "upPillar", "TSupPillar.mesh");
  36:     mUpPillar->attachObject(e);
  37:     //mUpPillar->setOrientation(0.997184, 0, 0, 0.0749965);
  38:  
  39:     //顶梁节点
  40:     mTopBeamAxis  = mUpPillar->createChildSceneNode(mName + "topBeamAxis", Vector3(0.00674, -0.00362, 0));
  41:     mTopBeamAxis->roll(Radian(Math::DegreesToRadians(-17)));
  42:     mTopBeam      = mTopBeamAxis->createChildSceneNode(mName + "topBeam");
  43:     mTopPillar    = mUpPillar->createChildSceneNode(mName + "topPillar");
  44:     //mTopBeamTrack = mTopBeamAxis->createChildSceneNode(mName + "topBeamTrack", Vector3(0.915483, -0.10226, 0));
  45:     mTopBeamTrack = mTopBeamAxis->createChildSceneNode(mName + "topBeamTrack", Vector3(/*0.915483*/0.715483, -0.10226, 0));
  46:     //e = mSManager->createEntity("TStopTarget", "ninja.mesh");
  47:     //mTopBeamTrack->attachObject(e);
  48:     //mTopBeamTrack->setScale(0.001, 0.001, 0.001);
  49:     e = mSManager->createEntity(mName + "topBeam", "TStopBeam.mesh");
  50:     mTopBeam->attachObject(e);
  51:  
  52:     //恻护节点
  53:     mSideGuard = mTopBeam->createChildSceneNode(mName + "sideGurad", Vector3(-0.00456, -0.00654, 0));
  54:     e = mSManager->createEntity(mName +"sideGuard", "TSsideGuard.mesh");
  55:     mSideGuard->attachObject(e);
  56:  
  57:     //平衡千斤顶顶梁部分
  58:     mShieldJack2Axis = mTopBeam->createChildSceneNode(mName + "shiledJack2Axis", Vector3(0.435347, -0.00176, 0));
  59:     mShieldJack2Axis->setInheritOrientation(false);
  60:     mShieldJack2 = mShieldJack2Axis->createChildSceneNode(mName + "ShieldJack1");
  61:     mShieldJack2->setOrientation(0.907374, 0, 0, 0.420324);
  62:     e = mSManager->createEntity(mName + "shieldJack2", "TSshieldJack2.mesh");
  63:     mShieldJack2->attachObject(e);
  64:  
  65:     //掩护梁节点
  66:     mShieldBeamAxis = mTopBeam->createChildSceneNode(mName + "shieldBeamAxis", Vector3(0.715483, -0.01226, 0));
  67:     mShieldBeamAxis->setOrientation(0.909066, 0, 0, -0.416652);
  68:     //mShieldBeamAxis->roll(Radian(Degree(-50)));
  69:     mShieldBeam = mShieldBeamAxis->createChildSceneNode(mName + "shieldBeam");
  70:     mShieldBeam->translate(0.35, 0.05, 0, Node::TransformSpace::TS_LOCAL);
  71:     e = mSManager->createEntity(mName + "shieldBeam", "TSshieldBeam.mesh");
  72:     mShieldBeam->attachObject(e);
  73:     //mShieldBeam->setVisible(false);
  74:  
  75:     //掩护梁恻护节点
  76:     mShieldSideGuard = mShieldBeam->createChildSceneNode(mName + "shieldSideGuard", Vector3(0, 0, -0.503772));
  77:     e = mSManager->createEntity(mName + "shieldSideGuard", "TSshieldSideGuard.mesh");
  78:     mShieldSideGuard->attachObject(e);
  79:  
  80:     //平衡千斤顶掩护梁部分节点
  81:     //mShieldJack2Axis = mShieldBeam->createChildSceneNode(mName + "shieldJack2Axis", Vector3(-0.074592, -0.184284, 0));
  82:     mShieldJack1Axis = mShieldBeam->createChildSceneNode(mName + "shieldJack1Axis", Vector3(0.1 ,-0.104284, 0));
  83:     mShieldJack1Axis->setInheritOrientation(false);
  84:     mShieldJack1 = mShieldJack1Axis->createChildSceneNode(mName + "shieldJack1");
  85:     e = mSManager->createEntity(mName + "shieldJack1", "TSshieldJack1.mesh");
  86:     mShieldJack1->attachObject(e);
  87:  
  88:  
  89:     mShieldJack2->setAutoTracking(true, mShieldJack1Axis, Vector3::NEGATIVE_UNIT_Y);
  90:     mShieldJack1->setAutoTracking(true, mShieldJack2Axis, Vector3::UNIT_Y);
  91:  
  92:     //mFrontRodTarget = mShieldBeam->createChildSceneNode(mName + "frontRodTarget", Vector3(0.0817407, -0.278777, 0));
  93:     SceneNode *mFrontTargetTo = mShieldBeam->createChildSceneNode(mName + "frontRodTargetTo", Vector3(0.3517407, -0.098777, 0));
  94:     mFrontRodTarget = mShieldBeam->createChildSceneNode(mName + "frontRodTarget", Vector3(0.0517407, -0.178777, 0));
  95:     //e = mSManager->createEntity("frontRodTarget", "ninja.mesh");
  96:     //mFrontRodTarget->attachObject(e);
  97:     //mFrontRodTarget->setScale(0.0005, 0.0005, 0.0005);
  98:     mFrontRodAxis = mBase->createChildSceneNode(mName + "frontRodAxis", Vector3(-0.579555, 0.413417, 0));
  99:     mFrontRod = mFrontRodAxis->createChildSceneNode(mName + "frontRod");
 100:     e = mSManager->createEntity(mName + "frontRod", "TSfrontRod.mesh");
 101:     mFrontRod->attachObject(e);
 102:  
 103:  
 104:     //mBackRodTarget = mShieldBeam->createChildSceneNode(mName + "backRodTarget", Vector3(0.245769, -0.543867, 0));
 105:     SceneNode *mBackRodTo = mShieldBeam->createChildSceneNode(mName + "backRodTargetTo", Vector3(0.68769, -0.05, 0));
 106:     mBackRodTarget = mShieldBeam->createChildSceneNode(mName + "backRodTarget", Vector3(0.00769, -0.05, 0));
 107:     //e = mSManager->createEntity("backRodTarget", "ninja.mesh");
 108:     //mBackRodTarget->attachObject(e);
 109:     //mBackRodTarget->setScale(0.0005, 0.0005, 0.0005);
 110:     mBackRodAxis = mBase->createChildSceneNode(mName + "backRodAxis", Vector3(-0.201678, 0.140705, 0));
 111:     mBackRod = mBackRodAxis->createChildSceneNode(mName + "backRod");
 112:     e = mSManager->createEntity(mName + "backRod", "TSbackRod.mesh");
 113:     mBackRod->attachObject(e);
 114:  
 115:     mFrontRod->setAutoTracking(true, mFrontTargetTo, Vector3::UNIT_Y);
 116:     mBackRod->setAutoTracking(true, mBackRodTo, Vector3::UNIT_Y);

3、动画控制部分

对于每个动作创建一个动画控制器(controller),根据动作的速度与每一帧的时间控制支架做动作,创建的动画控制器为createFrameTimePassthroughController,这样就可以使用frame time传递给控制器函数(controller function)。

为每个动作定义一个控制器,控制其中对每个支架的各个部分进行控制。在处理多个部分联动的时候可能要稍微注意一下,需要注意各部分的关系,本程序中在液压支架进行升柱、降柱的时候进对液压支架的顶梁、掩护梁、后连杆、底座、立柱进行了一系列余弦定理的处理,保证其动作的准确性。代码如下:

   1: public:
   2:     MonitorControllerValuePtr          mTopPillarDownController;          //上立柱降柱动画控制器
   3:     MonitorControllerValuePtr          mTopPillarUpController;            //上立柱升柱动画控制器
   4:     MonitorControllerValuePtr          mDownPillarDownController;         //下立柱降柱动画控制器
   5:     MonitorControllerValuePtr          mDownPillarUpController;           //下立柱升柱动画控制器
   6:  
   7:     MonitorControllerValuePtr          mBaseFrontController;              //移架动画控制器
   8:     MonitorControllerValuePtr          mScraperPushController;            //推溜动画控制器
   9:  
  10:     MonitorControllerValuePtr          mBalancePullController;            //伸平衡动画控制器
  11:     MonitorControllerValuePtr          mBalancePushController;            //收平衡动画控制器
  12:  
  13:     MonitorControllerValuePtr          mTopAngleCalController;            //顶梁角度控制器
   1: ControllerManager &contMgr = ControllerManager::getSingleton();
   2:  
   3:     //上立柱降柱动画控制器
   4:     mTopPillarDownController = MonitorControllerValuePtr(new MovePillarDown(mUpPillar,  1.03, mSpeedPillarDown, this));
   5:     contMgr.createFrameTimePassthroughController(mTopPillarDownController);
   6:     MonitorControlDest *pController = (MonitorControlDest *)mTopPillarDownController.get();
   7:  
   8:     //上立柱升柱动画控制器
   9:     //mTopPillarUpController = MonitorControllerValuePtr(new MovePillarUp(mUpPillar, 1.49607, mSpeedPillarUp, this));
  10:     mTopPillarUpController = MonitorControllerValuePtr(new MovePillarUp(mUpPillar, 1.181672, mSpeedPillarUp, this));
  11:     contMgr.createFrameTimePassthroughController(mTopPillarUpController);
  12:  
  13:     //下立柱降柱动画控制器
  14:     mDownPillarDownController = MonitorControllerValuePtr(new MovePillarDown(mDownPillar, 0.168, mSpeedPillarDown, this));
  15:     contMgr.createFrameTimePassthroughController(mDownPillarDownController);
  16:  
  17:     //下立柱升柱动画控制器
  18:     mDownPillarUpController = MonitorControllerValuePtr(new MovePillarUp(mDownPillar, 0.538018, mSpeedPillarUp, this));
  19:     contMgr.createFrameTimePassthroughController(mDownPillarUpController);
  20:  
  21:     //伸平衡动画控制器
  22:     mBalancePullController = MonitorControllerValuePtr(new PullBalance(mShieldBeamAxis, 3.0, mSpeedBalance, this));
  23:     contMgr.createFrameTimePassthroughController(mBalancePullController);
  24:  
  25:     //收平衡动画控制器
  26:     mBalancePushController = MonitorControllerValuePtr(new PushBalance(mShieldBeamAxis, 3.0, mSpeedBalance, this));
  27:     contMgr.createFrameTimePassthroughController(mBalancePushController);
  28:  
  29:     //推流动画控制器
  30:     mScraperPushController = MonitorControllerValuePtr(new MoveScraperFront(mMoveSupport, mFulcrum, 2.0, mSpeedPush));
  31:     contMgr.createFrameTimePassthroughController(mScraperPushController);
  32:  
  33:     //移架动画控制器
  34:     mBaseFrontController = MonitorControllerValuePtr(new MoveScraperFront(mFulcrum, mMoveSupport, -1.18005, mSpeedMove));
  35:     contMgr.createFrameTimePassthroughController(mBaseFrontController);
  36:  
  37:     mTopAngleCalController = MonitorControllerValuePtr(new CalAngle(this));
  38:     contMgr.createFrameTimePassthroughController(mTopAngleCalController);

各个控制器,控制函数定义代码:

   1: class MonitorControlDest : public Ogre::ControllerValue<Ogre::Real>
   2: {
   3: public:
   4:     MonitorControlDest() : mControlValue(0), mControlFlow(0){}
   5:  
   6:     //设置控制值
   7:     void setControlValue(Ogre::Real controlValue)
   8:     {
   9:         mControlValue = controlValue;
  10:     }
  11:  
  12:     //得到控制值
  13:     Ogre::Real getControlValue()
  14:     {
  15:         return mControlValue;
  16:     }
  17:  
  18:     //设置动画控制器
  19:     void setControlFlow(ControlFlow *pFlow)
  20:     {
  21:         mControlFlow = pFlow;
  22:     }
  23:  
  24:     //得到动画控制器
  25:     ControlFlow* getControlFlow()
  26:     {
  27:         return mControlFlow;
  28:     }
  29: protected:
  30:     Ogre::Real    mControlValue;           //控制值
  31:     ControlFlow   *mControlFlow;           //流程动画控制器
  32: };
  33:  
  34:  //收平衡动画控制器
  35: class PushBalance : public MonitorControlDest
  36: {
  37: public:
  38:     PushBalance(Ogre::SceneNode *node, Ogre::Real stopPos, Ogre::Real speed, ThinSeamSupport *support)
  39:         : mNode(node), mStopPos(stopPos), mSpeed(speed), mSupport(support)
  40:     {
  41:  
  42:     }
  43:  
  44:     //得到当前的值
  45:     virtual Ogre::Real getValue(void) const
  46:     {
  47:         if(mNode)
  48:             return mNode->getOrientation().getPitch().valueDegrees();
  49:         return 0;
  50:     }
  51:  
  52:     //设置当前值
  53:     virtual void setValue(Ogre::Real value);
  54: protected:
  55:     Ogre::SceneNode         *mNode;           //被控制对象
  56:     Ogre::Radian             mStopPos;        //停止位置
  57:     Ogre::Real               mSpeed;          //速度
  58:     ThinSeamSupport         *mSupport;        //液压支架对象
  59: };

程序运行如下:

未命名

原文地址:https://www.cnblogs.com/cg_ghost/p/2288799.html