zoukankan      html  css  js  c++  java
  • ODE的buggy例程分析

            ODE (Open Dynamic Engine) 是一个免费的具有工业品质的刚体动力学的库,一款优秀的开源物理引擎。它能很好地仿真现实环境中的可移动物体,而且它有内建的碰撞检测系统。

            最近从网上看到了ODE,不禁有一种跃跃欲试的冲动,于是这两天就小试了一下。虽然ODE这个库已经使用了十几年了,但是资料还是比较少,中文的更是寥寥可数,只有几篇官网教程的翻译,也只有前几章的,不是很全。貌似这种日本做的东西,文档做的都不是很好呀。以下是几篇教程的链接:

           ODE文档的部分翻译: 

                                               http://www.cnblogs.com/muxi/archive/2012/03/13/2394752.html

           ODE 教程:

                              http://bbs.sjtu.edu.cn/bbscon,board,GNULinux,file,M.1274284081.A.html

                                               http://hi.baidu.com/ujbiogeffebcmnd/item/86a926cbadea4227e80f2ef0 

                没办法,就开始看官方源码中的demo,今天花了一下午时间看了buggy的例程,对照着在线手册了解了程序中的API,简单做了一下中文注释。

           

    /*************************************************************************
     *                                                                       *
     * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
     * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
     *                                                                       *
     * This library is free software; you can redistribute it and/or         *
     * modify it under the terms of EITHER:                                  *
     *   (1) The GNU Lesser General Public License as published by the Free  *
     *       Software Foundation; either version 2.1 of the License, or (at  *
     *       your option) any later version. The text of the GNU Lesser      *
     *       General Public License is included with this library in the     *
     *       file LICENSE.TXT.                                               *
     *   (2) The BSD-style license that is included with this library in     *
     *       the file LICENSE-BSD.TXT.                                       *
     *                                                                       *
     * This library is distributed in the hope that it will be useful,       *
     * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
     * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
     *                                                                       *
     *************************************************************************/
    
    /*
       buggy with suspension.
       this also shows you how to use geom groups.
    */
    
    #define  dSINGLE    //定义为单精度
    #include <ode/ode.h>
    #include <drawstuff/drawstuff.h>
    
    #define DRAWSTUFF_TEXTURE_PATH "textures"   //纹理文件的路径
    
    // select correct drawing functions
    #ifdef dDOUBLE
    #define dsDrawBox dsDrawBoxD
    #define dsDrawSphere dsDrawSphereD
    #define dsDrawCylinder dsDrawCylinderD
    #define dsDrawCapsule dsDrawCapsuleD
    #endif
    
    // some constants
    #define LENGTH 0.7	// 车壳长度
    #define WIDTH 0.5	// 车壳宽度
    #define HEIGHT 0.2	// 车壳高度
    #define RADIUS 0.18	// 轮子半径
    #define STARTZ 0.5	// 开始车壳的位置
    #define CMASS 1		// 车壳的质量
    #define WMASS 0.2	// 轮子的质量
    
    
    // dynamics and collision objects (chassis, 3 wheels, environment)
    static dWorldID world;      //动力学计算使用的world
    static dSpaceID space;      //检测碰撞使用的space
    static dBodyID body[4];     //设置车体的ID(三个轮子,一个车体)
    static dJointID joint[3];	// joint[0]是前轮
    static dJointGroupID contactgroup;
    static dGeomID ground;      //大地
    static dSpaceID car_space;
    static dGeomID box[1];       //车体geom的ID
    static dGeomID sphere[3];    //车轮geom的ID
    static dGeomID ground_box;   //障碍物geom的ID
    
    
    // things that the user controls
    static dReal speed=0,steer=0;	// 用户命令
    
    // 碰撞检测的callback函数
    static void nearCallback (void *data, dGeomID o1, dGeomID o2)
    {
      int i,n;
    
      // 选择碰撞检测中的2个中的一个作为标志;
      // 如果有一个碰撞物为ground或者障碍物则把标志位g1\g2置为1
      int g1 = (o1 == ground || o1 == ground_box);
      int g2 = (o2 == ground || o2 == ground_box);
      if (!(g1 ^ g2)) return;
    
      const int N = 10;    //接触点的上限是10个
      dContact contact[N];
      n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));   //n是碰撞的次数
      if (n > 0) {
        for (i=0; i<n; i++) {
          contact[i].surface.mode = dContactSlip1 | dContactSlip2 |
    	dContactSoftERP | dContactSoftCFM | dContactApprox1;   //设定地面模式
          contact[i].surface.mu = dInfinity;   //库伦摩擦系数(dInfinity:无穷大)
          contact[i].surface.slip1 = 0.1;      //滑动系数
          contact[i].surface.slip2 = 0.1;
          contact[i].surface.soft_erp = 0.5;   //这两个好像是设置柔软度的
          contact[i].surface.soft_cfm = 0.3;
    
          //生成contactjoint
          dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
          //用contactjoint对接触的两个geom进行约束
          dJointAttach (c,
    		    dGeomGetBody(contact[i].geom.g1),
    		    dGeomGetBody(contact[i].geom.g2));
        }
      }
    }
    
    
    // 开始仿真,这是视角
    static void start()
    {
      dAllocateODEDataForThread(dAllocateMaskAll);
    
      static float xyz[3] = {0.8317f,-0.9817f,0.8000f};     //视线的位置
      static float hpr[3] = {121.0000f,-27.5000f,0.0000f};  //视线的方向
      dsSetViewpoint (xyz,hpr);                             //设定视线
      printf ("Press:\t'a' to increase speed.\n"
    	  "\t'z' to decrease speed.\n"
    	  "\t',' to steer left.\n"
    	  "\t'.' to steer right.\n"
    	  "\t' ' to reset speed and steering.\n"
    	  "\t'1' to save the current state to 'state.dif'.\n");
    }
    
    
    //键盘操作的回调函数
    static void command (int cmd)
    {
      switch (cmd) {
      case 'a': case 'A':
        speed += 0.3;
        break;
      case 'z': case 'Z':
        speed -= 0.3;
        break;
      case ',':
        steer -= 0.5;
        break;
      case '.':
        steer += 0.5;
        break;
      case ' ':
        speed = 0;
        steer = 0;
        break;
      case '1': {
          FILE *f = fopen ("state.dif","wt");
          if (f) {
            dWorldExportDIF (world,f,"");
            fclose (f);
          }
        }
      }
    }
    
    
    // 仿真循环
    // 电机驱动和转向驱动都是在前轮
    static void simLoop (int pause)
    {
      int i;
      if (!pause) {
        // motor
        dJointSetHinge2Param (joint[0],dParamVel2,-speed);    //设置期望速度
        dJointSetHinge2Param (joint[0],dParamFMax2,0.1);      //电机驱动的最大扭力
    
        // steering
        dReal v = steer - dJointGetHinge2Angle1 (joint[0]);
        if (v > 0.1) v = 0.1;
        if (v < -0.1) v = -0.1;
        v *= 10.0;
        dJointSetHinge2Param (joint[0],dParamVel,v);
        dJointSetHinge2Param (joint[0],dParamFMax,0.2);
        dJointSetHinge2Param (joint[0],dParamLoStop,-0.75);    //最小停止角度
        dJointSetHinge2Param (joint[0],dParamHiStop,0.75);     //最大停止角度
        dJointSetHinge2Param (joint[0],dParamFudgeFactor,0.1);  //防止启动跳动
    
        dSpaceCollide (space,0,&nearCallback);   //碰撞检测,最初写入的值
        dWorldStep (world,0.05);                 //决定simulation的stepsize
    
        // remove all contact joints
        dJointGroupEmpty (contactgroup);          //将contactgroup置空
      }
    
      //DrawStuff绘制
      dsSetColor (0,1,1);       //颜色切换
      dsSetTexture (DS_WOOD);   //纹理切换
      dReal sides[3] = {LENGTH,WIDTH,HEIGHT};   //车壳的尺寸
      dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides);   //绘制车壳
      dsSetColor (1,1,1);
      for (i=1; i<=3; i++) dsDrawCylinder (dBodyGetPosition(body[i]),
    				       dBodyGetRotation(body[i]),0.02f,RADIUS);    //绘制车轮
    
      dVector3 ss;
      dGeomBoxGetLengths (ground_box,ss);
      dsDrawBox (dGeomGetPosition(ground_box),dGeomGetRotation(ground_box),ss);   //绘制障碍
    }
    
    
    int main (int argc, char **argv)
    {
      int i;
      dMass m;
    
      // setup pointers to drawstuff callback functions
      dsFunctions fn;           // drawstuff结构体
      fn.version = DS_VERSION;  // drawstuff的版本
      fn.start = &start;        // 仿真的前处理函数
      fn.step = &simLoop;       // 仿真的每一步被调用的函数
      fn.command = &command;    // 键盘输入
      fn.stop = 0;              // 没有函数,因此设定为NULL指针
      fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH;  // 纹理文件的路径
    
      // create world
      dInitODE2(0);                    //初始化ODE环境
      world = dWorldCreate();          //创建世界
      space = dHashSpaceCreate (0);    //创建碰撞检测用space,返回它的ID。
      contactgroup = dJointGroupCreate (0);   //生成jointGroup
      dWorldSetGravity (world,0,0,-0.5);      //重力加速度
      ground = dCreatePlane (space,0,0,1,0);  //创建一个ground
    
      // 创建车体
      body[0] = dBodyCreate (world);
      dBodySetPosition (body[0],0,0,STARTZ);    //设置初始位置
      dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT);
      dMassAdjust (&m,CMASS);
      dBodySetMass (body[0],&m);                   //设置质量
      box[0] = dCreateBox (0,LENGTH,WIDTH,HEIGHT); //生成车体的geom
      dGeomSetBody (box[0],body[0]);               //设置车体中的geom,给物体的两个属性形状geom和刚体body添加关联。
    
      // wheel bodies
      for (i=1; i<=3; i++) {
        body[i] = dBodyCreate (world);          //创建车轮的body
        dQuaternion q;
        dQFromAxisAndAngle (q,1,0,0,M_PI*0.5);  //计算车轮的旋转角度
        dBodySetQuaternion (body[i],q);         //设置车轮的旋转角度
        dMassSetSphere (&m,1,RADIUS);
        dMassAdjust (&m,WMASS);
        dBodySetMass (body[i],&m);             //设置质量
        sphere[i-1] = dCreateSphere (0,RADIUS);
        dGeomSetBody (sphere[i-1],body[i]);    //设置geom
      }
      dBodySetPosition (body[1],0.5*LENGTH,0,STARTZ-HEIGHT*0.5);    //设置初始位置
      dBodySetPosition (body[2],-0.5*LENGTH, WIDTH*0.5,STARTZ-HEIGHT*0.5);
      dBodySetPosition (body[3],-0.5*LENGTH,-WIDTH*0.5,STARTZ-HEIGHT*0.5);
    
      // front and back wheel hinges
      for (i=0; i<3; i++) {
        joint[i] = dJointCreateHinge2 (world,0);         //创建joint
        dJointAttach (joint[i],body[0],body[i+1]);       //设置joint的连接体
        const dReal *a = dBodyGetPosition (body[i+1]);   //获取位置
        dJointSetHinge2Anchor (joint[i],a[0],a[1],a[2]); //设置joint的位置
        dJointSetHinge2Axis1 (joint[i],0,0,1);           //设置旋转轴
        dJointSetHinge2Axis2 (joint[i],0,1,0);
      }
    
      // 设置joint的悬挂参数
      // 如果不需要悬挂可以将参数设置为0
      for (i=0; i<3; i++) {                             
        dJointSetHinge2Param (joint[i],dParamSuspensionERP,0.4);
        dJointSetHinge2Param (joint[i],dParamSuspensionCFM,0.8);
      }
    
      // 固定后面两个轮子
      for (i=1; i<3; i++) {
        // set stops to make sure wheels always stay in alignment
        dJointSetHinge2Param (joint[i],dParamLoStop,0);
        dJointSetHinge2Param (joint[i],dParamHiStop,0);
      }
    
      // 创建car的space,并且包含在总的space中
      car_space = dSimpleSpaceCreate (space);
      dSpaceSetCleanup (car_space,0);
      dSpaceAdd (car_space,box[0]);
      dSpaceAdd (car_space,sphere[0]);
      dSpaceAdd (car_space,sphere[1]);
      dSpaceAdd (car_space,sphere[2]);
    
      // 设置障碍
      ground_box = dCreateBox (space,2,1.5,1);
      dMatrix3 R;
      dRFromAxisAndAngle (R,0,1,0,-0.15);
      dGeomSetPosition (ground_box,2,0,-0.34);
      dGeomSetRotation (ground_box,R);
    
      // run simulation
      dsSimulationLoop (argc,argv,352,288,&fn);
    
      dGeomDestroy (box[0]);
      dGeomDestroy (sphere[0]);
      dGeomDestroy (sphere[1]);
      dGeomDestroy (sphere[2]);
      dJointGroupDestroy (contactgroup);
      dSpaceDestroy (space);
      dWorldDestroy (world);
      dCloseODE();
      return 0;
    }
    

                   运行效果:            


                   程序中比较难理解的是一些参数的设置和API的使用。

             当发生碰撞时,调用回调函数nearCallback,其中需要设置一些碰撞点的参数,具体的参数可以参考用户手册中的说明:


            joint的配置中也有一些参数的设置:


            以上均参考在线文档:

            API手册:http://robotics.naist.jp/~akihiko-y/doxy/ode0.9/index.html

                用户手册:http://www.ode.org/ode-latest-userguide.html            

  • 相关阅读:
    ffplay(2.0.1)中的音视频同步
    (转)ffplay的音视频同步分析之视频同步到音频
    (转) 从ffmpeg中提取出YUV数据
    关于解决用tutorial7教程中的代码打造一款自己的播放器中的声音噪音问题
    基于<最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)>的一些个人总结
    (转)SDL2.0在mfc窗口中显示yuv的一种方法
    (转)SDL1.2到2.0的迁移指南
    APM (应用性能管理)
    在telnet下操作memcache详解(操作命令详解)
    MYSQL主从数据库搭建
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/2998664.html
Copyright © 2011-2022 走看看