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

主要思想:

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

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

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

1、通讯部分

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

示例代码如下:

short usDataLen)
   2: {
/* 高CRC 字节初始化 */
/* 低CRC 字节初始化 */
/* CRC 循环中的索引 */
/* 传输消息缓冲区 */
   7:     {
/* 计算CRC */
   9:         uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
  10:         uchCRCLo = auchCRCLo[uIndex] ;
  11:     }
return (uchCRCHi << 8 | uchCRCLo) ;
  13: }
  14:  
//构造液压支架通信命令
char>& result)
  17: {
  18:     result.resize(cnt+3);
  19:     result[0] = 0xaf;
  20:  
  21:     memcpy(&result[1], buf, cnt);
  22:  
char *)&result[0], cnt+1);
  24:     result[cnt + 1] = crc >> 8;
  25:     result[cnt + 2] = crc & 0xff;
  26:  
return cnt+3;
  28: }
  29:  
//CRC校验
char>& result)
  32: {
//if(cnt != 9)
//{
//}
  38:  
char *)(buf+0), cnt-2);
char *)(buf+1 + cnt-3));
  41:     send_crc <<= 8;
char *)(buf+2 + cnt-3));
if(send_crc != recv_crc)
  44:     {
));
return -1;
  48:     }
  49:  
  50:     result.resize(cnt-3);
  51:     memcpy(&result[0], buf+1, cnt-3);
  52:  
return cnt-3;
  54: }

2、支架组装,定义部分

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

   1: mSupportRoot = mSManager->getRootSceneNode()->createChildSceneNode(mName);
, Vector3(0, 0, 0));
   3:  
//推溜节点
, Vector3(-1.18005, 0.115254, 0));
);
   7:     mMoveSupport->attachObject(e);
   8:  
, Vector3(-1.03653, -0.0424172, 0));
);
  11:     mScraper->attachObject(e);
  12:     mScraper->setVisible(mIsShowScraper);
  13:  
//底座节点
);
);
  17:     mBase->attachObject(e);
, Vector3(-1.05936, 0.141, 0));
  19:  
//抬底节点
, Vector3(-1.26348, 0.30187, 0));
);
  23:     mLiftBase->attachObject(e);
  24:  
//下立柱节点
, Vector3(-1.07193, 0.538018, 0));
);
  28:     mDownPillar->attachObject(e);
  29:     mDownPillar->setOrientation(0.989742, 0, 0, 0.142869);
  30:  
//上立柱节点
, Vector3(0, 1.181672, 0));
);
  36:     mUpPillar->attachObject(e);
//mUpPillar->setOrientation(0.997184, 0, 0, 0.0749965);
  38:  
//顶梁节点
, Vector3(0.00674, -0.00362, 0));
  41:     mTopBeamAxis->roll(Radian(Math::DegreesToRadians(-17)));
);
);
/*0.915483*/0.715483, -0.10226, 0));
//mTopBeamTrack->attachObject(e);
//mTopBeamTrack->setScale(0.001, 0.001, 0.001);
);
  50:     mTopBeam->attachObject(e);
  51:  
//恻护节点
, Vector3(-0.00456, -0.00654, 0));
);
  55:     mSideGuard->attachObject(e);
  56:  
//平衡千斤顶顶梁部分
, Vector3(0.435347, -0.00176, 0));
  59:     mShieldJack2Axis->setInheritOrientation(false);
);
  61:     mShieldJack2->setOrientation(0.907374, 0, 0, 0.420324);
);
  63:     mShieldJack2->attachObject(e);
  64:  
//掩护梁节点
, Vector3(0.715483, -0.01226, 0));
  67:     mShieldBeamAxis->setOrientation(0.909066, 0, 0, -0.416652);
//mShieldBeamAxis->roll(Radian(Degree(-50)));
);
  70:     mShieldBeam->translate(0.35, 0.05, 0, Node::TransformSpace::TS_LOCAL);
);
  72:     mShieldBeam->attachObject(e);
//mShieldBeam->setVisible(false);
  74:  
//掩护梁恻护节点
, Vector3(0, 0, -0.503772));
);
  78:     mShieldSideGuard->attachObject(e);
  79:  
