1. OpenSourceRoboticsFoundation
  2. Untitled project
  3. gazebo

Commits

John Hsu  committed e1efc3e Merge

merging from default

  • Participants
  • Parent commits 16be140, c0a5168
  • Branches joint_effort_limit

Comments (0)

Files changed (90)

File cmake/FindGooglePerfTools.cmake

View file
+# -*- cmake -*-
+
+# - Find Google perftools
+# Find the Google perftools includes and libraries
+# This module defines
+#  GOOGLE_PERFTOOLS_INCLUDE_DIR, where to find heap-profiler.h, etc.
+#  GOOGLE_PERFTOOLS_FOUND, If false, do not try to use Google perftools.
+# also defined for general use are
+#  TCMALLOC_LIBRARIES, where to find the tcmalloc library.
+#  STACKTRACE_LIBRARIES, where to find the stacktrace library.
+#  PROFILER_LIBRARIES, where to find the profiler library.
+
+FIND_PATH(GOOGLE_PERFTOOLS_INCLUDE_DIR google/heap-profiler.h
+/usr/local/include
+/usr/include
+)
+
+SET(TCMALLOC_NAMES ${TCMALLOC_NAMES} tcmalloc)
+FIND_LIBRARY(TCMALLOC_LIBRARY
+  NAMES ${TCMALLOC_NAMES}
+  PATHS /usr/lib /usr/local/lib
+  )
+
+IF (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+    SET(TCMALLOC_LIBRARIES ${TCMALLOC_LIBRARY})
+    SET(GOOGLE_PERFTOOLS_FOUND "YES")
+ELSE (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+  SET(GOOGLE_PERFTOOLS_FOUND "NO")
+ENDIF (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+
+SET(STACKTRACE_NAMES ${STACKTRACE_NAMES} stacktrace)
+FIND_LIBRARY(STACKTRACE_LIBRARY
+  NAMES ${STACKTRACE_LIBRARY}
+  PATHS /usr/lib /usr/local/lib
+  )
+
+IF (STACKTRACE_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+    SET(STACKTRACE_LIBRARIES ${STACKTRACE_LIBRARY})
+ENDIF (STACKTRACE_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+
+SET(PROFILER_NAMES ${PROFILER_NAMES} profiler)
+FIND_LIBRARY(PROFILER_LIBRARY
+  NAMES ${PROFILER_LIBRARY}
+  PATHS /usr/lib /usr/local/lib
+  )
+
+IF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+    SET(PROFILER_LIBRARIES ${PROFILER_LIBRARY})
+ENDIF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+
+IF (GOOGLE_PERFTOOLS_FOUND)
+   IF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY)
+      MESSAGE(STATUS "Found Google perftools: ${GOOGLE_PERFTOOLS_LIBRARIES}")
+   ENDIF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY)
+ELSE (GOOGLE_PERFTOOLS_FOUND)
+   IF (GOOGLE_PERFTOOLS_FIND_REQUIRED)
+      MESSAGE(FATAL_ERROR "Could not find Google perftools library")
+   ENDIF (GOOGLE_PERFTOOLS_FIND_REQUIRED)
+ENDIF (GOOGLE_PERFTOOLS_FOUND)
+
+MARK_AS_ADVANCED(
+  TCMALLOC_LIBRARY
+  STACKTRACE_LIBRARY
+  PROFILER_LIBRARY
+  GOOGLE_PERFTOOLS_INCLUDE_DIR
+  )

File cmake/SearchForStuff.cmake

View file
   RESULT_VARIABLE protobuf_modversion_failed)
 
 ########################################
+# 1. can not use BUILD_TYPE_PROFILE is defined after include this module
+# 2. TODO: TOUPPER is a hack until we fix the build system to support standard build names
+if (CMAKE_BUILD_TYPE)
+  string(TOUPPER ${CMAKE_BUILD_TYPE} TMP_CMAKE_BUILD_TYPE)
+  if ("${TMP_CMAKE_BUILD_TYPE}" STREQUAL "PROFILE")
+    include (${gazebo_cmake_dir}/FindGooglePerfTools.cmake)
+    if (GOOGLE_PERFTOOLS_FOUND)
+      message(STATUS "Include google-perftools")
+    else()
+      BUILD_ERROR("Need google/heap-profiler.h (libgoogle-perftools-dev) tools to compile in Profile mode")
+    endif()
+  endif()
+endif()
+
+########################################
 if (PROTOBUF_VERSION LESS 2.3.0)
   BUILD_ERROR("Incorrect version: Gazebo requires protobuf version 2.3.0 or greater")
 endif()

File gazebo/Server.cc

View file
 
 #include "gazebo/sensors/Sensors.hh"
 
+#include "gazebo/physics/PhysicsFactory.hh"
 #include "gazebo/physics/Physics.hh"
 #include "gazebo/physics/World.hh"
 #include "gazebo/physics/Base.hh"
   v_desc.add_options()
     ("help,h", "Produce this help message.")
     ("pause,u", "Start the server in a paused state.")
+    ("physics,e", po::value<std::string>(),
+     "Specify a physics engine (ode|bullet).")
     ("play,p", po::value<std::string>(), "Play a log file.")
     ("record,r", "Record state data to disk.")
     ("seed",  po::value<double>(),
     if (this->vm.count("world_file"))
       configFilename = this->vm["world_file"].as<std::string>();
 
+    // Get the physics engine name specified from the command line, or use ""
+    // if no physics engine is specified.
+    std::string physics;
+    if (this->vm.count("physics"))
+      physics = this->vm["physics"].as<std::string>();
+
     // Load the server
-    if (!this->LoadFile(configFilename))
+    if (!this->LoadFile(configFilename, physics))
       return false;
   }
 
 }
 
 /////////////////////////////////////////////////
-bool Server::LoadFile(const std::string &_filename)
+bool Server::LoadFile(const std::string &_filename,
+                      const std::string &_physics)
 {
   // Quick test for a valid file
   FILE *test = fopen(common::find_file(_filename).c_str(), "r");
     return false;
   }
 
-  return this->LoadImpl(sdf->root);
+  return this->LoadImpl(sdf->root, _physics);
 }
 
 /////////////////////////////////////////////////
 }
 
 /////////////////////////////////////////////////
