773 lines
22 KiB
C++
773 lines
22 KiB
C++
|
/*
|
||
|
* Copyright (C) 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.
|
||
|
*
|
||
|
*/
|
||
|
#ifdef _WIN32
|
||
|
// Ensure that Winsock2.h is included before Windows.h, which can get
|
||
|
// pulled in by anybody (e.g., Boost).
|
||
|
#include <Winsock2.h>
|
||
|
#endif
|
||
|
|
||
|
#include <functional>
|
||
|
#include <boost/bind.hpp>
|
||
|
#include "gazebo/common/Assert.hh"
|
||
|
#include "gazebo/common/Time.hh"
|
||
|
|
||
|
#include "gazebo/physics/PhysicsIface.hh"
|
||
|
#include "gazebo/physics/PhysicsEngine.hh"
|
||
|
#include "gazebo/physics/World.hh"
|
||
|
#include "gazebo/sensors/Sensor.hh"
|
||
|
#include "gazebo/sensors/SensorsIface.hh"
|
||
|
#include "gazebo/sensors/SensorFactory.hh"
|
||
|
#include "gazebo/sensors/SensorManager.hh"
|
||
|
|
||
|
using namespace gazebo;
|
||
|
using namespace sensors;
|
||
|
|
||
|
/// \brief A mutex used by SensorContainer and SimTimeEventHandler
|
||
|
/// for timing coordination.
|
||
|
boost::mutex g_sensorTimingMutex;
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
SensorManager::SensorManager()
|
||
|
: initialized(false), removeAllSensors(false)
|
||
|
{
|
||
|
// sensors::IMAGE container
|
||
|
this->sensorContainers.push_back(new ImageSensorContainer());
|
||
|
|
||
|
// sensors::RAY container
|
||
|
this->sensorContainers.push_back(new SensorContainer());
|
||
|
|
||
|
// sensors::OTHER container
|
||
|
this->sensorContainers.push_back(new SensorContainer());
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
SensorManager::~SensorManager()
|
||
|
{
|
||
|
// Clean up the sensors.
|
||
|
for (SensorContainer_V::iterator iter = this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor Constainer is NULL");
|
||
|
(*iter)->Stop();
|
||
|
(*iter)->RemoveSensors();
|
||
|
delete (*iter);
|
||
|
}
|
||
|
this->sensorContainers.clear();
|
||
|
|
||
|
this->initSensors.clear();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::RunThreads()
|
||
|
{
|
||
|
// Start the non-image sensor containers. The first item in the
|
||
|
// sensorsContainers list are the image-based sensors, which rely on the
|
||
|
// rendering engine, which in turn requires that they run in the main
|
||
|
// thread.
|
||
|
for (SensorContainer_V::iterator iter = ++this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor Constainer is NULL");
|
||
|
(*iter)->Run();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::Stop()
|
||
|
{
|
||
|
// Start all the sensor containers.
|
||
|
for (SensorContainer_V::iterator iter = this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor Constainer is NULL");
|
||
|
(*iter)->Stop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::Update(bool _force)
|
||
|
{
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
if (this->worlds.empty() && physics::worlds_running() && this->initialized)
|
||
|
{
|
||
|
auto world = physics::get_world();
|
||
|
this->worlds[world->GetName()] = world;
|
||
|
world->_SetSensorsInitialized(true);
|
||
|
}
|
||
|
|
||
|
if (!this->initSensors.empty())
|
||
|
{
|
||
|
// in case things are spawned, sensors length changes
|
||
|
for (auto &sensor : this->initSensors)
|
||
|
{
|
||
|
GZ_ASSERT(sensor != NULL, "Sensor pointer is NULL");
|
||
|
GZ_ASSERT(sensor->Category() < 0 ||
|
||
|
sensor->Category() < CATEGORY_COUNT, "Sensor category is empty");
|
||
|
GZ_ASSERT(this->sensorContainers[sensor->Category()] != NULL,
|
||
|
"Sensor container is NULL");
|
||
|
|
||
|
sensor->Init();
|
||
|
this->sensorContainers[sensor->Category()]->AddSensor(sensor);
|
||
|
}
|
||
|
this->initSensors.clear();
|
||
|
for (auto &worldName_worldPtr : this->worlds)
|
||
|
worldName_worldPtr.second->_SetSensorsInitialized(true);
|
||
|
}
|
||
|
|
||
|
for (std::vector<std::string>::iterator iter = this->removeSensors.begin();
|
||
|
iter != this->removeSensors.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT(!(*iter).empty(), "Remove sensor name is empty.");
|
||
|
|
||
|
bool removed = false;
|
||
|
for (SensorContainer_V::iterator iter2 = this->sensorContainers.begin();
|
||
|
iter2 != this->sensorContainers.end() && !removed; ++iter2)
|
||
|
{
|
||
|
GZ_ASSERT((*iter2) != NULL, "SensorContainer is NULL");
|
||
|
|
||
|
removed = (*iter2)->RemoveSensor(*iter);
|
||
|
}
|
||
|
|
||
|
if (!removed)
|
||
|
{
|
||
|
gzerr << "RemoveSensor failed. The SensorManager's list of sensors "
|
||
|
<< "changed during sensor removal. This is bad, and should "
|
||
|
<< "never happen.\n";
|
||
|
}
|
||
|
}
|
||
|
this->removeSensors.clear();
|
||
|
|
||
|
if (this->removeAllSensors)
|
||
|
{
|
||
|
for (SensorContainer_V::iterator iter2 = this->sensorContainers.begin();
|
||
|
iter2 != this->sensorContainers.end(); ++iter2)
|
||
|
{
|
||
|
GZ_ASSERT((*iter2) != NULL, "SensorContainer is NULL");
|
||
|
(*iter2)->RemoveSensors();
|
||
|
}
|
||
|
this->initSensors.clear();
|
||
|
this->removeAllSensors = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Only update if there are sensors
|
||
|
if (this->sensorContainers[sensors::IMAGE]->sensors.size() > 0)
|
||
|
this->sensorContainers[sensors::IMAGE]->Update(_force);
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
bool SensorManager::SensorsInitialized()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
bool result = this->initSensors.empty();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::ResetLastUpdateTimes()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
for (SensorContainer_V::iterator iter = this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "SensorContainer is NULL");
|
||
|
(*iter)->ResetLastUpdateTimes();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::Init()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
this->simTimeEventHandler = new SimTimeEventHandler();
|
||
|
|
||
|
// Initialize all the sensor containers.
|
||
|
for (SensorContainer_V::iterator iter = this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "SensorContainer is NULL");
|
||
|
(*iter)->Init();
|
||
|
}
|
||
|
|
||
|
// Connect to the time reset event.
|
||
|
this->timeResetConnection = event::Events::ConnectTimeReset(
|
||
|
std::bind(&SensorManager::ResetLastUpdateTimes, this));
|
||
|
|
||
|
// Connect to the remove sensor event.
|
||
|
this->removeSensorConnection = event::Events::ConnectRemoveSensor(
|
||
|
std::bind(&SensorManager::RemoveSensor, this, std::placeholders::_1));
|
||
|
|
||
|
// Connect to the create sensor event.
|
||
|
this->createSensorConnection = event::Events::ConnectCreateSensor(
|
||
|
std::bind(&SensorManager::OnCreateSensor, this,
|
||
|
std::placeholders::_1, std::placeholders::_2,
|
||
|
std::placeholders::_3, std::placeholders::_4));
|
||
|
|
||
|
this->initialized = true;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::Fini()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
// Finalize all the sensor containers.
|
||
|
for (SensorContainer_V::iterator iter = this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "SensorContainer is NULL");
|
||
|
(*iter)->Fini();
|
||
|
(*iter)->Stop();
|
||
|
}
|
||
|
|
||
|
this->removeSensors.clear();
|
||
|
this->initSensors.clear();
|
||
|
this->worlds.clear();
|
||
|
|
||
|
delete this->simTimeEventHandler;
|
||
|
this->simTimeEventHandler = NULL;
|
||
|
|
||
|
this->initialized = false;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::GetSensorTypes(std::vector<std::string> &_types) const
|
||
|
{
|
||
|
sensors::SensorFactory::GetSensorTypes(_types);
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::OnCreateSensor(sdf::ElementPtr _elem,
|
||
|
const std::string &_worldName,
|
||
|
const std::string &_parentName,
|
||
|
const uint32_t _parentId)
|
||
|
{
|
||
|
this->CreateSensor(_elem, _worldName, _parentName, _parentId);
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
std::string SensorManager::CreateSensor(sdf::ElementPtr _elem,
|
||
|
const std::string &_worldName,
|
||
|
const std::string &_parentName,
|
||
|
uint32_t _parentId)
|
||
|
{
|
||
|
std::string type = _elem->Get<std::string>("type");
|
||
|
SensorPtr sensor = sensors::SensorFactory::NewSensor(type);
|
||
|
|
||
|
if (!sensor)
|
||
|
{
|
||
|
gzerr << "Unable to create sensor of type[" << type << "]\n";
|
||
|
return std::string();
|
||
|
}
|
||
|
|
||
|
// Must come before sensor->Load
|
||
|
sensor->SetParent(_parentName, _parentId);
|
||
|
|
||
|
// Load the sensor
|
||
|
sensor->Load(_worldName, _elem);
|
||
|
this->worlds[_worldName] = physics::get_world(_worldName);
|
||
|
|
||
|
// If the SensorManager has not been initialized, then it's okay to push
|
||
|
// the sensor into one of the sensor vectors because the sensor will get
|
||
|
// initialized in SensorManager::Init
|
||
|
if (!this->initialized)
|
||
|
{
|
||
|
this->sensorContainers[sensor->Category()]->AddSensor(sensor);
|
||
|
}
|
||
|
// Otherwise the SensorManager is already running, and the sensor will get
|
||
|
// initialized during the next SensorManager::Update call.
|
||
|
else
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
this->worlds[_worldName]->_SetSensorsInitialized(false);
|
||
|
this->initSensors.push_back(sensor);
|
||
|
}
|
||
|
|
||
|
return sensor->ScopedName();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
SensorPtr SensorManager::GetSensor(const std::string &_name) const
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
SensorContainer_V::const_iterator iter;
|
||
|
SensorPtr result;
|
||
|
|
||
|
// Try to find the sensor in all of the containers
|
||
|
for (iter = this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end() && !result; ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "SensorContainer is NULL");
|
||
|
result = (*iter)->GetSensor(_name);
|
||
|
}
|
||
|
|
||
|
// If the sensor was not found, then try to find based on an unscoped
|
||
|
// name.
|
||
|
// If multiple sensors exist with the same name, then an error occurs
|
||
|
// because we don't know which sensor is correct.
|
||
|
if (!result)
|
||
|
{
|
||
|
SensorPtr tmpSensor;
|
||
|
for (iter = this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "SensorContainer is NULL");
|
||
|
tmpSensor = (*iter)->GetSensor(_name, true);
|
||
|
|
||
|
if (!tmpSensor)
|
||
|
continue;
|
||
|
|
||
|
if (!result)
|
||
|
{
|
||
|
result = tmpSensor;
|
||
|
GZ_ASSERT(result != NULL, "SensorContainer contains a NULL Sensor");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gzerr << "Unable to get a sensor, multiple sensors with the same "
|
||
|
<< "name[" << _name << "]. Use a scoped name instead, "
|
||
|
<< "world_name::model_name::link_name::sensor_name.\n";
|
||
|
result.reset();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
Sensor_V SensorManager::GetSensors() const
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
Sensor_V result;
|
||
|
|
||
|
// Copy the sensor pointers
|
||
|
for (SensorContainer_V::const_iterator iter = this->sensorContainers.begin();
|
||
|
iter != this->sensorContainers.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "SensorContainer is NULL");
|
||
|
std::copy((*iter)->sensors.begin(), (*iter)->sensors.end(),
|
||
|
std::back_inserter(result));
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::RemoveSensor(const std::string &_name)
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
SensorPtr sensor = this->GetSensor(_name);
|
||
|
|
||
|
if (!sensor)
|
||
|
{
|
||
|
gzerr << "Unable to remove sensor[" << _name << "] because it "
|
||
|
<< "does not exist.\n";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Push it on the list, to be removed by the main sensor thread,
|
||
|
// to ensure correct access to rendering resources.
|
||
|
this->removeSensors.push_back(sensor->ScopedName());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::RemoveSensors()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
this->removeAllSensors = true;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
SensorManager::SensorContainer::SensorContainer()
|
||
|
{
|
||
|
this->stop = true;
|
||
|
this->initialized = false;
|
||
|
this->runThread = NULL;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
SensorManager::SensorContainer::~SensorContainer()
|
||
|
{
|
||
|
this->sensors.clear();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::Init()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
for (auto &sensor : this->sensors)
|
||
|
{
|
||
|
GZ_ASSERT(sensor != NULL, "Sensor is NULL");
|
||
|
sensor->Init();
|
||
|
}
|
||
|
|
||
|
this->initialized = true;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::Fini()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
Sensor_V::iterator iter;
|
||
|
|
||
|
// Finialize each sensor in the current sensor vector
|
||
|
for (iter = this->sensors.begin(); iter != this->sensors.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor is NULL");
|
||
|
(*iter)->Fini();
|
||
|
}
|
||
|
|
||
|
// Remove all the sensors from the current sensor vector.
|
||
|
this->sensors.clear();
|
||
|
|
||
|
this->initialized = false;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::Run()
|
||
|
{
|
||
|
this->runThread = new boost::thread(
|
||
|
boost::bind(&SensorManager::SensorContainer::RunLoop, this));
|
||
|
|
||
|
GZ_ASSERT(this->runThread, "Unable to create boost::thread.");
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::Stop()
|
||
|
{
|
||
|
this->stop = true;
|
||
|
this->runCondition.notify_all();
|
||
|
if (this->runThread)
|
||
|
{
|
||
|
// Note: calling interrupt seems to cause the thread to either block
|
||
|
// or throw an exception, so commenting it out for now.
|
||
|
// this->runThread->interrupt();
|
||
|
this->runThread->join();
|
||
|
delete this->runThread;
|
||
|
this->runThread = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::RunLoop()
|
||
|
{
|
||
|
this->stop = false;
|
||
|
|
||
|
physics::WorldPtr world = physics::get_world();
|
||
|
GZ_ASSERT(world != NULL, "Pointer to World is NULL");
|
||
|
|
||
|
physics::PhysicsEnginePtr engine = world->GetPhysicsEngine();
|
||
|
GZ_ASSERT(engine != NULL, "Pointer to PhysicsEngine is NULL");
|
||
|
|
||
|
engine->InitForThread();
|
||
|
|
||
|
// The original value was hardcode to 1.0. Changed the value to
|
||
|
// 1000 * MaxStepSize in order to handle simulation with a
|
||
|
// large step size.
|
||
|
double maxSensorUpdate = engine->GetMaxStepSize() * 1000;
|
||
|
|
||
|
common::Time sleepTime, startTime, eventTime, diffTime;
|
||
|
double maxUpdateRate = 0;
|
||
|
|
||
|
boost::mutex tmpMutex;
|
||
|
boost::mutex::scoped_lock lock2(tmpMutex);
|
||
|
|
||
|
// Wait for a sensor to be added.
|
||
|
// Use a while loop since world resets will notify the runCondition.
|
||
|
while (this->sensors.empty())
|
||
|
{
|
||
|
this->runCondition.wait(lock2);
|
||
|
if (this->stop)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
// Get the minimum update rate from the sensors.
|
||
|
for (Sensor_V::iterator iter = this->sensors.begin();
|
||
|
iter != this->sensors.end() && !this->stop; ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor is NULL");
|
||
|
maxUpdateRate = std::max((*iter)->UpdateRate(), maxUpdateRate);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Calculate an appropriate sleep time.
|
||
|
if (maxUpdateRate > 0)
|
||
|
sleepTime.Set(1.0 / (maxUpdateRate));
|
||
|
else
|
||
|
sleepTime.Set(0, 1e6);
|
||
|
|
||
|
while (!this->stop)
|
||
|
{
|
||
|
// If all the sensors get deleted, wait here.
|
||
|
// Use a while loop since world resets will notify the runCondition.
|
||
|
while (this->sensors.empty())
|
||
|
{
|
||
|
this->runCondition.wait(lock2);
|
||
|
if (this->stop)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get the start time of the update.
|
||
|
startTime = world->GetSimTime();
|
||
|
|
||
|
this->Update(false);
|
||
|
|
||
|
// Compute the time it took to update the sensors.
|
||
|
// It's possible that the world time was reset during the Update. This
|
||
|
// would case a negative diffTime. Instead, just use a event time of zero
|
||
|
diffTime = std::max(common::Time::Zero, world->GetSimTime() - startTime);
|
||
|
|
||
|
// Set the default sleep time
|
||
|
eventTime = std::max(common::Time::Zero, sleepTime - diffTime);
|
||
|
|
||
|
// Make sure update time is reasonable.
|
||
|
GZ_ASSERT(diffTime.sec < maxSensorUpdate,
|
||
|
"Took over 1000*max_step_size to update a sensor.");
|
||
|
|
||
|
// Make sure eventTime is not negative.
|
||
|
GZ_ASSERT(eventTime >= common::Time::Zero,
|
||
|
"Time to next sensor update is negative.");
|
||
|
|
||
|
boost::mutex::scoped_lock timingLock(g_sensorTimingMutex);
|
||
|
|
||
|
// Add an event to trigger when the appropriate simulation time has been
|
||
|
// reached.
|
||
|
SensorManager::Instance()->simTimeEventHandler->AddRelativeEvent(
|
||
|
eventTime, &this->runCondition);
|
||
|
|
||
|
// This if statement helps prevent deadlock on osx during teardown.
|
||
|
if (!this->stop)
|
||
|
{
|
||
|
this->runCondition.wait(timingLock);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::Update(bool _force)
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
if (this->sensors.empty())
|
||
|
gzlog << "Updating a sensor container without any sensors.\n";
|
||
|
|
||
|
// Update all the sensors in this container.
|
||
|
for (Sensor_V::iterator iter = this->sensors.begin();
|
||
|
iter != this->sensors.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor is NULL");
|
||
|
(*iter)->Update(_force);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
SensorPtr SensorManager::SensorContainer::GetSensor(const std::string &_name,
|
||
|
bool _useLeafName) const
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
SensorPtr result;
|
||
|
|
||
|
// Look for a sensor with the correct name
|
||
|
for (Sensor_V::const_iterator iter = this->sensors.begin();
|
||
|
iter != this->sensors.end() && !result; ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor is NULL");
|
||
|
|
||
|
// We match on the scoped name (model::link::sensor) because multiple
|
||
|
// sensors with the same leaf name may exist in a world.
|
||
|
if ((_useLeafName && (*iter)->Name() == _name) ||
|
||
|
(!_useLeafName && (*iter)->ScopedName() == _name))
|
||
|
{
|
||
|
result = (*iter);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::AddSensor(SensorPtr _sensor)
|
||
|
{
|
||
|
GZ_ASSERT(_sensor != NULL, "Sensor is NULL when passed to ::AddSensor");
|
||
|
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
this->sensors.push_back(_sensor);
|
||
|
}
|
||
|
|
||
|
// Tell the run loop that we have received a sensor
|
||
|
this->runCondition.notify_one();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
bool SensorManager::SensorContainer::RemoveSensor(const std::string &_name)
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
Sensor_V::iterator iter;
|
||
|
|
||
|
bool removed = false;
|
||
|
|
||
|
// Find the correct sensor based on name, and remove it.
|
||
|
for (iter = this->sensors.begin(); iter != this->sensors.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor is NULL");
|
||
|
|
||
|
if ((*iter)->ScopedName() == _name)
|
||
|
{
|
||
|
(*iter)->Fini();
|
||
|
this->sensors.erase(iter);
|
||
|
removed = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return removed;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::ResetLastUpdateTimes()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
Sensor_V::iterator iter;
|
||
|
|
||
|
// Rest last update times for all contained sensors.
|
||
|
for (iter = this->sensors.begin(); iter != this->sensors.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor is NULL");
|
||
|
(*iter)->ResetLastUpdateTime();
|
||
|
}
|
||
|
|
||
|
// Tell the run loop that world time has been reset.
|
||
|
this->runCondition.notify_one();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::SensorContainer::RemoveSensors()
|
||
|
{
|
||
|
boost::recursive_mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
Sensor_V::iterator iter;
|
||
|
|
||
|
// Remove all the sensors
|
||
|
for (iter = this->sensors.begin(); iter != this->sensors.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT((*iter) != NULL, "Sensor is NULL");
|
||
|
(*iter)->Fini();
|
||
|
}
|
||
|
|
||
|
this->sensors.clear();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void SensorManager::ImageSensorContainer::Update(bool _force)
|
||
|
{
|
||
|
event::Events::preRender();
|
||
|
|
||
|
// Tell all the cameras to render
|
||
|
event::Events::render();
|
||
|
|
||
|
event::Events::postRender();
|
||
|
|
||
|
// Update the sensors, which will produce data messages.
|
||
|
SensorContainer::Update(_force);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
SimTimeEventHandler::SimTimeEventHandler()
|
||
|
{
|
||
|
this->updateConnection = event::Events::ConnectWorldUpdateBegin(
|
||
|
boost::bind(&SimTimeEventHandler::OnUpdate, this, _1));
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
SimTimeEventHandler::~SimTimeEventHandler()
|
||
|
{
|
||
|
// Cleanup the events.
|
||
|
for (std::list<SimTimeEvent*>::iterator iter = this->events.begin();
|
||
|
iter != this->events.end(); ++iter)
|
||
|
{
|
||
|
GZ_ASSERT(*iter != NULL, "SimTimeEvent is NULL");
|
||
|
delete *iter;
|
||
|
}
|
||
|
this->events.clear();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void SimTimeEventHandler::AddRelativeEvent(const common::Time &_time,
|
||
|
boost::condition_variable *_var)
|
||
|
{
|
||
|
boost::mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
physics::WorldPtr world = physics::get_world();
|
||
|
GZ_ASSERT(world != NULL, "World pointer is NULL");
|
||
|
|
||
|
// Create the new event.
|
||
|
SimTimeEvent *event = new SimTimeEvent;
|
||
|
event->time = world->GetSimTime() + _time;
|
||
|
event->condition = _var;
|
||
|
|
||
|
// Add the event to the list.
|
||
|
this->events.push_back(event);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void SimTimeEventHandler::OnUpdate(const common::UpdateInfo &_info)
|
||
|
{
|
||
|
boost::mutex::scoped_lock timingLock(g_sensorTimingMutex);
|
||
|
boost::mutex::scoped_lock lock(this->mutex);
|
||
|
|
||
|
// Iterate over all the events.
|
||
|
for (std::list<SimTimeEvent*>::iterator iter = this->events.begin();
|
||
|
iter != this->events.end();)
|
||
|
{
|
||
|
GZ_ASSERT(*iter != NULL, "SimTimeEvent is NULL");
|
||
|
|
||
|
// Find events that have a time less than or equal to simulation
|
||
|
// time.
|
||
|
if ((*iter)->time <= _info.simTime)
|
||
|
{
|
||
|
// Notify the event by triggering its condition.
|
||
|
(*iter)->condition->notify_all();
|
||
|
|
||
|
// Remove the event.
|
||
|
delete *iter;
|
||
|
this->events.erase(iter++);
|
||
|
}
|
||
|
else
|
||
|
++iter;
|
||
|
}
|
||
|
}
|