//平衡千斤顶掩护梁部分节点
, Vector3(0.1 ,-0.104284, 0));
  83:     mShieldJack1Axis->setInheritOrientation(false);
);
);
  86:     mShieldJack1->attachObject(e);
  87:  
  88:  
  89:     mShieldJack2->setAutoTracking(true, mShieldJack1Axis, Vector3::NEGATIVE_UNIT_Y);
  90:     mShieldJack1->setAutoTracking(true, mShieldJack2Axis, Vector3::UNIT_Y);
  91:  
, Vector3(0.3517407, -0.098777, 0));
, Vector3(0.0517407, -0.178777, 0));
//mFrontRodTarget->attachObject(e);
//mFrontRodTarget->setScale(0.0005, 0.0005, 0.0005);
, Vector3(-0.579555, 0.413417, 0));
);
);
 101:     mFrontRod->attachObject(e);
 102:  
 103:  
, Vector3(0.68769, -0.05, 0));
, Vector3(0.00769, -0.05, 0));
//mBackRodTarget->attachObject(e);
//mBackRodTarget->setScale(0.0005, 0.0005, 0.0005);
, Vector3(-0.201678, 0.140705, 0));
);
);
 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)。

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

public:
//上立柱降柱动画控制器
//上立柱升柱动画控制器
//下立柱降柱动画控制器
//下立柱升柱动画控制器
   6:  
//移架动画控制器
//推溜动画控制器
   9:  
//伸平衡动画控制器
//收平衡动画控制器
  12:  
  13:     MonitorControllerValuePtr          mTopAngleCalController;            //顶梁角度控制器

 

   1: ControllerManager &contMgr = ControllerManager::getSingleton();
   2:  
//上立柱降柱动画控制器
this));
   5:     contMgr.createFrameTimePassthroughController(mTopPillarDownController);
   6:     MonitorControlDest *pController = (MonitorControlDest *)mTopPillarDownController.get();
   7:  
//上立柱升柱动画控制器
//mTopPillarUpController = MonitorControllerValuePtr(new MovePillarUp(mUpPillar, 1.49607, mSpeedPillarUp, this));
this));
  11:     contMgr.createFrameTimePassthroughController(mTopPillarUpController);
  12:  
//下立柱降柱动画控制器
this));
  15:     contMgr.createFrameTimePassthroughController(mDownPillarDownController);
  16:  
//下立柱升柱动画控制器
this));
  19:     contMgr.createFrameTimePassthroughController(mDownPillarUpController);
  20:  
//伸平衡动画控制器
this));
  23:     contMgr.createFrameTimePassthroughController(mBalancePullController);
  24:  
//收平衡动画控制器
this));
  27:     contMgr.createFrameTimePassthroughController(mBalancePushController);
  28:  
//推流动画控制器
new MoveScraperFront(mMoveSupport, mFulcrum, 2.0, mSpeedPush));
  31:     contMgr.createFrameTimePassthroughController(mScraperPushController);
  32:  
//移架动画控制器
new MoveScraperFront(mFulcrum, mMoveSupport, -1.18005, mSpeedMove));
  35:     contMgr.createFrameTimePassthroughController(mBaseFrontController);
  36:  
this));
  38:     contMgr.createFrameTimePassthroughController(mTopAngleCalController);

 

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

public Ogre::ControllerValue<Ogre::Real>
   2: {
public:
   4:     MonitorControlDest() : mControlValue(0), mControlFlow(0){}
   5:  
//设置控制值
void setControlValue(Ogre::Real controlValue)
   8:     {
   9:         mControlValue = controlValue;
  10:     }
  11:  
//得到控制值
  13:     Ogre::Real getControlValue()
  14:     {
return mControlValue;
  16:     }
  17:  
//设置动画控制器
void setControlFlow(ControlFlow *pFlow)
  20:     {
  21:         mControlFlow = pFlow;
  22:     }
  23:  
//得到动画控制器
  25:     ControlFlow* getControlFlow()
  26:     {
return mControlFlow;
  28:     }
protected:
//控制值
//流程动画控制器
  32: };
  33:  
//收平衡动画控制器
public MonitorControlDest
  36: {
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:  
//得到当前的值
const
  46:     {
if(mNode)
return mNode->getOrientation().getPitch().valueDegrees();
return 0;
  50:     }
  51:  
//设置当前值
void setValue(Ogre::Real value);
protected:
//被控制对象
//停止位置
//速度
//液压支架对象
  59: };

 

程序运行如下:

支架仿真系统的实现

相关文章: