00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 #include <stdlib.h>
00230 #include <signal.h>
00231 #include <iostream>
00232 #include <sys/stat.h>
00233 #include <sys/time.h>
00234 #include <unistd.h>
00235 #include <selforg/configurable.h>
00236 #include <selforg/abstractcontroller.h>
00237
00238 #include "simulation.h"
00239
00240 #include <osg/ShapeDrawable>
00241 #include <osg/ArgumentParser>
00242 #include <osg/BlendFunc>
00243 #include <osg/AlphaFunc>
00244 #include <osgDB/ReaderWriter>
00245 #include <osgDB/FileUtils>
00246
00247 #include "odeagent.h"
00248 #include "primitive.h"
00249
00250 #include "grabframe.h"
00251
00252 #include "abstractobstacle.h"
00253 #include "cameramanipulator.h"
00254 #include "cameramanipulatorTV.h"
00255 #include "cameramanipulatorFollow.h"
00256 #include "cameramanipulatorRace.h"
00257
00258 namespace lpzrobots {
00259
00260 using namespace std;
00261 using namespace osg;
00262 using namespace osgProducer;
00263
00264
00265 int Simulation::ctrl_C = 0;
00266
00267 Simulation::Simulation(){
00268 nextLeakAnnounce = 20;
00269 leakAnnCounter = 1;
00270 sim_step = 0;
00271 state = none;
00272 pause = false;
00273 viewer = 0;
00274 cam = 0;
00275 arguments= 0;
00276 }
00277
00278 Simulation::~Simulation(){
00279 if(state!=running) return;
00280 dJointGroupDestroy ( odeHandle.jointGroup );
00281 dWorldDestroy ( odeHandle.world );
00282 dSpaceDestroy ( odeHandle.space );
00283 dCloseODE ();
00284
00285 state=closed;
00286
00287 osgGA::GUIEventHandler::unref_nodelete();
00288
00289 Producer::Camera::Callback::unref_nodelete();
00290 }
00291
00292
00293
00294 bool Simulation::init(int argc, char** argv){
00295
00296
00297 odeHandle.world = dWorldCreate ();
00298
00299
00300 odeHandle.space = dHashSpaceCreate (0);
00301
00302
00303 odeHandle.jointGroup = dJointGroupCreate ( 1000000 );
00304
00305 globalData.odeConfig.setOdeHandle(odeHandle);
00306
00307
00308 dWorldSetGravity ( odeHandle.world , 0 , 0 , globalData.odeConfig.gravity );
00309 dWorldSetERP ( odeHandle.world , 1 );
00310
00311 cmd_handler_init();
00312
00313 globalData.environment = new DummyPrimitive();
00314
00315
00316 globalData.configs.push_back(&(globalData.odeConfig));
00317
00318
00319
00320 osgDB::FilePathList l = osgDB::getDataFilePathList();
00321 l.push_back("../../osg/data");
00322 osgDB::setDataFilePathList(l);
00323
00324 processCmdLine(argc, argv);
00325
00326 arguments = new ArgumentParser(&argc, argv);
00327
00328
00329 arguments->getApplicationUsage()->setDescription(
00330 arguments->getApplicationName() + " Lpzrobots Simulator");
00331 arguments->getApplicationUsage()->setCommandLineUsage(arguments->getApplicationName());
00332 arguments->getApplicationUsage()->addCommandLineOption(
00333 "-h or --help", "Display this information");
00334
00335
00336 viewer = new ExtendedViewer(*arguments);
00337
00338
00339 unsigned int options = Viewer::SKY_LIGHT_SOURCE |
00340 Viewer::STATE_MANIPULATOR |
00341 Viewer::STATS_MANIPULATOR |
00342 Viewer::VIEWER_MANIPULATOR |
00343 Viewer::ESCAPE_SETS_DONE;
00344 viewer->setUpViewer(options);
00345
00346 viewer->getEventHandlerList().push_front(this);
00347
00348
00349 if (arguments->read("-h") || arguments->read("--help")) {
00350 arguments->getApplicationUsage()->write(std::cout);
00351 return false;
00352 }
00353
00354
00355
00356
00357 if (arguments->errors()) {
00358 arguments->writeErrorMessages(std::cout);
00359 return false;
00360 }
00361
00362 osgHandle.tesselhints[0] = new TessellationHints();
00363 osgHandle.tesselhints[1] = new TessellationHints();
00364 osgHandle.tesselhints[2] = new TessellationHints();
00365 osgHandle.tesselhints[0]->setDetailRatio(0.1f);
00366 osgHandle.tesselhints[1]->setDetailRatio(1.0f);
00367 osgHandle.tesselhints[2]->setDetailRatio(3.0f);
00368
00369 osgHandle.color = Color(1,1,1,1);
00370
00371 osgHandle.scene=makeScene();
00372 if (!osgHandle.scene) return false;
00373
00374 osgHandle.normalState = new StateSet();
00375
00376
00377 osg::StateSet* stateset = new StateSet();
00378 osg::BlendFunc* transBlend = new osg::BlendFunc;
00379 transBlend->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
00380 stateset->setAttributeAndModes(transBlend, osg::StateAttribute::ON);
00381 stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
00382
00383 stateset->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
00384 osgHandle.transparentState = stateset;
00385
00386
00387 CameraManipulator* defaultCameramanipulator =
00388 new CameraManipulator(osgHandle.scene, globalData);
00389 CameraManipulator* cameramanipulatorFollow =
00390 new CameraManipulatorFollow(osgHandle.scene, globalData);
00391 CameraManipulator* cameramanipulatorTV =
00392 new CameraManipulatorTV(osgHandle.scene, globalData);
00393 CameraManipulator* cameramanipulatorRace =
00394 new CameraManipulatorRace(osgHandle.scene, globalData);
00395 unsigned int pos = viewer->addCameraManipulator(defaultCameramanipulator);
00396 viewer->addCameraManipulator(cameramanipulatorFollow);
00397 viewer->addCameraManipulator(cameramanipulatorTV);
00398 viewer->addCameraManipulator(cameramanipulatorRace);
00399 viewer->selectCameraManipulator(pos);
00400
00401
00402 viewer->getUsage(*(arguments->getApplicationUsage()));
00403
00404 state=initialised;
00405 return true;
00406 }
00407
00408
00409 bool Simulation::run(int argc, char** argv){
00410 if(!init(argc, argv)) return false;
00411
00412
00413 printf ( "\nWelcome to the virtual ODE - robot simulator of the Robot Group Leipzig\n" );
00414 printf ( "------------------------------------------------------------------------\n" );
00415 printf ( "Press Ctrl-C for an basic commandline interface (on the console).\n\n" );
00416 printf ( "Press h for help.\n\n" );
00417
00418
00419 state=running;
00420 globalData.time=0;
00421 resetSyncTimer();
00422
00423 start(odeHandle, osgHandle, globalData);
00424
00425
00426 viewer->setSceneData(root);
00427
00428 Producer::CameraConfig* cfg = viewer->getCameraConfig();
00429 cam = cfg->getCamera(0);
00430
00431 Producer::RenderSurface* rs = cam->getRenderSurface();
00432 rs->setWindowName( "LpzRobots - Selforg" );
00433
00434
00435 int x = rs->getWindowOriginX();
00436 int y = rs->getWindowOriginY();
00437 rs->setWindowRectangle(x,y,windowWidth, windowHeight);
00438 rs->fullScreen(false);
00439
00440 cam->addPostDrawCallback(this);
00441
00442
00443 viewer->realize();
00444
00445 while (!viewer->done())
00446 {
00447
00448 viewer->sync();
00449
00450 loop();
00451
00452
00453
00454 viewer->update();
00455
00456
00457
00458 viewer->frame();
00459 }
00460
00461
00462 viewer->sync();
00463 tidyUp(globalData);
00464 end(globalData);
00465 return true;
00466
00467 }
00468
00469 void Simulation::config(GlobalData& globalData){
00470 changeParams(globalData.configs);
00471 }
00472
00473 void Simulation::end(GlobalData& globalData){
00474 }
00475
00476 void Simulation::loop(){
00477
00478
00479 for(int t = 0; t < globalData.odeConfig.drawInterval; t++){
00480
00481 if (control_c_pressed()){
00482 cmd_begin_input();
00483 config(globalData);
00484 cmd_end_input();
00485 resetSyncTimer();
00486 }
00487
00488
00489 if (!pause) {
00490 globalData.time += globalData.odeConfig.simStepSize;
00491 sim_step++;
00492
00493 if(sim_step% ( int(1/globalData.odeConfig.simStepSize) * 600) ==0) {
00494 printf("Simulation time: %li min\n", sim_step/ ( long(1/globalData.odeConfig.simStepSize)*60));
00495 }
00496
00497 for(OdeAgentList::iterator i=globalData.agents.begin(); i != globalData.agents.end(); i++){
00498 if ( (sim_step % globalData.odeConfig.controlInterval ) == 0 ){
00499 (*i)->step(globalData.odeConfig.noise);
00500 }
00501 (*i)->getRobot()->doInternalStuff(globalData);
00502 }
00503
00504
00505 dSpaceCollide ( odeHandle.space , this , &nearCallback );
00506 dWorldStep ( odeHandle.world , globalData.odeConfig.simStepSize );
00507
00508 dJointGroupEmpty (odeHandle.jointGroup);
00509 }
00510
00511 addCallback(globalData, t==0, pause);
00512
00513 if(t==0){
00514
00515 for(ObstacleList::iterator i=globalData.obstacles.begin(); i != globalData.obstacles.end(); i++){
00516 (*i)->update();
00517 }
00518 for(OdeAgentList::iterator i=globalData.agents.begin(); i != globalData.agents.end(); i++){
00519 (*i)->getRobot()->update();
00520 }
00521
00522 osgGA::MatrixManipulator* mm =viewer->getCurrentCameraManipulator();
00523 if(mm){
00524 CameraManipulator* cameramanipulator = dynamic_cast<CameraManipulator*>(mm);
00525 if(cameramanipulator)
00526 cameramanipulator->update();
00527 }
00528
00529
00530
00531
00532
00533 }
00534
00535 }
00536
00537
00538 if(globalData.odeConfig.realTimeFactor!=0.0 && !pause){
00539 long elaped = timeOfDayinMS() - realtimeoffset;
00540
00541 long diff = long((globalData.time*1000.0 - simtimeoffset)
00542 / globalData.odeConfig.realTimeFactor ) - elaped;
00543 if(diff > 10000 || diff < -10000)
00544 resetSyncTimer();
00545 else{
00546 if(diff > 4){
00547 usleep((diff-2)*1000);
00548 nextLeakAnnounce=4;
00549 }else if (diff < 0){
00550
00551 if(leakAnnCounter%nextLeakAnnounce==0 && diff < -100 && !videostream.isOpen()){
00552 printf("Time leak of %li ms (Suggestion: realtimefactor=%g , next in annoucement in %i )\n",
00553 -diff, globalData.odeConfig.realTimeFactor*0.5, nextLeakAnnounce);
00554 nextLeakAnnounce=min(nextLeakAnnounce*2,512);
00555 leakAnnCounter=0;
00556 resetSyncTimer();
00557 }
00558 leakAnnCounter++;
00559 }
00560 }
00561 }else if (pause) {
00562 usleep(1000);
00563 }
00564 }
00565
00566 bool Simulation::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&) {
00567 bool handled = false;
00568 switch(ea.getEventType()) {
00569 case(osgGA::GUIEventAdapter::KEYDOWN):
00570 {
00571 handled = command(odeHandle, osgHandle, globalData, ea.getKey(), true);
00572 if(handled) break;
00573
00574 switch(ea.getKey()){
00575 case 18:
00576 if(videostream.isOpen()){
00577 printf("Stop video recording!\n");
00578 videostream.close();
00579 }else{
00580 char dir[128];
00581 char filename[140];
00582 createNewDir("video", dir);
00583 printf("Start video recording in %s!\n", dir);
00584 sprintf(filename, "%s/frame", dir);
00585 videostream.open(filename);
00586 }
00587 break;
00588 case 16:
00589 pause = !pause;
00590 printf( pause ? "Pause\n" : "Continue\n" );
00591 resetSyncTimer();
00592 handled = true;
00593 break;
00594 }
00595 }
00596 case(osgGA::GUIEventAdapter::KEYUP):
00597 {
00598 handled = command(odeHandle, osgHandle, globalData, ea.getKey(), false);
00599 }
00600 default:
00601 break;
00602 }
00603 return handled;
00604 }
00605
00606 void Simulation::getUsage (osg::ApplicationUsage& au) const {
00607 au.addKeyboardMouseBinding("Simulation: Ctrl-r","Start/Stop video recording");
00608 au.addKeyboardMouseBinding("Simulation: Ctrl-p","Pause on/off");
00609 bindingDescription(au);
00610 }
00611
00612 void Simulation::accept(osgGA::GUIEventHandlerVisitor& v) {
00613 v.visit(*this);
00614 }
00615
00616
00617 void Simulation::operator() (const Producer::Camera &c){
00618
00619 if(videostream.isOpen() && !pause){
00620 if(!videostream.grabAndWriteFrame(c)){
00621 fprintf(stderr,"Stop video recording because of failture!\n");
00622 videostream.close();
00623 }
00624 }
00625 }
00626
00627
00628 void Simulation::tidyUp(GlobalData& global){
00629
00630 for(ObstacleList::iterator i=global.obstacles.begin(); i != global.obstacles.end(); i++){
00631 delete (*i);
00632 }
00633 global.obstacles.clear();
00634
00635
00636 for(OdeAgentList::iterator i=global.agents.begin(); i != global.agents.end(); i++){
00637 delete (*i)->getRobot();
00638 delete (*i)->getController();
00639 delete (*i);
00640 }
00641 if(global.environment) delete global.environment;
00642 global.agents.clear();
00643 }
00644
00645
00646 void Simulation::processCmdLine(int argc, char** argv){
00647 if(contains(argv, argc, "-h")) usage(argv[0]);
00648
00649 int seedIndex = contains(argv, argc, "-r");
00650 long seed=0;
00651
00652 if(seedIndex && argc > seedIndex) {
00653 seed=atoi(argv[seedIndex]);
00654 }else{
00655
00656 seed=time(0);
00657 }
00658 printf("Use random number seed: %li\n", seed);
00659 srand(seed);
00660
00661 int resolindex = contains(argv, argc, "-x");
00662 windowWidth = 640;
00663 windowHeight = 480;
00664 if(resolindex && argc > resolindex) {
00665 sscanf(argv[resolindex],"%ix%i", &windowWidth,&windowHeight);
00666 windowWidth = windowWidth < 64 ? 64 : (windowWidth > 1600 ? 1600 : windowWidth);
00667 windowHeight = windowHeight < 64 ? 64 : (windowHeight > 1200 ? 1200 : windowHeight);
00668 }
00669
00670 pause = contains(argv, argc, "-pause")!=0;
00671
00672 }
00673
00674
00675
00676 void Simulation::nearCallback(void *data, dGeomID o1, dGeomID o2){
00677 Simulation* me = (Simulation*) data;
00678 if (!me) return;
00679
00680 bool collision_treated=false;
00681
00682 for(OdeAgentList::iterator i= me->globalData.agents.begin();
00683 (i != me->globalData.agents.end()) && !collision_treated; i++){
00684 collision_treated=(*i)->getRobot()->collisionCallback(data, o1, o2);
00685 }
00686
00687 if (collision_treated) return;
00688
00689 if(!(me->collCallback(me->odeHandle, data,o1,o2))){
00690
00691
00692 int i,n;
00693 const int N = 40;
00694 dContact contact[N];
00695 n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
00696 if (n > 0) {
00697 for (i=0; i<n; i++)
00698 {
00699 contact[i].surface.mode = dContactSlip1 | dContactSlip2 |
00700 dContactSoftERP | dContactSoftCFM | dContactApprox1;
00701 contact[i].surface.mu = 0.8;
00702 contact[i].surface.slip1 = 0.005;
00703 contact[i].surface.slip2 = 0.005;
00704 contact[i].surface.soft_erp = 1;
00705 contact[i].surface.soft_cfm = 0.00001;
00706 dJointID c = dJointCreateContact (me->odeHandle.world,
00707 me->odeHandle.jointGroup,&contact[i]);
00708 dJointAttach ( c , dGeomGetBody(contact[i].geom.g1) , dGeomGetBody(contact[i].geom.g2)) ;
00709 }
00710 }
00711 }
00712 }
00713
00714
00715
00716
00717
00718
00719 void Simulation::control_c(int i){
00720 ctrl_C++ ;
00721
00722 }
00723
00724 void Simulation::cmd_handler_exit(void){
00725 signal(SIGINT,SIG_DFL);
00726 ctrl_C=0;
00727 }
00728
00729 void Simulation::cmd_handler_init(){
00730 signal(SIGINT,control_c);
00731 atexit(cmd_handler_exit);
00732 }
00733
00734 bool Simulation::control_c_pressed(){
00735 return ctrl_C!=0;
00736 }
00737
00738 void Simulation::cmd_begin_input(){
00739 cmd_handler_exit();
00740 }
00741
00742 void Simulation::cmd_end_input(){
00743 cmd_handler_init();
00744 }
00745
00746 long Simulation::timeOfDayinMS(){
00747 struct timeval t;
00748 gettimeofday(&t, 0);
00749 return t.tv_sec*1000 + t.tv_usec/1000;
00750 }
00751
00752 void Simulation::resetSyncTimer(){
00753 realtimeoffset = timeOfDayinMS();
00754 simtimeoffset = int(globalData.time*1000);
00755 }
00756
00757
00758
00759
00760 int contains(char **list, int len, const char *str){
00761 for(int i=0; i<len; i++){
00762 if(strcmp(list[i],str) == 0) return i+1;
00763 }
00764 return 0;
00765 }
00766
00767 void Simulation::usage(const char* progname){
00768 printf("Parameter: %s [-r SEED] [-x WxH] [-pause]\n", progname);
00769 printf("\t-r SEED\t\tuse SEED as random number seed\n");
00770 printf("\t-x WxH\t\twindow size of width(W) x height(H) is used (640x480 default)\n");
00771 printf("\t-pause \t\tstart in pause mode\n");
00772 }
00773
00774
00775 void showParams(const ConfigList& configs)
00776 {
00777 for(vector<Configurable*>::const_iterator i=configs.begin(); i != configs.end(); i++){
00778 (*i)->print(stdout, 0);
00779 }
00780 }
00781
00782 void changeParams(ConfigList& configs){
00783 char buffer[1024];
00784 std::cout << "Type: Parameter=Value\n";
00785 fgets( buffer, 1024, stdin);
00786 if ( strchr(buffer,'?')!=0){
00787 showParams(configs);
00788 return;
00789 }
00790
00791 char *p = strchr(buffer,'=');
00792 if (p){
00793 *p=0;
00794 double v=strtod(p+1,0);
00795 for(ConfigList::iterator i=configs.begin(); i != configs.end(); i++){
00796 if ((*i)->setParam(buffer,v))
00797 printf(" %s=\t%f \n", buffer, (*i)->getParam(buffer));
00798 }
00799 }
00800 }
00801
00802 void createNewDir(const char* base, char *newdir){
00803 struct stat s;
00804 for(int i=0; i<1000; i++){
00805 sprintf(newdir,"%s%03i", base, i);
00806 if(stat(newdir,&s)!=0){
00807 mkdir(newdir, S_IREAD | S_IWRITE | S_IEXEC | S_IRGRP | S_IXGRP );
00808 return;
00809 }
00810 }
00811 assert(1);
00812 }
00813
00814 void Simulation::setCameraHomePos(const osg::Vec3& eye, const osg::Vec3& view){
00815 osgGA::MatrixManipulator* mm =viewer->getCurrentCameraManipulator();
00816 if(mm){
00817 CameraManipulator* cameramanipulator = dynamic_cast<CameraManipulator*>(mm);
00818 if(cameramanipulator)
00819 cameramanipulator->setHome(eye, view);
00820 }
00821 }
00822
00823
00824 }
00825