-bool Server::LoadImpl(sdf::ElementPtr _elem)
+bool Server::LoadImpl(sdf::ElementPtr _elem,
+                      const std::string &_physics)
 {
   std::string host = "";
   unsigned int port = 0;
   /// Load the physics library
   physics::load();
 
+  // If a physics engine is specified,
+  if (_physics.length())
+  {
+    // Check if physics engine name is valid
+    // This must be done after physics::load();
+    if (!physics::PhysicsFactory::IsRegistered(_physics))
+    {
+      gzerr << "Unregistered physics engine [" << _physics
+            << "], the default will be used instead.\n";
+    }
+    // Try inserting physics engine name if one is given
+    else if (_elem->HasElement("world") &&
+             _elem->GetElement("world")->HasElement("physics"))
+    {
+      _elem->GetElement("world")->GetElement("physics")
+           ->GetAttribute("type")->Set(_physics);
+    }
+    else
+    {
+      gzerr << "Cannot set physics engine: <world> does not have <physics>\n";
+    }
+  }
+
   sdf::ElementPtr worldElem = _elem->GetElement("world");
   if (worldElem)
   {

File gazebo/Server.hh

View file
     public: void PrintUsage();
     public: bool ParseArgs(int argc, char **argv);
 
-    public: bool LoadFile(const std::string &_filename="worlds/empty.world");
+    /// \brief Load a world file and optionally override physics engine type.
+    /// \param[in] _filename Name of the world file to load.
+    /// \param[in] _physics Type of physics engine to use (ode|bullet).
+    public: bool LoadFile(const std::string &_filename="worlds/empty.world",
+                          const std::string &_physics="");
+
     public: bool LoadString(const std::string &_sdfString);
     public: void Init();
     public: void Run();
 
     /// \brief Load implementation.
     /// \param[in] _elem Description of the world to load.
-    private: bool LoadImpl(sdf::ElementPtr _elem);
+    /// \param[in] _physics Type of physics engine to use (ode|bullet).
+    private: bool LoadImpl(sdf::ElementPtr _elem,
+                           const std::string &_physics="");
 
     private: static void SigInt(int _v);
 

File gazebo/common/Animation_TEST.cc

View file
   {
     common::PoseAnimation anim("test", 1.0, true);
     anim.SetTime(-0.5);
-    EXPECT_EQ(0.5, anim.GetTime());
+    EXPECT_DOUBLE_EQ(0.5, anim.GetTime());
   }
 
   {
     common::PoseAnimation anim("test", 1.0, false);
     anim.SetTime(-0.5);
-    EXPECT_EQ(0.0, anim.GetTime());
+    EXPECT_DOUBLE_EQ(0.0, anim.GetTime());
 
     anim.SetTime(1.5);
-    EXPECT_EQ(1.0, anim.GetTime());
+    EXPECT_DOUBLE_EQ(1.0, anim.GetTime());
   }
 
 
   common::PoseAnimation anim("pose_test", 5.0, false);
   common::PoseKeyFrame *key = anim.CreateKeyFrame(0.0);
 
-  EXPECT_EQ(5.0, anim.GetLength());
+  EXPECT_DOUBLE_EQ(5.0, anim.GetLength());
   anim.SetLength(10.0);
-  EXPECT_EQ(10.0, anim.GetLength());
+  EXPECT_DOUBLE_EQ(10.0, anim.GetLength());
 
   key->SetTranslation(math::Vector3(0, 0, 0));
   EXPECT_TRUE(key->GetTranslation() == math::Vector3(0, 0, 0));
   EXPECT_TRUE(key->GetRotation() == math::Quaternion(0.1, 0.2, 0.3));
 
   anim.AddTime(5.0);
-  EXPECT_EQ(5.0, anim.GetTime());
+  EXPECT_DOUBLE_EQ(5.0, anim.GetTime());
 
   anim.SetTime(4.0);
-  EXPECT_EQ(4.0, anim.GetTime());
+  EXPECT_DOUBLE_EQ(4.0, anim.GetTime());
 
   common::PoseKeyFrame interpolatedKey(-1.0);
   anim.GetInterpolatedKeyFrame(interpolatedKey);
   common::NumericKeyFrame *key = anim.CreateKeyFrame(0.0);
 
   key->SetValue(0.0);
-  EXPECT_EQ(0.0, key->GetValue());
+  EXPECT_DOUBLE_EQ(0.0, key->GetValue());
 
   key = anim.CreateKeyFrame(10.0);
   key->SetValue(30);
-  EXPECT_EQ(30, key->GetValue());
+  EXPECT_DOUBLE_EQ(30, key->GetValue());
 
   anim.AddTime(5.0);
-  EXPECT_EQ(5.0, anim.GetTime());
+  EXPECT_DOUBLE_EQ(5.0, anim.GetTime());
 
   anim.SetTime(4.0);
-  EXPECT_EQ(4.0, anim.GetTime());
+  EXPECT_DOUBLE_EQ(4.0, anim.GetTime());
 
   common::NumericKeyFrame interpolatedKey(0);
   anim.GetInterpolatedKeyFrame(interpolatedKey);
-  EXPECT_EQ(12, interpolatedKey.GetValue());
+  EXPECT_DOUBLE_EQ(12, interpolatedKey.GetValue());
 }
 
 

File gazebo/common/CMakeLists.txt

View file
   SystemPaths.hh
   Time.hh
   Timer.hh
+  UpdateInfo.hh
   Video.hh
  )
 

File gazebo/common/Color_TEST.cc

View file
 TEST(Color, Color)
 {
   common::Color clr(.1, .2, .3, 1.0);
-  EXPECT_EQ(0.1f, clr.r);
-  EXPECT_EQ(0.2f, clr.g);
-  EXPECT_EQ(0.3f, clr.b);
-  EXPECT_EQ(1.0f, clr.a);
+  EXPECT_FLOAT_EQ(0.1f, clr.r);
+  EXPECT_FLOAT_EQ(0.2f, clr.g);
+  EXPECT_FLOAT_EQ(0.3f, clr.b);
+  EXPECT_FLOAT_EQ(1.0f, clr.a);
 
   clr.Reset();
-  EXPECT_EQ(0.0f, clr.r);
-  EXPECT_EQ(0.0f, clr.g);
-  EXPECT_EQ(0.0f, clr.b);
-  EXPECT_EQ(0.0f, clr.a);
+  EXPECT_FLOAT_EQ(0.0f, clr.r);
+  EXPECT_FLOAT_EQ(0.0f, clr.g);
+  EXPECT_FLOAT_EQ(0.0f, clr.b);
+  EXPECT_FLOAT_EQ(0.0f, clr.a);
 
   clr.SetFromHSV(0, 0.5, 1.0);
-  EXPECT_EQ(1.0f, clr.r);
-  EXPECT_EQ(0.5f, clr.g);
-  EXPECT_EQ(0.5f, clr.b);
-  EXPECT_EQ(0.0f, clr.a);
+  EXPECT_FLOAT_EQ(1.0f, clr.r);
+  EXPECT_FLOAT_EQ(0.5f, clr.g);
+  EXPECT_FLOAT_EQ(0.5f, clr.b);
+  EXPECT_FLOAT_EQ(0.0f, clr.a);
 
   EXPECT_TRUE(clr.GetAsHSV() == math::Vector3(6, 0.5, 1));
 
   clr.SetFromHSV(60, 0.0, 1.0);
-  EXPECT_EQ(1.0f, clr.r);
-  EXPECT_EQ(1.0f, clr.g);
-  EXPECT_EQ(1.0f, clr.b);
-  EXPECT_EQ(0.0f, clr.a);
+  EXPECT_FLOAT_EQ(1.0f, clr.r);
+  EXPECT_FLOAT_EQ(1.0f, clr.g);
+  EXPECT_FLOAT_EQ(1.0f, clr.b);
+  EXPECT_FLOAT_EQ(0.0f, clr.a);
 
   clr.SetFromHSV(120, 0.5, 1.0);
-  EXPECT_EQ(0.5f, clr.r);
-  EXPECT_EQ(1.0f, clr.g);
-  EXPECT_EQ(0.5f, clr.b);
-  EXPECT_EQ(0.0f, clr.a);
+  EXPECT_FLOAT_EQ(0.5f, clr.r);
+  EXPECT_FLOAT_EQ(1.0f, clr.g);
+  EXPECT_FLOAT_EQ(0.5f, clr.b);
+  EXPECT_FLOAT_EQ(0.0f, clr.a);
 
   clr.SetFromHSV(180, 0.5, 1.0);
-  EXPECT_EQ(0.5f, clr.r);
-  EXPECT_EQ(1.0f, clr.g);
-  EXPECT_EQ(1.0f, clr.b);
-  EXPECT_EQ(0.0f, clr.a);
+  EXPECT_FLOAT_EQ(0.5f, clr.r);
+  EXPECT_FLOAT_EQ(1.0f, clr.g);
+  EXPECT_FLOAT_EQ(1.0f, clr.b);
+  EXPECT_FLOAT_EQ(0.0f, clr.a);
 
   clr.SetFromHSV(240, 0.5, 1.0);
-  EXPECT_EQ(0.5f, clr.r);
-  EXPECT_EQ(0.5f, clr.g);
-  EXPECT_EQ(1.0f, clr.b);
-  EXPECT_EQ(0.0f, clr.a);
+  EXPECT_FLOAT_EQ(0.5f, clr.r);
+  EXPECT_FLOAT_EQ(0.5f, clr.g);
+  EXPECT_FLOAT_EQ(1.0f, clr.b);
+  EXPECT_FLOAT_EQ(0.0f, clr.a);
 
   clr.SetFromHSV(300, 0.5, 1.0);
-  EXPECT_EQ(1.0f, clr[0]);
-  EXPECT_EQ(0.5f, clr[1]);
-  EXPECT_EQ(1.0f, clr[2]);
-  EXPECT_EQ(0.0f, clr[3]);
-  EXPECT_EQ(0.0f, clr[4]);
+  EXPECT_FLOAT_EQ(1.0f, clr[0]);
+  EXPECT_FLOAT_EQ(0.5f, clr[1]);
+  EXPECT_FLOAT_EQ(1.0f, clr[2]);
+  EXPECT_FLOAT_EQ(0.0f, clr[3]);
+  EXPECT_FLOAT_EQ(0.0f, clr[4]);
 
   clr.r = 0.1;
   clr.g = 0.2;
   clr.b = 0.3;
   clr.a = 0.4;
-  EXPECT_EQ(0.1f, clr[0]);
-  EXPECT_EQ(0.2f, clr[1]);
-  EXPECT_EQ(0.3f, clr[2]);
-  EXPECT_EQ(0.4f, clr[3]);
+  EXPECT_FLOAT_EQ(0.1f, clr[0]);
+  EXPECT_FLOAT_EQ(0.2f, clr[1]);
+  EXPECT_FLOAT_EQ(0.3f, clr[2]);
+  EXPECT_FLOAT_EQ(0.4f, clr[3]);
 
   clr.Set(0.1, 0.2, 0.3, 0.4);
   clr = clr + 0.2;

File gazebo/common/Events.cc

View file
 EventT<void (std::string)> Events::deleteEntity;
 
 EventT<void ()> Events::worldUpdateStart;
+EventT<void (const common::UpdateInfo &)> Events::worldUpdateBegin;
+
 EventT<void ()> Events::worldUpdateEnd;
 
 EventT<void ()> Events::preRender;
 
 EventT<void (std::string)> Events::diagTimerStart;
 EventT<void (std::string)> Events::diagTimerStop;
+
+/////////////////////////////////////////////////
+void Events::DisconnectWorldUpdateStart(ConnectionPtr _subscriber)
+{
+  worldUpdateStart.Disconnect(_subscriber);
+}
+
+/////////////////////////////////////////////////
+void Events::DisconnectWorldUpdateBegin(ConnectionPtr _subscriber)
+{
+  worldUpdateBegin.Disconnect(_subscriber);
+}

File gazebo/common/Events.hh

View file
 #define _EVENTS_HH_
 
 #include <string>
-#include "common/Event.hh"
+
+#include "gazebo/common/Console.hh"
+#include "gazebo/common/UpdateInfo.hh"
+#include "gazebo/common/Event.hh"
 
 namespace gazebo
 {
       public: template<typename T>
               static ConnectionPtr ConnectPause(T _subscriber)
               { return pause.Connect(_subscriber); }
+
       /// \brief Disconnect a boost::slot the the pause signal
       /// \param[in] _subscriber the subscriber to this event
       public: static void DisconnectPause(ConnectionPtr _subscriber)
               { pause.Disconnect(_subscriber); }
+
       //////////////////////////////////////////////////////////////////////////
       /// \brief Connect a boost::slot the the step signal
       /// \param[in] _subscriber the subscriber to this event
       /// \return a connection
       public: template<typename T>
               static ConnectionPtr ConnectWorldUpdateStart(T _subscriber)
-              { return worldUpdateStart.Connect(_subscriber); }
+              {
+                // Putting in this comment so the deprecation message
+                // will be found easier: GAZEBO_DEPRECATED.
+                gzerr << "Events::ConnectWorldUpdateStart is deprecated "
+                      << "in v 1.5.0. Please use "
+                      << "Events::ConnectWorldUpdateBegin\n";
+                 return worldUpdateStart.Connect(_subscriber);
+              }
+
       /// \brief Disconnect a boost::slot the the world update start signal
       /// \param[in] _subscriber the subscriber to this event
       public: static void DisconnectWorldUpdateStart(ConnectionPtr _subscriber)
-              { worldUpdateStart.Disconnect(_subscriber); }
+              GAZEBO_DEPRECATED;
+
+      //////////////////////////////////////////////////////////////////////////
+      /// \brief Connect a boost::slot the the world update start signal
+      /// \param[in] _subscriber the subscriber to this event
+      /// \return a connection
+      public: template<typename T>
+              static ConnectionPtr ConnectWorldUpdateBegin(T _subscriber)
+              { return worldUpdateBegin.Connect(_subscriber); }
+
+      /// \brief Disconnect a boost::slot the the world update start signal
+      /// \param[in] _subscriber the subscriber to this event
+      public: static void DisconnectWorldUpdateBegin(
+                  ConnectionPtr _subscriber);
+
       //////////////////////////////////////////////////////////////////////////
       /// \brief Connect a boost::slot the the world update end signal
       /// \param[in] _subscriber the subscriber to this event
       /// \brief World update has started
       public: static EventT<void ()> worldUpdateStart;
 
+      /// \brief World update has started
+      public: static EventT<void (const common::UpdateInfo &)> worldUpdateBegin;
+
       /// \brief World update has ended
       public: static EventT<void ()> worldUpdateEnd;
 

File gazebo/common/Exception.cc

File contents unchanged.

File gazebo/common/LogPlay.cc

View file
   // Read in the header.
   this->ReadHeader();
 
+  this->logCurrXml = this->logStartXml;
   this->encoding.clear();
 }
 
 /////////////////////////////////////////////////
 bool LogPlay::Step(std::string &_data)
 {
-  if (!this->logCurrXml)
+  if (this->logCurrXml == this->logStartXml)
     this->logCurrXml = this->logStartXml->FirstChildElement("chunk");
+  else if (this->logCurrXml)
+    this->logCurrXml = this->logCurrXml->NextSiblingElement("chunk");
   else
-    this->logCurrXml = this->logCurrXml->NextSiblingElement("chunk");
+    return false;
 
   return this->GetChunkData(this->logCurrXml, _data);
 }

File gazebo/common/LogRecord.cc

View file
 
 #include "gazebo/math/Rand.hh"
 
+#include "gazebo/common/Assert.hh"
 #include "gazebo/common/Events.hh"
 #include "gazebo/common/Time.hh"
 #include "gazebo/common/Console.hh"
 //////////////////////////////////////////////////
 LogRecord::LogRecord()
 {
-  this->stop = true;
+  this->running = false;
+  this->paused = false;
   this->initialized = false;
+  this->stopThread = false;
+  this->firstUpdate = true;
 
   // Get the user's home directory
   // \todo getenv is not portable, and there is no generic cross-platform
   // method. Must check OS and choose a method
   char *homePath = getenv("HOME");
+  GZ_ASSERT(homePath, "HOME environment variable is missing");
 
   if (!homePath)
-    this->logPath = boost::filesystem::path("/tmp/gazebo");
+    this->logBasePath = boost::filesystem::path("/tmp/gazebo");
   else
-    this->logPath = boost::filesystem::path(homePath);
+    this->logBasePath = boost::filesystem::path(homePath);
 
-  this->logPath /= "/.gazebo/log/";
-
-  // Add the current time
-  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
-  this->logPath /= boost::posix_time::to_iso_extended_string(now);
+  this->logBasePath /= "/.gazebo/log/";
 
   this->logsEnd = this->logs.end();
 }
 LogRecord::~LogRecord()
 {
   // Stop the write thread.
-  this->Stop();
-
-  // Delete all the log objects
-  for (Log_M::iterator iter = this->logs.begin();
-       iter != this->logs.end(); ++iter)
-  {
-    delete iter->second;
-  }
-
-  this->logs.clear();
+  this->Fini();
 }
 
 //////////////////////////////////////////////////
 bool LogRecord::Init(const std::string &_subdir)
 {
-  if (this->initialized)
+  if (_subdir.empty())
+  {
+    gzerr << "LogRecord initialization directory is empty." << std::endl;
     return false;
+  }
 
-  if (!_subdir.empty())
-    this->logPath /=  _subdir;
+  this->logSubDir = _subdir;
 
-  this->logsEnd = this->logs.end();
+  this->ClearLogs();
+
   this->initialized = true;
+  this->running = false;
+  this->paused = false;
+  this->stopThread = false;
+  this->firstUpdate = true;
 
   return true;
 }
 
-
 //////////////////////////////////////////////////
-void LogRecord::Start(const std::string &_encoding)
+bool LogRecord::Start(const std::string &_encoding)
 {
   boost::mutex::scoped_lock lock(this->controlMutex);
 
+  // Make sure ::Init has been called.
+  if (!this->initialized)
+  {
+    gzerr << "LogRecord has not been initialized." << std::endl;
+    return false;
+  }
+
   // Check to see if the logger is already started.
-  if (!this->stop)
-    return;
+  if (this->running)
+  {
+    /// \TODO replace this with gzlog
+    gzerr << "LogRecord has already been started" << std::endl;
+    return false;
+  }
+
+  // Get the current time as an ISO string.
+  std::string logTimeDir = common::Time::GetWallTimeAsISOString();
+
+  this->logCompletePath = this->logBasePath / logTimeDir / this->logSubDir;
+
+  // Create the log directory if necessary
+  if (!boost::filesystem::exists(this->logCompletePath))
+    boost::filesystem::create_directories(logCompletePath);
 
   if (_encoding != "bz2" && _encoding != "txt")
     gzthrow("Invalid log encoding[" + _encoding +
 
   this->encoding = _encoding;
 
-  // Create the log directory if necessary
-  if (!boost::filesystem::exists(this->logPath))
-    boost::filesystem::create_directories(this->logPath);
+  {
+    boost::mutex::scoped_lock logLock(this->writeMutex);
+    this->logsEnd = this->logs.end();
 
-  this->logsEnd = this->logs.end();
-
-  this->stop = false;
+    // Start all the logs
+    for (Log_M::iterator iter = this->logs.begin();
+         iter != this->logsEnd; ++iter)
+      iter->second->Start(logCompletePath);
+  }
 
   // Listen to the world update event
-  if (!this->updateConnection)
-  {
-    this->updateConnection =
-      event::Events::ConnectWorldUpdateStart(
-          boost::bind(&LogRecord::Update, this));
-  }
-  else
-  {
-    gzerr << "LogRecord has already been initialized\n";
-    return;
-  }
+  this->updateConnection = event::Events::ConnectWorldUpdateBegin(
+        boost::bind(&LogRecord::Update, this, _1));
 
-  // Start the logging thread
+  // Start the writing thread if it has not already been started
   if (!this->writeThread)
     this->writeThread = new boost::thread(boost::bind(&LogRecord::Run, this));
-  else
-  {
-    gzerr << "LogRecord has already been initialized\n";
-    return;
-  }
-}
 
-//////////////////////////////////////////////////
-bool LogRecord::GetRunning() const
-{
-  return !this->stop;
+  this->running = true;
+  this->paused = false;
+  this->firstUpdate = true;
+
+  this->startTime = this->currTime = common::Time();
+
+  return true;
 }
 
 //////////////////////////////////////////////////
 }
 
 //////////////////////////////////////////////////
-void LogRecord::Stop()
+void LogRecord::Fini()
 {
-  boost::mutex::scoped_lock lock(this->controlMutex);
+  this->stopThread = true;
 
-  this->stop = true;
-
-  // Kick the write thread
-  this->dataAvailableCondition.notify_one();
+  this->Stop();
 
   // Wait for the write thread, if it exists
   if (this->writeThread)
     this->writeThread->join();
   delete this->writeThread;
   this->writeThread = NULL;
+}
+
+//////////////////////////////////////////////////
+void LogRecord::Stop()
+{
+  boost::mutex::scoped_lock lock(this->controlMutex);
 
   // Disconnect from the world update signale
   if (this->updateConnection)
-    event::Events::DisconnectWorldUpdateStart(this->updateConnection);
+    event::Events::DisconnectWorldUpdateBegin(this->updateConnection);
   this->updateConnection.reset();
+
+  // Kick the write thread
+  this->dataAvailableCondition.notify_one();
+
+  // Remove all the logs.
+  this->ClearLogs();
+
+  // Reset the times
+  this->startTime = this->currTime = common::Time();
+
+  // Reset the flags
+  this->running = false;
+  this->paused = false;
+}
+
+//////////////////////////////////////////////////
+void LogRecord::ClearLogs()
+{
+  boost::mutex::scoped_lock logLock(this->writeMutex);
+
+  // Delete all the log objects
+  for (Log_M::iterator iter = this->logs.begin();
+      iter != this->logs.end(); ++iter)
+  {
+    delete iter->second;
+  }
+
+  this->logs.clear();
+  this->logsEnd = this->logs.end();
+}
+
+//////////////////////////////////////////////////
+void LogRecord::SetPaused(bool _paused)
+{
+  this->paused = _paused;
+}
+
+//////////////////////////////////////////////////
+bool LogRecord::GetPaused() const
+{
+  return this->paused;
+}
+
+//////////////////////////////////////////////////
+bool LogRecord::GetRunning() const
+{
+  return this->running;
 }
 
 //////////////////////////////////////////////////
 void LogRecord::Add(const std::string &_name, const std::string &_filename,
-                 boost::function<bool (std::ostringstream &)> _logCallback)
+                    boost::function<bool (std::ostringstream &)> _logCallback)
 {
-  boost::mutex::scoped_lock lock(this->controlMutex);
+  boost::mutex::scoped_lock logLock(this->writeMutex);
 
-  // Check to see if the logger is already started.
-  if (this->stop)
-    return;
+  // Check to see if the log has already been added.
+  if (this->logs.find(_name) != this->logs.end())
+  {
+    /// \todo Good place to use GZ_ASSERT
+    /// GZ_ASSERT(this->logs.find(_name)->second != NULL);
 
-  if (this->logs.find(_name) != this->logs.end())
-    gzthrow("Log file with name[" + _name + "] already exists.\n");
-
-  // Make the full path
-  boost::filesystem::path path = this->logPath / _filename;
-
-  // Make sure the file does not exist
-  if (boost::filesystem::exists(path))
-    gzthrow("Filename[" + path.string() + "], already exists\n");
+    if (this->logs.find(_name)->second->GetRelativeFilename() != _filename)
+    {
+      gzthrow(std::string("Attempting to add a duplicate log object named[")
+          + _name + "] with a filename of [" + _filename + "]\n");
+    }
+    else
+    {
+      return;
+    }
+  }
 
   LogRecord::Log *newLog;
 
   // Create a new log object
   try
   {
-    newLog = new LogRecord::Log(this, path.string(), _logCallback);
+    newLog = new LogRecord::Log(this, _filename, _logCallback);
   }
   catch(...)
   {
     gzthrow("Unable to create log. File permissions are probably bad.");
   }
 
+  if (this->running)
+    newLog->Start(this->logCompletePath);
+
   // Add the log to our map
   this->logs[_name] = newLog;
 
 //////////////////////////////////////////////////
 bool LogRecord::Remove(const std::string &_name)
 {
+  boost::mutex::scoped_lock logLock(this->writeMutex);
+
   bool result = false;
 
   Log_M::iterator iter = this->logs.find(_name);
 }
 
 //////////////////////////////////////////////////
-void LogRecord::Update()
+std::string LogRecord::GetFilename(const std::string &_name) const
 {
+  boost::mutex::scoped_lock logLock(this->writeMutex);
+
+  std::string result;
+
+  Log_M::const_iterator iter = this->logs.find(_name);
+  if (iter != this->logs.end())
+  {
+    /// \TODO GZ_ASSERT(iter->second);
+    result = iter->second->GetCompleteFilename();
+  }
+
+  return result;
+}
+
+//////////////////////////////////////////////////
+unsigned int LogRecord::GetFileSize(const std::string &_name) const
+{
+  unsigned int result = 0;
+
+  // Get the filename of the specified log object;
+  std::string filename = this->GetFilename(_name);
+
+  // Get the size of the log file on disk.
+  if (!filename.empty())
+  {
+    // Get the size of the file
+    if (!filename.empty() && boost::filesystem::exists(filename))
+      result = boost::filesystem::file_size(filename);
+  }
+
+  // Add in the contents of the write buffer. This is the data that will be
+  // written to disk soon.
   {
     boost::mutex::scoped_lock lock(this->writeMutex);
+    Log_M::const_iterator iter = this->logs.find(_name);
 
-    // Collect all the new log data. This will not write data to disk.
-    for (this->updateIter = this->logs.begin();
-         this->updateIter != this->logsEnd; ++this->updateIter)
+    if (iter != this->logs.end())
     {
-      this->updateIter->second->Update();
+      GZ_ASSERT(iter->second, "Log object is NULL");
+      result += iter->second->GetBufferSize();
     }
   }
 
-  // Signal that new data is available.
-  this->dataAvailableCondition.notify_one();
+  return result;
+}
+
+//////////////////////////////////////////////////
+void LogRecord::SetBasePath(const std::string &_path)
+{
+  // Make sure the  directory exists
+  if (!boost::filesystem::exists(_path))
+    boost::filesystem::create_directories(_path);
+
+  // Make sure we have a directory
+  if (!boost::filesystem::is_directory(_path))
+  {
+    gzerr << "Path " << _path << " is not a directory. Please only specify a "
+           << "directory for data logging.\n";
+    return;
+  }
+
+  // Make sure the path is writable.
+  // Note: This is not cross-platform compatible.
+  if (access(_path.c_str(), W_OK) != 0)
+  {
+    gzerr << "You do no have permission to write into " << _path << "\n";
+    return;
+  }
+
+  this->logBasePath = _path;
+}
+
+//////////////////////////////////////////////////
+std::string LogRecord::GetBasePath() const
+{
+  return this->logBasePath.string();
+}
+
+//////////////////////////////////////////////////
+bool LogRecord::GetFirstUpdate() const
+{
+  return this->firstUpdate;
+}
+
+//////////////////////////////////////////////////
+void LogRecord::Update(const common::UpdateInfo &_info)
+{
+  if (!this->paused)
+  {
+    unsigned int size = 0;
+
+    {
+      boost::mutex::scoped_lock lock(this->writeMutex);
+
+      // Collect all the new log data. This will not write data to disk.
+      for (this->updateIter = this->logs.begin();
+          this->updateIter != this->logsEnd; ++this->updateIter)
+      {
+        size += this->updateIter->second->Update();
+      }
+    }
+
+    if (this->firstUpdate)
+    {
+      this->firstUpdate = false;
+      this->startTime = _info.simTime;
+    }
+
+
+    // Signal that new data is available.
+    if (size > 0)
+      this->dataAvailableCondition.notify_one();
+
+    this->currTime = _info.simTime;
+  }
 }
 
 //////////////////////////////////////////////////
 void LogRecord::Run()
 {
+  if (!this->running)
+    gzerr << "Running LogRecord before it has been started." << std::endl;
+
+  this->stopThread = false;
+
   // This loop will write data to disk.
-  while (!this->stop)
+  while (!this->stopThread)
   {
     {
       // Wait for new data.
     }
 
     // Throttle the write loop.
-    common::Time::MSleep(2000);
+    common::Time::MSleep(1000);
   }
 }
 
 //////////////////////////////////////////////////
-LogRecord::Log::Log(LogRecord *_parent, const std::string &_filename,
+common::Time LogRecord::GetRunTime() const
+{
+  return this->currTime - this->startTime;
+}
+
+//////////////////////////////////////////////////
+LogRecord::Log::Log(LogRecord *_parent, const std::string &_relativeFilename,
                  boost::function<bool (std::ostringstream &)> _logCB)
 {
   this->parent = _parent;
   this->logCB = _logCB;
 
-  this->filename = _filename;
+  this->relativeFilename = _relativeFilename;
   std::ostringstream stream;
   stream << "<?xml version='1.0'?>\n"
          << "<gazebo_log>\n"
 }
 
 //////////////////////////////////////////////////
-void LogRecord::Log::Update()
+unsigned int LogRecord::Log::Update()
 {
   std::ostringstream stream;
 
+  // Get log data via the callback.
   if (this->logCB(stream) && !stream.str().empty())
   {
     const std::string encoding = this->parent->GetEncoding();
 
     this->buffer.append("</chunk>\n");
   }
+
+  return this->buffer.size();
 }
 
 //////////////////////////////////////////////////
 }
 
 //////////////////////////////////////////////////
+unsigned int LogRecord::Log::GetBufferSize()
+{
+  return this->buffer.size();
+}
+
+//////////////////////////////////////////////////
+std::string LogRecord::Log::GetRelativeFilename() const
+{
+  return this->relativeFilename;
+}
+
+//////////////////////////////////////////////////
+std::string LogRecord::Log::GetCompleteFilename() const
+{
+  return this->completePath.string();
+}
+
+//////////////////////////////////////////////////
+void LogRecord::Log::Start(const boost::filesystem::path &_path)
+{
+  // Make the full path for the log file
+  this->completePath = _path / this->relativeFilename;
+
+  // Make sure the file does not exist
+  if (boost::filesystem::exists(this->completePath))
+    gzthrow("Filename[" + this->completePath.string() + "], already exists\n");
+}
+
+//////////////////////////////////////////////////
 void LogRecord::Log::Write()
 {
   // Make sure the file is open for writing
   if (!this->logFile.is_open())
   {
     // Try to open it...
-    this->logFile.open(this->filename.c_str(),
+    this->logFile.open(this->completePath.string().c_str(),
                        std::fstream::out | std::ios::binary);
 
     // Throw an error if we couldn't open the file for writing.
     if (!this->logFile.is_open())
-      gzthrow("Unable to open file for logging:" + this->filename + "]");
+      gzthrow("Unable to open file for logging:" +
+              this->completePath.string() + "]");
   }
 
+  // Check to see if the log file still exists on disk. This will catch the
+  // case when someone deletes a log file while recording.
+  if (!boost::filesystem::exists(this->completePath.string().c_str()))
+  {
+    gzerr << "Log file[" << this->completePath << "] no longer exists. "
+          << "Unable to write log data.\n";
+
+    // We have to clear the buffer, or else it may grow indefinitely.
+    this->buffer.clear();
+    return;
+  }
+
+
   // Write out the contents of the buffer.
   this->logFile.write(this->buffer.c_str(), this->buffer.size());
   this->logFile.flush();

File gazebo/common/LogRecord.hh

View file
 #include <boost/archive/iterators/ostream_iterator.hpp>
 #include <boost/filesystem.hpp>
 
-#include "common/Event.hh"
-#include "common/SingletonT.hh"
+#include "gazebo/common/UpdateInfo.hh"
+#include "gazebo/common/Event.hh"
+#include "gazebo/common/SingletonT.hh"
 
 #define GZ_LOG_VERSION "1.0"
 
       /// \brief Stop the logger.
       public: void Stop();
 
+      /// \brief Set whether logging should pause. A paused state means the
+      /// log file is still open, but data is not written to it.
+      /// \param[in] _paused True to pause data logging.
+      /// \sa LogRecord::GetPaused
+      public: void SetPaused(bool _paused);
+
+      /// \brief Get whether logging is paused.
+      /// \return True if logging is paused.
+      /// \sa LogRecord::SetPaused
+      public: bool GetPaused() const;
+
+      /// \brief Get whether logging is running.
+      /// \return True if logging has been started.
+      public: bool GetRunning() const;
+
       /// \brief Start the logger.
       /// \param[in] _encoding The type of encoding (txt, or bz2).
-      public: void Start(const std::string &_encoding="bz2");
+      public: bool Start(const std::string &_encoding="bz2");
 
       /// \brief Get the encoding used.
       /// \return Either [txt, or bz2], where txt is plain txt and bz2 is
       /// bzip2 compressed data with Base64 encoding.
       public: const std::string &GetEncoding() const;
 
-      /// \brief Return true if running.
-      /// \return True if LogRecord has been started.
-      public: bool GetRunning() const;
+      /// \brief Get the filename for a log object.
+      /// \param[in] _name Name of the log object.
+      /// \return Filename, empty string if not found.
+      public: std::string GetFilename(const std::string &_name) const;
+
+      /// \brief Get the file size for a log object.
+      /// \param[in] _name Name of the log object.
+      /// \return Size in bytes.
+      public: unsigned int GetFileSize(const std::string &_name) const;
+
+      /// \brief Set the base path.
+      /// \param[in] _path Path to the new logging location.
+      public: void SetBasePath(const std::string &_path);
+
+      /// \brief Get the base path for a log recording.
+      /// \return Path for log recording.
+      public: std::string GetBasePath() const;
+
+      /// \brief Get the run time in sim time.
+      /// \return Run sim time.
+      public: common::Time GetRunTime() const;
+
+      /// \brief Finialize, and shutdown.
+      public: void Fini();
+
+      /// \brief Return true if an Update has not yet been completed.
+      /// \return True if an Update has not yet been completed.
+      public: bool GetFirstUpdate() const;
 
       /// \brief Update the log files
       ///
       /// Captures the current state of all registered entities, and outputs
       /// the data to their respective log files.
-      private: void Update();
+      private: void Update(const common::UpdateInfo &_info);
 
       /// \brief Run the Write loop.
       private: void Run();
 
+      /// \brief Clear and delete the log buffers.
+      private: void ClearLogs();
+
       /// \brief Write the header to file.
       // private: void WriteHeader();
 
       /// \cond
       private: class Log
       {
-        public: Log(LogRecord *_parent, const std::string &_filename,
+        /// \brief Constructor
+        /// \param[in] _parent Pointer to the LogRecord parent.
+        /// \param[in] _relativeFilename The name of the log file to
+        /// generate, sans the complete path.
+        /// \param[in] _logCB Callback function, which is used to get log
+        /// data.
+        public: Log(LogRecord *_parent, const std::string &_relativeFilename,
                     boost::function<bool (std::ostringstream &)> _logCB);
 
+        /// \brief Destructor
         public: virtual ~Log();
 
+        /// \brief Start the log.
+        /// \param[in] _path The complete path in which to put the log file.
+        public: void Start(const boost::filesystem::path &_path);
+
+        /// \brief Write data to disk.
         public: void Write();
 
-        public: void Update();
+        /// \brief Update the data buffer.
+        /// \return The size of the data buffer.
+        public: unsigned int Update();
 
+        /// \brief Clear the data buffer.
         public: void ClearBuffer();
 
+        /// \brief Get the byte size of the buffer.
+        /// \return Buffer byte size.
+        public: unsigned int GetBufferSize();
+
+        /// \brief Get the relative filename. This is the filename passed
+        /// to the constructor.
+        /// \return The relative filename.
+        public: std::string GetRelativeFilename() const;
+
+        /// \brief Get the complete filename.
+        /// \return The complete filename.
+        public: std::string GetCompleteFilename() const;
+
+        /// \brief Pointer to the log record parent.
         public: LogRecord *parent;
+
+        /// \brief Callback from which to get data.
         public: boost::function<bool (std::ostringstream &)> logCB;
+
+        /// \brief Data buffer.
         public: std::string buffer;
+
+        /// \brief The log file.
         public: std::ofstream logFile;
-        public: std::string filename;
+
+        /// \brief Relative log filename.
+        public: std::string relativeFilename;
+
+        private: boost::filesystem::path completePath;
       };
       /// \endcond
 
       /// \brief Event connected to the World update.
       private: event::ConnectionPtr updateConnection;
 
-      /// \brief True if logging is stopped.
-      private: bool stop;
+      /// \brief True if logging is running.
+      private: bool running;
 
       /// \brief Thread used to write data to disk.
       private: boost::thread *writeThread;
 
       /// \brief Mutext to protect writing.
-      private: boost::mutex writeMutex;
+      private: mutable boost::mutex writeMutex;
 
       /// \brief Mutex to protect logging control.
       private: boost::mutex controlMutex;
       private: boost::condition_variable dataAvailableCondition;
 
       /// \brief The base pathname for all the logs.
-      private: boost::filesystem::path logPath;
+      private: boost::filesystem::path logBasePath;
+
+      /// \brief The complete pathname for all the logs.
+      private: boost::filesystem::path logCompletePath;
+
+      /// \brief Subdirectory for log files. This is appended to
+      /// logBasePath.
+      private: std::string logSubDir;
 
       /// \brief Encoding format for each chunk.
       private: std::string encoding;
       /// \brief True if initialized.
       private: bool initialized;
 
+      /// \brief True to pause recording.
+      private: bool paused;
+
+      /// \brief Used to indicate the first update callback.
+      private: bool firstUpdate;
+
+      /// \brief Flag used to stop the write thread.
+      private: bool stopThread;
+
+      /// \brief Start simulation time.
+      private: common::Time startTime;
+
+      /// \brief Current simulation time.
+      private: common::Time currTime;
+
       /// \brief This is a singleton
       private: friend class SingletonT<LogRecord>;
     };

File gazebo/common/LogRecord_TEST.cc

View file
 */
 
 #include <gtest/gtest.h>
+#include <boost/filesystem.hpp>
 
+#include "gazebo/common/Exception.hh"
 #include "gazebo/common/LogRecord.hh"
 
-using namespace gazebo;
+/////////////////////////////////////////////////
+/// \brief Test LogRecord constructor and a few accessors
+TEST(LogRecord_TEST, Constructor)
+{
+  gazebo::common::LogRecord *recorder = gazebo::common::LogRecord::Instance();
 
-TEST(LogRecordTest, LogRecord)
+  char *homePath = getenv("HOME");
+  EXPECT_TRUE(homePath != NULL);
+
+  boost::filesystem::path logPath = "/tmp/gazebo";
+  if (homePath)
+    logPath = boost::filesystem::path(homePath);
+  logPath /= "/.gazebo/log/";
+
+  // Make sure the log path is correct
+  EXPECT_EQ(recorder->GetBasePath(), logPath.string());
+
+  EXPECT_FALSE(recorder->GetPaused());
+  EXPECT_FALSE(recorder->GetRunning());
+  EXPECT_TRUE(recorder->GetFirstUpdate());
+
+  // Init without a subdirectory
+  EXPECT_FALSE(recorder->Init(""));
+}
+
+/////////////////////////////////////////////////
+/// \brief Test LogRecord Start errors
+TEST(LogRecord_TEST, StartErrors)
 {
-  EXPECT_TRUE(common::LogRecord::Instance()->Init("test"));
+  gazebo::common::LogRecord *recorder = gazebo::common::LogRecord::Instance();
 
-  common::LogRecord::Instance()->Stop();
-  common::LogRecord::Instance()->Stop();
+  // Start without an init
+  {
+    EXPECT_FALSE(recorder->Start("bz2"));
+  }
 
-  common::LogRecord::Instance()->Start();
-  common::LogRecord::Instance()->Start();
+  // Invalid encoding
+  {
+    EXPECT_TRUE(recorder->Init("test"));
+    EXPECT_THROW(recorder->Start("garbage"), gazebo::common::Exception);
+  }
 
-  common::LogRecord::Instance()->Stop();
-  common::LogRecord::Instance()->Start();
+  // Double start
+  {
+    EXPECT_TRUE(recorder->Start("bz2"));
+    EXPECT_TRUE(recorder->GetRunning());
+    EXPECT_FALSE(recorder->Start("bz2"));
+  }
+}
 
+/////////////////////////////////////////////////
+/// \brief Test LogRecord Init and Start
+TEST(LogRecord_TEST, Start)
+{
+  gazebo::common::LogRecord *recorder = gazebo::common::LogRecord::Instance();
+  recorder->Init("test");
+  recorder->Start("bz2");
 
-  common::LogRecord::Instance()->Start();
-  common::LogRecord::Instance()->Stop();
+  // Make sure the right flags have been set
+  EXPECT_FALSE(recorder->GetPaused());
+  EXPECT_TRUE(recorder->GetRunning());
+  EXPECT_TRUE(recorder->GetFirstUpdate());
 
-  common::LogRecord::Instance()->Stop();
+  // Make sure the right encoding is set
+  EXPECT_EQ(recorder->GetEncoding(), std::string("bz2"));
+
+  // Make sure the log directories exist
+  EXPECT_TRUE(boost::filesystem::exists(recorder->GetBasePath()));
+  EXPECT_TRUE(boost::filesystem::is_directory(recorder->GetBasePath()));
+
+  // Run time should be zero since no update has been triggered.
+  EXPECT_EQ(recorder->GetRunTime(), gazebo::common::Time());
+
+  // Stop recording.
+  recorder->Stop();
+
+  // Make sure everything has reset.
+  EXPECT_FALSE(recorder->GetRunning());
+  EXPECT_FALSE(recorder->GetPaused());
+  EXPECT_EQ(recorder->GetRunTime(), gazebo::common::Time());
 }
 
 /////////////////////////////////////////////////

File gazebo/common/Material_TEST.cc

View file
   EXPECT_TRUE(mat.GetEmissive() == common::Color(0.1, 0.2, 0.3, 0.4));
 
   mat.SetTransparency(0.2);
-  EXPECT_EQ(0.2, mat.GetTransparency());
+  EXPECT_DOUBLE_EQ(0.2, mat.GetTransparency());
 
   mat.SetShininess(0.2);
-  EXPECT_EQ(0.2, mat.GetShininess());
+  EXPECT_DOUBLE_EQ(0.2, mat.GetShininess());
 
   mat.SetBlendFactors(.1, .5);
   double a, b;
   mat.GetBlendFactors(a, b);
-  EXPECT_EQ(.1, a);
-  EXPECT_EQ(0.5, b);
+  EXPECT_DOUBLE_EQ(.1, a);
+  EXPECT_DOUBLE_EQ(0.5, b);
 
   mat.SetBlendMode(common::Material::MODULATE);
   EXPECT_EQ(common::Material::MODULATE, mat.GetBlendMode());
   EXPECT_EQ(common::Material::BLINN, mat.GetShadeMode());
 
   mat.SetPointSize(0.2);
-  EXPECT_EQ(0.2, mat.GetPointSize());
+  EXPECT_DOUBLE_EQ(0.2, mat.GetPointSize());
 
   mat.SetDepthWrite(false);
   EXPECT_FALSE(mat.GetDepthWrite());

File gazebo/common/Mesh_TEST.cc

View file
   mesh->FillArrays(&vertArray, &indArray);
 
   int i = 0;
-  EXPECT_EQ(.5, vertArray[i++]);
-  EXPECT_EQ(-.5, vertArray[i++]);
-  EXPECT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
 
-  EXPECT_EQ(-.5, vertArray[i++]);
-  EXPECT_EQ(-.5, vertArray[i++]);
-  EXPECT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
 
-  EXPECT_EQ(-.5, vertArray[i++]);
-  EXPECT_EQ(-.5, vertArray[i++]);
-  EXPECT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
 
-  EXPECT_EQ(.5, vertArray[i++]);
-  EXPECT_EQ(-.5, vertArray[i++]);
-  EXPECT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
 
-  EXPECT_EQ(-.5, vertArray[i++]);
-  EXPECT_EQ(.5, vertArray[i++]);
-  EXPECT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
 
-  EXPECT_EQ(.5, vertArray[i++]);
-  EXPECT_EQ(.5, vertArray[i++]);
-  EXPECT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
 
-  EXPECT_EQ(.5, vertArray[i++]);
-  EXPECT_EQ(.5, vertArray[i++]);
-  EXPECT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
 
-  EXPECT_EQ(-.5, vertArray[i++]);
-  EXPECT_EQ(.5, vertArray[i++]);
-  EXPECT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(.5, vertArray[i++]);
+  EXPECT_FLOAT_EQ(-.5, vertArray[i++]);
 
   common::Mesh *newMesh = new common::Mesh();
   newMesh->SetName("testBox");

File gazebo/common/ModelDatabase.cc

View file
     if (success != CURLE_OK)
     {
       gzwarn << "Unable to connect to model database using [" << _uri
-        << "]. Only locally installed models will be available.";
+        << "]. Only locally installed models will be available.\n";
     }
 
     curl_easy_cleanup(curl);

File gazebo/common/Time.cc

View file
 #include <sys/time.h>
 #include <time.h>
 #include <math.h>
+#include <boost/date_time.hpp>
+
 #include "math/Helpers.hh"
 #include "common/Time.hh"
 #include "common/Console.hh"
 using namespace common;
 
 Time Time::wallTime;
+std::string Time::wallTimeISO;
+
 struct timespec Time::clock_resolution;
 
 /////////////////////////////////////////////////
 }
 
 /////////////////////////////////////////////////
+const std::string &Time::GetWallTimeAsISOString()
+{
+  wallTimeISO = boost::posix_time::to_iso_extended_string(
+      boost::posix_time::microsec_clock::local_time());
+
+  return wallTimeISO;
+}
+
+/////////////////////////////////////////////////
 void Time::SetToWallTime()
 {
   *this = this->GetWallTime();

File gazebo/common/Time.hh

View file
 #ifndef _TIME_HH_
 #define _TIME_HH_
 
+#include <string>
 #include <stdlib.h>
 #include <time.h>
 #include <iostream>
       /// \return the current time
       public: static const Time &GetWallTime();
 
+      /// \brief Get the wall time as an ISO string: YYYY-MM-DDTHH:MM:SS
+      /// \return The current wall time as an ISO string.
+      public: static const std::string &GetWallTimeAsISOString();
+
       /// \brief Set the time to the wall time
       public: void SetToWallTime();
 
       /// \brief a singleton value of the last GetWallTime() value
       private: static Time wallTime;
 
+      /// \brief Wall time as an ISO string.
+      private: static std::string wallTimeISO;
+
       /// \brief Correct the time so that small additions/substractions
       /// preserve the internal seconds and nanoseconds separation
       private: inline void Correct()

File gazebo/common/UpdateInfo.hh

View file
+/*
+ * Copyright 2012 Open Source Robotics Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+#ifndef _UPDATEINFO_HH_
+#define _UPDATEINFO_HH_
+
+#include <string>
+#include "gazebo/common/Time.hh"
+
+namespace gazebo
+{
+  namespace common
+  {
+    /// \class UpdateInfo UpdateInfo.hh common/common.hh
+    /// \brief Information for use in an update event.
+    class UpdateInfo
+    {
+      /// \brief Name of the world.
+      public: std::string worldName;
+
+      /// \brief Current simulation time.
+      public: common::Time simTime;
+
+      /// \brief Current real time.
+      public: common::Time realTime;
+    };
+  }
+}
+
+#endif

File gazebo/gui/CMakeLists.txt

View file
 
 set (headers
   qt.h
+  qt_test.h
   BoxMaker.hh
   CylinderMaker.hh
   EntityMaker.hh

File gazebo/gui/LightMaker.cc

View file
 
   this->light->SetLightType(this->lightTypename);
   this->light->SetPosition(math::Vector3(0, 0, 1));
+  if (this->lightTypename == "directional")
+    this->light->SetDirection(math::Vector3(.1, .1, -0.9));
 
   std::ostringstream stream;
   stream << "user_" << this->lightTypename << "_light_" << counter++;

File gazebo/gui/QTestFixture.hh

View file
 #include "gazebo/rendering/rendering.hh"
 #include "gazebo/Server.hh"
 #include "gazebo/gui/qt.h"
+#include "gazebo/gui/qt_test.h"
 
 #include "gazebo_config.h"
 #include "test_config.h"

File gazebo/gui/qt.h

View file
 #include <QApplication>
 #include <qmainwindow.h>
 #include <QAction>
-#include <QtTest/QtTest>
 
 #endif

File gazebo/gui/qt_test.h

View file
+/*
+ * Copyright 2011 Nate Koenig
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#ifndef GAZEBO_QT_TEST_HEADERS_H_
+#define GAZEBO_QT_TEST_HEADERS_H_
+
+#pragma GCC system_header
+
+#include <QtTest/QtTest>
+#endif

File gazebo/msgs/CMakeLists.txt

View file
   laserscan_stamped.proto
   light.proto
   link.proto
+  log_control.proto
+  log_status.proto
   material.proto
   meshgeom.proto
   model.proto

File gazebo/msgs/geometry.proto

View file
 
   repeated Vector3d points          = 9;
 }
-

File gazebo/msgs/image.proto

View file
   // repeated uint32 data          = 5; // Actual data, size if (step * rows)
   required bytes data          = 5; // Actual data, size if (step * rows)
 }
-
-

File gazebo/msgs/log_control.proto

View file
+package gazebo.msgs;
+
+/// \ingroup gazebo_msgs
+/// \interface LogControl
+/// \brief A message that allows for control of logging functions
+
+message LogControl
+{
+  optional bool start           = 1;
+  optional bool stop            = 2;
+  optional bool paused          = 3;
+  optional string base_path     = 4;
+}

File gazebo/msgs/log_status.proto

View file
+package gazebo.msgs;
+
+/// \ingroup gazebo_msgs
+/// \interface LogStatus
+/// \brief A message that contains information about data logging
+
+import "time.proto";
+
+message LogStatus
+{
+  message LogFile
+  {
+    enum Units
+    {
+      BYTES = 1;
+      K_BYTES = 2;
+      M_BYTES = 3;
+      G_BYTES = 4;
+    }
+
+    optional string base_path  = 1;
+    optional string full_path  = 2;
+    optional float size        = 3;
+    optional Units size_units  = 4;
+  }
+
+  optional Time sim_time     = 1;
+  optional LogFile log_file  = 2;
+}

File gazebo/msgs/visual.proto

View file
   optional bool is_static      = 12;
   optional Plugin plugin       = 13;
 }
-
-

File gazebo/msgs/world_control.proto

View file
 /// \interface WorldControl
 /// \brief A message that allows for control of world functions
 
-
-import "header.proto";
 import "world_reset.proto";
 
 message WorldControl

File gazebo/msgs/world_stats.proto

View file
   required Time  pause_time  = 3;
   required Time  real_time   = 4;
   required bool  paused      = 5;
-  optional int32 model_count = 6;
+  required uint64 iterations = 6;
+  optional int32 model_count = 7;
 }
 
 

File gazebo/physics/Base.cc

View file
  */
 
 
-#include "common/Console.hh"
-#include "common/Exception.hh"
-#include "physics/World.hh"
-#include "physics/Base.hh"
+#include "gazebo/common/Assert.hh"
+#include "gazebo/common/Console.hh"
+#include "gazebo/common/Exception.hh"
+#include "gazebo/physics/World.hh"
+#include "gazebo/physics/Base.hh"
 
 using namespace gazebo;
 using namespace physics;
 //////////////////////////////////////////////////
 void Base::Load(sdf::ElementPtr _sdf)
 {
+  GZ_ASSERT(_sdf != NULL, "_sdf parameter is NULL");
+
   this->sdf = _sdf;
   if (this->parent)
   {
 //////////////////////////////////////////////////
 void Base::UpdateParameters(sdf::ElementPtr _sdf)
 {
+  GZ_ASSERT(_sdf != NULL, "_sdf parameter is NULL");
+  GZ_ASSERT(this->sdf != NULL, "Base sdf member is NULL");
   this->sdf->Copy(_sdf);
 }
 
 //////////////////////////////////////////////////
 void Base::SetName(const std::string &_name)
 {
+  GZ_ASSERT(this->sdf != NULL, "Base sdf member is NULL");
+  GZ_ASSERT(this->sdf->GetAttribute("name"), "Base sdf missing name attribute");
   this->sdf->GetAttribute("name")->Set(_name);
 }
 
 //////////////////////////////////////////////////
 std::string Base::GetName() const
 {
+  GZ_ASSERT(this->sdf != NULL, "Base sdf member is NULL");
+
   if (this->sdf->HasAttribute("name"))
     return this->sdf->GetValueString("name");
   else
 //////////////////////////////////////////////////
 const sdf::ElementPtr Base::GetSDF()
 {
+  GZ_ASSERT(this->sdf != NULL, "Base sdf member is NULL");
   this->sdf->Update();
   return this->sdf;
 }

File gazebo/physics/CollisionState.hh

View file
       public: friend std::ostream &operator<<(std::ostream &_out,
                                  const gazebo::physics::CollisionState &_state)
       {
-        _out << "<collision name='" << _state.name << "'>\n"
-             << "<pose>" << _state.pose << "</pose>\n";
-        _out << "</collision>\n";
+        _out << "      <collision name='" << _state.name << "'>\n"
+             << "        <pose>" << _state.pose << "</pose>\n";
+        _out << "      </collision>\n";
 
         return _out;
       }

File gazebo/physics/Entity.cc

View file
 
 #include "msgs/msgs.hh"
 
-#include "common/Events.hh"
-#include "common/Console.hh"
-#include "common/Animation.hh"
-#include "common/KeyFrame.hh"
+#include "gazebo/common/Assert.hh"
+#include "gazebo/common/Events.hh"
+#include "gazebo/common/Console.hh"
+#include "gazebo/common/Animation.hh"
+#include "gazebo/common/KeyFrame.hh"
 
-#include "transport/Publisher.hh"
-#include "transport/Transport.hh"
-#include "transport/Node.hh"
+#include "gazebo/transport/Publisher.hh"
+#include "gazebo/transport/Transport.hh"
+#include "gazebo/transport/Node.hh"
 
-#include "physics/RayShape.hh"
-#include "physics/Collision.hh"
-#include "physics/Model.hh"
-#include "physics/Link.hh"
-#include "physics/World.hh"
-#include "physics/PhysicsEngine.hh"
-#include "physics/Entity.hh"
+#include "gazebo/physics/RayShape.hh"
+#include "gazebo/physics/Collision.hh"
+#include "gazebo/physics/Model.hh"
+#include "gazebo/physics/Link.hh"
+#include "gazebo/physics/World.hh"
+#include "gazebo/physics/PhysicsEngine.hh"
+#include "gazebo/physics/Entity.hh"
 
 using namespace gazebo;
 using namespace physics;
   this->prevAnimationTime = this->world->GetSimTime();
   this->animation = _anim;
   this->onAnimationComplete.clear();
-  this->animationConnection = event::Events::ConnectWorldUpdateStart(
-      boost::bind(&Entity::UpdateAnimation, this));
+  this->animationConnection = event::Events::ConnectWorldUpdateBegin(
+      boost::bind(&Entity::UpdateAnimation, this, _1));
 }
 
 //////////////////////////////////////////////////