This commit is contained in:
Chris Lovett 2021-05-13 17:40:06 -07:00
Родитель 7fe46feca1
Коммит 0edf734254
410 изменённых файлов: 58552 добавлений и 49644 удалений

Просмотреть файл

@ -10,72 +10,74 @@
#include <map>
#include "common/common_utils/UniqueValueMap.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class ApiProvider {
public:
ApiProvider(WorldSimApiBase * world_sim_api)
: world_sim_api_(world_sim_api)
class ApiProvider
{
}
virtual ~ApiProvider() = default;
public:
ApiProvider(WorldSimApiBase* world_sim_api)
: world_sim_api_(world_sim_api)
{
}
virtual ~ApiProvider() = default;
//vehicle API
virtual VehicleApiBase* getVehicleApi(const std::string& vehicle_name)
{
return vehicle_apis_.findOrDefault(vehicle_name, nullptr);
}
//vehicle API
virtual VehicleApiBase* getVehicleApi(const std::string& vehicle_name)
{
return vehicle_apis_.findOrDefault(vehicle_name, nullptr);
}
//world simulation API
virtual WorldSimApiBase* getWorldSimApi()
{
return world_sim_api_;
}
//world simulation API
virtual WorldSimApiBase* getWorldSimApi()
{
return world_sim_api_;
}
//vehicle simulation API
virtual VehicleSimApiBase* getVehicleSimApi(const std::string& vehicle_name) const
{
return vehicle_sim_apis_.findOrDefault(vehicle_name, nullptr);
}
//vehicle simulation API
virtual VehicleSimApiBase* getVehicleSimApi(const std::string& vehicle_name) const
{
return vehicle_sim_apis_.findOrDefault(vehicle_name, nullptr);
}
size_t getVehicleCount() const
{
return vehicle_apis_.valsSize();
}
void insert_or_assign(const std::string& vehicle_name, VehicleApiBase* vehicle_api,
VehicleSimApiBase* vehicle_sim_api)
{
vehicle_apis_.insert_or_assign(vehicle_name, vehicle_api);
vehicle_sim_apis_.insert_or_assign(vehicle_name, vehicle_sim_api);
}
const common_utils::UniqueValueMap<std::string, VehicleApiBase*>& getVehicleApis()
{
return vehicle_apis_;
}
const common_utils::UniqueValueMap<std::string, VehicleSimApiBase*>& getVehicleSimApis()
{
return vehicle_sim_apis_;
}
bool hasDefaultVehicle() const
{
return !(vehicle_apis_.findOrDefault("", nullptr) == nullptr &&
vehicle_sim_apis_.findOrDefault("", nullptr) == nullptr);
}
size_t getVehicleCount() const
{
return vehicle_apis_.valsSize();
}
void insert_or_assign(const std::string& vehicle_name, VehicleApiBase* vehicle_api,
VehicleSimApiBase* vehicle_sim_api)
{
vehicle_apis_.insert_or_assign(vehicle_name, vehicle_api);
vehicle_sim_apis_.insert_or_assign(vehicle_name, vehicle_sim_api);
}
const common_utils::UniqueValueMap<std::string, VehicleApiBase*>& getVehicleApis()
{
return vehicle_apis_;
}
const common_utils::UniqueValueMap<std::string, VehicleSimApiBase*>& getVehicleSimApis()
{
return vehicle_sim_apis_;
}
bool hasDefaultVehicle() const
{
return !(vehicle_apis_.findOrDefault("", nullptr) == nullptr &&
vehicle_sim_apis_.findOrDefault("", nullptr) == nullptr);
}
void makeDefaultVehicle(const std::string& vehicle_name)
{
vehicle_apis_.insert_or_assign("", vehicle_apis_.at(vehicle_name));
vehicle_sim_apis_.insert_or_assign("", vehicle_sim_apis_.at(vehicle_name));
}
void makeDefaultVehicle(const std::string& vehicle_name)
{
vehicle_apis_.insert_or_assign("", vehicle_apis_.at(vehicle_name));
vehicle_sim_apis_.insert_or_assign("", vehicle_sim_apis_.at(vehicle_name));
}
private:
WorldSimApiBase* world_sim_api_;
private:
WorldSimApiBase* world_sim_api_;
common_utils::UniqueValueMap<std::string, VehicleApiBase*> vehicle_apis_;
common_utils::UniqueValueMap<std::string, VehicleSimApiBase*> vehicle_sim_apis_;
};
}} //namespace
common_utils::UniqueValueMap<std::string, VehicleApiBase*> vehicle_apis_;
common_utils::UniqueValueMap<std::string, VehicleSimApiBase*> vehicle_sim_apis_;
};
}
} //namespace
#endif

Просмотреть файл

@ -7,15 +7,19 @@
#include <functional>
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class ApiServerBase {
public:
virtual void start(bool block, std::size_t thread_count) = 0;
virtual void stop() = 0;
class ApiServerBase
{
public:
virtual void start(bool block, std::size_t thread_count) = 0;
virtual void stop() = 0;
virtual ~ApiServerBase() = default;
};
}} //namespace
virtual ~ApiServerBase() = default;
};
}
} //namespace
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -16,120 +16,130 @@
#include "physics/Environment.hpp"
#include "api/WorldSimApiBase.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
//common methods for RCP clients of different vehicles
class RpcLibClientBase {
public:
enum class ConnectionState : uint {
Initial = 0, Connected, Disconnected, Reset, Unknown
//common methods for RCP clients of different vehicles
class RpcLibClientBase
{
public:
enum class ConnectionState : uint
{
Initial = 0,
Connected,
Disconnected,
Reset,
Unknown
};
public:
RpcLibClientBase(const string& ip_address = "localhost", uint16_t port = RpcLibPort, float timeout_sec = 60);
virtual ~RpcLibClientBase(); //required for pimpl
void confirmConnection();
void reset();
ConnectionState getConnectionState();
bool ping();
int getClientVersion() const;
int getServerVersion() const;
int getMinRequiredServerVersion() const;
int getMinRequiredClientVersion() const;
bool simIsPaused() const;
void simPause(bool is_paused);
void simContinueForTime(double seconds);
void simContinueForFrames(uint32_t frames);
void simSetTimeOfDay(bool is_enabled, const string& start_datetime = "", bool is_start_datetime_dst = false,
float celestial_clock_speed = 1, float update_interval_secs = 60, bool move_sun = true);
void simEnableWeather(bool enable);
void simSetWeatherParameter(WorldSimApiBase::WeatherParameter param, float val);
vector<string> simListSceneObjects(const string& name_regex = string(".*")) const;
Pose simGetObjectPose(const std::string& object_name) const;
bool simLoadLevel(const string& level_name);
Vector3r simGetObjectScale(const std::string& object_name) const;
bool simSetObjectPose(const std::string& object_name, const Pose& pose, bool teleport = true);
bool simSetObjectScale(const std::string& object_name, const Vector3r& scale);
//task management APIs
void cancelLastTask(const std::string& vehicle_name = "");
virtual RpcLibClientBase* waitOnLastTask(bool* task_result = nullptr, float timeout_sec = Utils::nan<float>());
bool simSetSegmentationObjectID(const std::string& mesh_name, int object_id, bool is_name_regex = false);
int simGetSegmentationObjectID(const std::string& mesh_name) const;
void simPrintLogMessage(const std::string& message, std::string message_param = "", unsigned char severity = 0);
void simFlushPersistentMarkers();
void simPlotPoints(const vector<Vector3r>& points, const vector<float>& color_rgba, float size, float duration, bool is_persistent);
void simPlotLineStrip(const vector<Vector3r>& points, const vector<float>& color_rgba, float thickness, float duration, bool is_persistent);
void simPlotLineList(const vector<Vector3r>& points, const vector<float>& color_rgba, float thickness, float duration, bool is_persistent);
void simPlotArrows(const vector<Vector3r>& points_start, const vector<Vector3r>& points_end, const vector<float>& color_rgba, float thickness, float arrow_size, float duration, bool is_persistent);
void simPlotStrings(const vector<std::string>& strings, const vector<Vector3r>& positions, float scale, const vector<float>& color_rgba, float duration);
void simPlotTransforms(const vector<Pose>& poses, float scale, float thickness, float duration, bool is_persistent);
void simPlotTransformsWithNames(const vector<Pose>& poses, const vector<std::string>& names, float tf_scale, float tf_thickness, float text_scale, const vector<float>& text_color_rgba, float duration);
bool armDisarm(bool arm, const std::string& vehicle_name = "");
bool isApiControlEnabled(const std::string& vehicle_name = "") const;
void enableApiControl(bool is_enabled, const std::string& vehicle_name = "");
msr::airlib::GeoPoint getHomeGeoPoint(const std::string& vehicle_name = "") const;
bool simRunConsoleCommand(const std::string& command);
// sensor APIs
msr::airlib::LidarData getLidarData(const std::string& lidar_name = "", const std::string& vehicle_name = "") const;
msr::airlib::ImuBase::Output getImuData(const std::string& imu_name = "", const std::string& vehicle_name = "") const;
msr::airlib::BarometerBase::Output getBarometerData(const std::string& barometer_name = "", const std::string& vehicle_name = "") const;
msr::airlib::MagnetometerBase::Output getMagnetometerData(const std::string& magnetometer_name = "", const std::string& vehicle_name = "") const;
msr::airlib::GpsBase::Output getGpsData(const std::string& gps_name = "", const std::string& vehicle_name = "") const;
msr::airlib::DistanceSensorData getDistanceSensorData(const std::string& distance_sensor_name = "", const std::string& vehicle_name = "") const;
Pose simGetVehiclePose(const std::string& vehicle_name = "") const;
void simSetVehiclePose(const Pose& pose, bool ignore_collision, const std::string& vehicle_name = "");
void simSetTraceLine(const std::vector<float>& color_rgba, float thickness = 3.0f, const std::string& vehicle_name = "");
vector<ImageCaptureBase::ImageResponse> simGetImages(vector<ImageCaptureBase::ImageRequest> request, const std::string& vehicle_name = "");
vector<uint8_t> simGetImage(const std::string& camera_name, ImageCaptureBase::ImageType type, const std::string& vehicle_name = "");
vector<MeshPositionVertexBuffersResponse> simGetMeshPositionVertexBuffers();
bool simAddVehicle(const std::string& vehicle_name, const std::string& vehicle_type, const Pose& pose, const std::string& pawn_path = "");
CollisionInfo simGetCollisionInfo(const std::string& vehicle_name = "") const;
CameraInfo simGetCameraInfo(const std::string& camera_name, const std::string& vehicle_name = "") const;
void simSetDistortionParam(const std::string& camera_name, const std::string& param_name, float value, const std::string& vehicle_name = "");
std::vector<float> simGetDistortionParams(const std::string& camera_name, const std::string& vehicle_name = "");
void simSetCameraPose(const std::string& camera_name, const Pose& pose, const std::string& vehicle_name = "");
void simSetCameraFov(const std::string& camera_name, float fov_degrees, const std::string& vehicle_name = "");
// This is a backwards-compatibility wrapper over simSetCameraPose, and can be removed in future major releases
void simSetCameraOrientation(const std::string& camera_name, const Quaternionr& orientation, const std::string& vehicle_name = "");
bool simCreateVoxelGrid(const Vector3r& position, const int& x_size, const int& y_size, const int& z_size, const float& res, const std::string& output_file);
msr::airlib::Kinematics::State simGetGroundTruthKinematics(const std::string& vehicle_name = "") const;
msr::airlib::Environment::State simGetGroundTruthEnvironment(const std::string& vehicle_name = "") const;
std::vector<std::string> simSwapTextures(const std::string& tags, int tex_id = 0, int component_id = 0, int material_id = 0);
// Recording APIs
void startRecording();
void stopRecording();
bool isRecording();
void simSetWind(const Vector3r& wind) const;
std::string getSettingsString() const;
protected:
void* getClient();
const void* getClient() const;
private:
struct impl;
std::unique_ptr<impl> pimpl_;
};
public:
RpcLibClientBase(const string& ip_address = "localhost", uint16_t port = RpcLibPort, float timeout_sec = 60);
virtual ~RpcLibClientBase(); //required for pimpl
void confirmConnection();
void reset();
ConnectionState getConnectionState();
bool ping();
int getClientVersion() const;
int getServerVersion() const;
int getMinRequiredServerVersion() const;
int getMinRequiredClientVersion() const;
bool simIsPaused() const;
void simPause(bool is_paused);
void simContinueForTime(double seconds);
void simContinueForFrames(uint32_t frames);
void simSetTimeOfDay(bool is_enabled, const string& start_datetime = "", bool is_start_datetime_dst = false,
float celestial_clock_speed = 1, float update_interval_secs = 60, bool move_sun = true);
void simEnableWeather(bool enable);
void simSetWeatherParameter(WorldSimApiBase::WeatherParameter param, float val);
vector<string> simListSceneObjects(const string& name_regex = string(".*")) const;
Pose simGetObjectPose(const std::string& object_name) const;
bool simLoadLevel(const string& level_name);
Vector3r simGetObjectScale(const std::string& object_name) const;
bool simSetObjectPose(const std::string& object_name, const Pose& pose, bool teleport = true);
bool simSetObjectScale(const std::string& object_name, const Vector3r& scale);
//task management APIs
void cancelLastTask(const std::string& vehicle_name = "");
virtual RpcLibClientBase* waitOnLastTask(bool* task_result = nullptr, float timeout_sec = Utils::nan<float>());
bool simSetSegmentationObjectID(const std::string& mesh_name, int object_id, bool is_name_regex = false);
int simGetSegmentationObjectID(const std::string& mesh_name) const;
void simPrintLogMessage(const std::string& message, std::string message_param = "", unsigned char severity = 0);
void simFlushPersistentMarkers();
void simPlotPoints(const vector<Vector3r>& points, const vector<float>& color_rgba, float size, float duration, bool is_persistent);
void simPlotLineStrip(const vector<Vector3r>& points, const vector<float>& color_rgba, float thickness, float duration, bool is_persistent);
void simPlotLineList(const vector<Vector3r>& points, const vector<float>& color_rgba, float thickness, float duration, bool is_persistent);
void simPlotArrows(const vector<Vector3r>& points_start, const vector<Vector3r>& points_end, const vector<float>& color_rgba, float thickness, float arrow_size, float duration, bool is_persistent);
void simPlotStrings(const vector<std::string>& strings, const vector<Vector3r>& positions, float scale, const vector<float>& color_rgba, float duration);
void simPlotTransforms(const vector<Pose>& poses, float scale, float thickness, float duration, bool is_persistent);
void simPlotTransformsWithNames(const vector<Pose>& poses, const vector<std::string>& names, float tf_scale, float tf_thickness, float text_scale, const vector<float>& text_color_rgba, float duration);
bool armDisarm(bool arm, const std::string& vehicle_name = "");
bool isApiControlEnabled(const std::string& vehicle_name = "") const;
void enableApiControl(bool is_enabled, const std::string& vehicle_name = "");
msr::airlib::GeoPoint getHomeGeoPoint(const std::string& vehicle_name = "") const;
bool simRunConsoleCommand(const std::string& command);
// sensor APIs
msr::airlib::LidarData getLidarData(const std::string& lidar_name = "", const std::string& vehicle_name = "") const;
msr::airlib::ImuBase::Output getImuData(const std::string& imu_name = "", const std::string& vehicle_name = "") const;
msr::airlib::BarometerBase::Output getBarometerData(const std::string& barometer_name = "", const std::string& vehicle_name = "") const;
msr::airlib::MagnetometerBase::Output getMagnetometerData(const std::string& magnetometer_name = "", const std::string& vehicle_name = "") const;
msr::airlib::GpsBase::Output getGpsData(const std::string& gps_name = "", const std::string& vehicle_name = "") const;
msr::airlib::DistanceSensorData getDistanceSensorData(const std::string& distance_sensor_name = "", const std::string& vehicle_name = "") const;
Pose simGetVehiclePose(const std::string& vehicle_name = "") const;
void simSetVehiclePose(const Pose& pose, bool ignore_collision, const std::string& vehicle_name = "");
void simSetTraceLine(const std::vector<float>& color_rgba, float thickness=3.0f, const std::string& vehicle_name = "");
vector<ImageCaptureBase::ImageResponse> simGetImages(vector<ImageCaptureBase::ImageRequest> request, const std::string& vehicle_name = "");
vector<uint8_t> simGetImage(const std::string& camera_name, ImageCaptureBase::ImageType type, const std::string& vehicle_name = "");
vector<MeshPositionVertexBuffersResponse> simGetMeshPositionVertexBuffers();
bool simAddVehicle(const std::string& vehicle_name, const std::string& vehicle_type, const Pose& pose, const std::string& pawn_path = "");
CollisionInfo simGetCollisionInfo(const std::string& vehicle_name = "") const;
CameraInfo simGetCameraInfo(const std::string& camera_name, const std::string& vehicle_name = "") const;
void simSetDistortionParam(const std::string& camera_name, const std::string& param_name, float value, const std::string& vehicle_name = "");
std::vector<float> simGetDistortionParams(const std::string& camera_name, const std::string& vehicle_name = "");
void simSetCameraPose(const std::string& camera_name, const Pose& pose, const std::string& vehicle_name = "");
void simSetCameraFov(const std::string& camera_name, float fov_degrees, const std::string& vehicle_name = "");
// This is a backwards-compatibility wrapper over simSetCameraPose, and can be removed in future major releases
void simSetCameraOrientation(const std::string& camera_name, const Quaternionr& orientation, const std::string& vehicle_name = "");
bool simCreateVoxelGrid(const Vector3r& position, const int& x_size, const int& y_size, const int& z_size, const float& res, const std::string& output_file);
msr::airlib::Kinematics::State simGetGroundTruthKinematics(const std::string& vehicle_name = "") const;
msr::airlib::Environment::State simGetGroundTruthEnvironment(const std::string& vehicle_name = "") const;
std::vector<std::string> simSwapTextures(const std::string& tags, int tex_id = 0, int component_id = 0, int material_id = 0);
// Recording APIs
void startRecording();
void stopRecording();
bool isRecording();
void simSetWind(const Vector3r& wind) const;
std::string getSettingsString() const;
protected:
void* getClient();
const void* getClient() const;
private:
struct impl;
std::unique_ptr<impl> pimpl_;
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -8,65 +8,66 @@
#include "api/ApiServerBase.hpp"
#include "api/ApiProvider.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class RpcLibServerBase : public ApiServerBase {
public:
RpcLibServerBase(ApiProvider* api_provider, const std::string& server_address, uint16_t port = RpcLibPort);
virtual ~RpcLibServerBase() override;
virtual void start(bool block, std::size_t thread_count) override;
virtual void stop() override;
class ApiNotSupported : public std::runtime_error {
class RpcLibServerBase : public ApiServerBase
{
public:
ApiNotSupported(const std::string& message)
: std::runtime_error(message) {
RpcLibServerBase(ApiProvider* api_provider, const std::string& server_address, uint16_t port = RpcLibPort);
virtual ~RpcLibServerBase() override;
virtual void start(bool block, std::size_t thread_count) override;
virtual void stop() override;
class ApiNotSupported : public std::runtime_error
{
public:
ApiNotSupported(const std::string& message)
: std::runtime_error(message)
{
}
};
protected:
void* getServer() const;
virtual VehicleApiBase* getVehicleApi(const std::string& vehicle_name)
{
auto* api = api_provider_->getVehicleApi(vehicle_name);
if (api)
return api;
else
throw ApiNotSupported("Vehicle API for '" + vehicle_name +
"' is not available. This could either because this is simulation-only API or this vehicle does not exist");
}
virtual VehicleSimApiBase* getVehicleSimApi(const std::string& vehicle_name)
{
auto* api = api_provider_->getVehicleSimApi(vehicle_name);
if (api)
return api;
else
throw ApiNotSupported("Vehicle Sim-API for '" + vehicle_name +
"' is not available. This could either because this is not a simulation or this vehicle does not exist");
}
virtual WorldSimApiBase* getWorldSimApi()
{
auto* api = api_provider_->getWorldSimApi();
if (api)
return api;
else
throw ApiNotSupported("World-Sim API "
"' is not available. This could be because this is not a simulation");
}
private:
ApiProvider* api_provider_;
struct impl;
std::unique_ptr<impl> pimpl_;
};
protected:
void* getServer() const;
virtual VehicleApiBase* getVehicleApi(const std::string& vehicle_name)
{
auto* api = api_provider_->getVehicleApi(vehicle_name);
if (api)
return api;
else
throw ApiNotSupported("Vehicle API for '" + vehicle_name +
"' is not available. This could either because this is simulation-only API or this vehicle does not exist");
}
virtual VehicleSimApiBase* getVehicleSimApi(const std::string& vehicle_name)
{
auto* api = api_provider_->getVehicleSimApi(vehicle_name);
if (api)
return api;
else
throw ApiNotSupported("Vehicle Sim-API for '" + vehicle_name +
"' is not available. This could either because this is not a simulation or this vehicle does not exist");
}
virtual WorldSimApiBase* getWorldSimApi()
{
auto* api = api_provider_->getWorldSimApi();
if (api)
return api;
else
throw ApiNotSupported("World-Sim API "
"' is not available. This could be because this is not a simulation");
}
private:
ApiProvider* api_provider_;
struct impl;
std::unique_ptr<impl> pimpl_;
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -21,200 +21,207 @@
#include <exception>
#include <string>
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
/*
/*
Vehicle controller allows to obtain state from vehicle and send control commands to the vehicle.
State can include many things including sensor data, logs, estimated state from onboard computer etc.
Control commands can be low level actuation commands or high level movement commands.
The base class defines usually available methods that all vehicle controllers may implement.
Some methods may not be applicable to specific vehicle in which case an exception may be raised or call may be ignored.
*/
class VehicleApiBase : public UpdatableObject {
public:
virtual void enableApiControl(bool is_enabled) = 0;
virtual bool isApiControlEnabled() const = 0;
virtual bool armDisarm(bool arm) = 0;
virtual GeoPoint getHomeGeoPoint() const = 0;
virtual void update() override
class VehicleApiBase : public UpdatableObject
{
UpdatableObject::update();
}
public:
virtual void enableApiControl(bool is_enabled) = 0;
virtual bool isApiControlEnabled() const = 0;
virtual bool armDisarm(bool arm) = 0;
virtual GeoPoint getHomeGeoPoint() const = 0;
virtual void cancelLastTask()
{
//if derived class supports async task then override this method
}
virtual void update() override
{
UpdatableObject::update();
}
virtual bool isReady(std::string& message) const
{
unused(message);
return true;
}
virtual void cancelLastTask()
{
//if derived class supports async task then override this method
}
virtual bool canArm() const
{
return true;
}
virtual bool isReady(std::string& message) const
{
unused(message);
return true;
}
//if vehicle supports it, call this method to send
//kinematics and other info to somewhere (ex. log viewer, file, cloud etc)
virtual void sendTelemetry(float last_interval = -1)
{
//no default action
unused(last_interval);
}
virtual bool canArm() const
{
return true;
}
//below APIs are used by FastPhysicsEngine
virtual real_T getActuation(unsigned int actuator_index) const
{
unused(actuator_index);
throw VehicleCommandNotImplementedException("getActuation API is not supported for this vehicle");
}
virtual size_t getActuatorCount() const
{
throw VehicleCommandNotImplementedException("getActuatorCount API is not supported for this vehicle");
}
//if vehicle supports it, call this method to send
//kinematics and other info to somewhere (ex. log viewer, file, cloud etc)
virtual void sendTelemetry(float last_interval = -1)
{
//no default action
unused(last_interval);
}
virtual void getStatusMessages(std::vector<std::string>& messages)
{
unused(messages);
//default implementation
}
//below APIs are used by FastPhysicsEngine
virtual real_T getActuation(unsigned int actuator_index) const
{
unused(actuator_index);
throw VehicleCommandNotImplementedException("getActuation API is not supported for this vehicle");
}
virtual size_t getActuatorCount() const
{
throw VehicleCommandNotImplementedException("getActuatorCount API is not supported for this vehicle");
}
/*
virtual void getStatusMessages(std::vector<std::string>& messages)
{
unused(messages);
//default implementation
}
/*
For RCs, there are two cases: (1) vehicle may be configured to use
RC bound to its hardware (2) vehicle may be configured to get RC data
supplied via API calls. Below two APIs are not symmetrical, i.e.,
getRCData() may or may not return same thing as setRCData().
*/
//get reading from RC bound to vehicle (if unsupported then RCData::is_valid = false)
virtual RCData getRCData() const
{
static const RCData invalid_rc_data {};
return invalid_rc_data;
}
//set external RC data to vehicle (if unsupported then returns false)
virtual bool setRCData(const RCData& rc_data)
{
unused(rc_data);
return false;
}
// Sensors APIs
virtual const SensorCollection& getSensors() const
{
throw VehicleCommandNotImplementedException("getSensors API is not supported for this vehicle");
}
// Lidar APIs
virtual LidarData getLidarData(const std::string& lidar_name) const
{
auto *lidar = static_cast<const LidarBase*>(findSensorByName(lidar_name, SensorBase::SensorType::Lidar));
if (lidar == nullptr)
throw VehicleControllerException(Utils::stringf("No lidar with name %s exist on vehicle", lidar_name.c_str()));
return lidar->getOutput();
}
// IMU API
virtual ImuBase::Output getImuData(const std::string& imu_name) const
{
auto *imu = static_cast<const ImuBase*>(findSensorByName(imu_name, SensorBase::SensorType::Imu));
if (imu == nullptr)
throw VehicleControllerException(Utils::stringf("No IMU with name %s exist on vehicle", imu_name.c_str()));
return imu->getOutput();
}
// Barometer API
virtual BarometerBase::Output getBarometerData(const std::string& barometer_name) const
{
auto *barometer = static_cast<const BarometerBase*>(findSensorByName(barometer_name, SensorBase::SensorType::Barometer));
if (barometer == nullptr)
throw VehicleControllerException(Utils::stringf("No barometer with name %s exist on vehicle", barometer_name.c_str()));
return barometer->getOutput();
}
// Magnetometer API
virtual MagnetometerBase::Output getMagnetometerData(const std::string& magnetometer_name) const
{
auto *magnetometer = static_cast<const MagnetometerBase*>(findSensorByName(magnetometer_name, SensorBase::SensorType::Magnetometer));
if (magnetometer == nullptr)
throw VehicleControllerException(Utils::stringf("No magnetometer with name %s exist on vehicle", magnetometer_name.c_str()));
return magnetometer->getOutput();
}
// Gps API
virtual GpsBase::Output getGpsData(const std::string& gps_name) const
{
auto *gps = static_cast<const GpsBase*>(findSensorByName(gps_name, SensorBase::SensorType::Gps));
if (gps == nullptr)
throw VehicleControllerException(Utils::stringf("No gps with name %s exist on vehicle", gps_name.c_str()));
return gps->getOutput();
}
// Distance Sensor API
virtual DistanceSensorData getDistanceSensorData(const std::string& distance_sensor_name) const
{
auto *distance_sensor = static_cast<const DistanceBase*>(findSensorByName(distance_sensor_name, SensorBase::SensorType::Distance));
if (distance_sensor == nullptr)
throw VehicleControllerException(Utils::stringf("No distance sensor with name %s exist on vehicle", distance_sensor_name.c_str()));
return distance_sensor->getOutput();
}
virtual ~VehicleApiBase() = default;
//exceptions
class VehicleControllerException : public std::runtime_error {
public:
VehicleControllerException(const std::string& message)
: runtime_error(message) {
//get reading from RC bound to vehicle (if unsupported then RCData::is_valid = false)
virtual RCData getRCData() const
{
static const RCData invalid_rc_data{};
return invalid_rc_data;
}
};
class VehicleCommandNotImplementedException : public VehicleControllerException {
public:
VehicleCommandNotImplementedException(const std::string& message)
: VehicleControllerException(message) {
//set external RC data to vehicle (if unsupported then returns false)
virtual bool setRCData(const RCData& rc_data)
{
unused(rc_data);
return false;
}
};
class VehicleMoveException : public VehicleControllerException {
public:
VehicleMoveException(const std::string& message)
: VehicleControllerException(message) {
// Sensors APIs
virtual const SensorCollection& getSensors() const
{
throw VehicleCommandNotImplementedException("getSensors API is not supported for this vehicle");
}
};
// Lidar APIs
virtual LidarData getLidarData(const std::string& lidar_name) const
{
auto* lidar = static_cast<const LidarBase*>(findSensorByName(lidar_name, SensorBase::SensorType::Lidar));
if (lidar == nullptr)
throw VehicleControllerException(Utils::stringf("No lidar with name %s exist on vehicle", lidar_name.c_str()));
return lidar->getOutput();
}
// IMU API
virtual ImuBase::Output getImuData(const std::string& imu_name) const
{
auto* imu = static_cast<const ImuBase*>(findSensorByName(imu_name, SensorBase::SensorType::Imu));
if (imu == nullptr)
throw VehicleControllerException(Utils::stringf("No IMU with name %s exist on vehicle", imu_name.c_str()));
return imu->getOutput();
}
// Barometer API
virtual BarometerBase::Output getBarometerData(const std::string& barometer_name) const
{
auto* barometer = static_cast<const BarometerBase*>(findSensorByName(barometer_name, SensorBase::SensorType::Barometer));
if (barometer == nullptr)
throw VehicleControllerException(Utils::stringf("No barometer with name %s exist on vehicle", barometer_name.c_str()));
return barometer->getOutput();
}
// Magnetometer API
virtual MagnetometerBase::Output getMagnetometerData(const std::string& magnetometer_name) const
{
auto* magnetometer = static_cast<const MagnetometerBase*>(findSensorByName(magnetometer_name, SensorBase::SensorType::Magnetometer));
if (magnetometer == nullptr)
throw VehicleControllerException(Utils::stringf("No magnetometer with name %s exist on vehicle", magnetometer_name.c_str()));
return magnetometer->getOutput();
}
// Gps API
virtual GpsBase::Output getGpsData(const std::string& gps_name) const
{
auto* gps = static_cast<const GpsBase*>(findSensorByName(gps_name, SensorBase::SensorType::Gps));
if (gps == nullptr)
throw VehicleControllerException(Utils::stringf("No gps with name %s exist on vehicle", gps_name.c_str()));
return gps->getOutput();
}
// Distance Sensor API
virtual DistanceSensorData getDistanceSensorData(const std::string& distance_sensor_name) const
{
auto* distance_sensor = static_cast<const DistanceBase*>(findSensorByName(distance_sensor_name, SensorBase::SensorType::Distance));
if (distance_sensor == nullptr)
throw VehicleControllerException(Utils::stringf("No distance sensor with name %s exist on vehicle", distance_sensor_name.c_str()));
return distance_sensor->getOutput();
}
virtual ~VehicleApiBase() = default;
//exceptions
class VehicleControllerException : public std::runtime_error
{
public:
VehicleControllerException(const std::string& message)
: runtime_error(message)
{
}
};
class VehicleCommandNotImplementedException : public VehicleControllerException
{
public:
VehicleCommandNotImplementedException(const std::string& message)
: VehicleControllerException(message)
{
}
};
class VehicleMoveException : public VehicleControllerException
{
public:
VehicleMoveException(const std::string& message)
: VehicleControllerException(message)
{
}
};
private:
const SensorBase* findSensorByName(const std::string& sensor_name, const SensorBase::SensorType type) const
{
const SensorBase* sensor = nullptr;
// Find sensor with the given name (for empty input name, return the first one found)
// Not efficient but should suffice given small number of sensors
uint count_sensors = getSensors().size(type);
for (uint i = 0; i < count_sensors; i++)
const SensorBase* findSensorByName(const std::string& sensor_name, const SensorBase::SensorType type) const
{
const SensorBase* current_sensor = getSensors().getByType(type, i);
if (current_sensor != nullptr && (current_sensor->getName() == sensor_name || sensor_name == ""))
{
sensor = current_sensor;
break;
const SensorBase* sensor = nullptr;
// Find sensor with the given name (for empty input name, return the first one found)
// Not efficient but should suffice given small number of sensors
uint count_sensors = getSensors().size(type);
for (uint i = 0; i < count_sensors; i++) {
const SensorBase* current_sensor = getSensors().getByType(type, i);
if (current_sensor != nullptr && (current_sensor->getName() == sensor_name || sensor_name == "")) {
sensor = current_sensor;
break;
}
}
return sensor;
}
return sensor;
}
};
}} //namespace
};
}
} //namespace
#endif

Просмотреть файл

@ -11,68 +11,72 @@
#include "physics/Environment.hpp"
#include "common/AirSimSettings.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class VehicleSimApiBase : public msr::airlib::UpdatableObject {
public:
virtual ~VehicleSimApiBase() = default;
virtual void update() override
class VehicleSimApiBase : public msr::airlib::UpdatableObject
{
UpdatableObject::update();
}
public:
virtual ~VehicleSimApiBase() = default;
//this method is called at every render tick when we want to transfer state from
//physics engine to render engine. As physics engine is halted while
//this happens, this method should do minimal processing
virtual void updateRenderedState(float dt)
{
unused(dt);
//derived class should override if needed
}
//called when render changes are required at every render tick
virtual void updateRendering(float dt)
{
unused(dt);
//derived class should override if needed
}
virtual void update() override
{
UpdatableObject::update();
}
virtual const ImageCaptureBase* getImageCapture() const = 0;
virtual ImageCaptureBase* getImageCapture()
{
return const_cast<ImageCaptureBase*>(static_cast<const VehicleSimApiBase*>(this)->getImageCapture());
}
//this method is called at every render tick when we want to transfer state from
//physics engine to render engine. As physics engine is halted while
//this happens, this method should do minimal processing
virtual void updateRenderedState(float dt)
{
unused(dt);
//derived class should override if needed
}
//called when render changes are required at every render tick
virtual void updateRendering(float dt)
{
unused(dt);
//derived class should override if needed
}
virtual void initialize() = 0;
virtual const ImageCaptureBase* getImageCapture() const = 0;
virtual ImageCaptureBase* getImageCapture()
{
return const_cast<ImageCaptureBase*>(static_cast<const VehicleSimApiBase*>(this)->getImageCapture());
}
virtual std::vector<ImageCaptureBase::ImageResponse> getImages(const std::vector<ImageCaptureBase::ImageRequest>& request) const = 0;
virtual std::vector<uint8_t> getImage(const std::string& camera_name, ImageCaptureBase::ImageType image_type) const = 0;
virtual void initialize() = 0;
virtual Pose getPose() const = 0;
virtual void setPose(const Pose& pose, bool ignore_collision) = 0;
virtual const Kinematics::State* getGroundTruthKinematics() const = 0;
virtual const msr::airlib::Environment* getGroundTruthEnvironment() const = 0;
virtual std::vector<ImageCaptureBase::ImageResponse> getImages(const std::vector<ImageCaptureBase::ImageRequest>& request) const = 0;
virtual std::vector<uint8_t> getImage(const std::string& camera_name, ImageCaptureBase::ImageType image_type) const = 0;
virtual CameraInfo getCameraInfo(const std::string& camera_name) const = 0;
virtual void setCameraPose(const std::string& camera_name, const Pose& pose) = 0;
virtual void setCameraFoV(const std::string& camera_name, float fov_degrees) = 0;
virtual void setDistortionParam(const std::string& camera_name, const std::string& param_name, float value) = 0;
virtual std::vector<float> getDistortionParams(const std::string& camera_name) = 0;
virtual Pose getPose() const = 0;
virtual void setPose(const Pose& pose, bool ignore_collision) = 0;
virtual const Kinematics::State* getGroundTruthKinematics() const = 0;
virtual const msr::airlib::Environment* getGroundTruthEnvironment() const = 0;
virtual CollisionInfo getCollisionInfo() const = 0;
virtual int getRemoteControlID() const = 0; //which RC to use, 0 is first one, -1 means disable RC (use keyborad)
virtual RCData getRCData() const = 0; //get reading from RC from simulator's host OS
virtual std::string getVehicleName() const = 0;
virtual std::string getRecordFileLine(bool is_header_line) const = 0;
virtual void toggleTrace() = 0;
virtual void setTraceLine(const std::vector<float>& color_rgba, float thickness) = 0;
virtual CameraInfo getCameraInfo(const std::string& camera_name) const = 0;
virtual void setCameraPose(const std::string& camera_name, const Pose& pose) = 0;
virtual void setCameraFoV(const std::string& camera_name, float fov_degrees) = 0;
virtual void setDistortionParam(const std::string& camera_name, const std::string& param_name, float value) = 0;
virtual std::vector<float> getDistortionParams(const std::string& camera_name) = 0;
//use pointer here because of derived classes for VehicleSetting
const AirSimSettings::VehicleSetting* getVehicleSetting() const
{
return AirSimSettings::singleton().getVehicleSetting(getVehicleName());
}
};
virtual CollisionInfo getCollisionInfo() const = 0;
virtual int getRemoteControlID() const = 0; //which RC to use, 0 is first one, -1 means disable RC (use keyborad)
virtual RCData getRCData() const = 0; //get reading from RC from simulator's host OS
virtual std::string getVehicleName() const = 0;
virtual std::string getRecordFileLine(bool is_header_line) const = 0;
virtual void toggleTrace() = 0;
virtual void setTraceLine(const std::vector<float>& color_rgba, float thickness) = 0;
} } //namespace
//use pointer here because of derived classes for VehicleSetting
const AirSimSettings::VehicleSetting* getVehicleSetting() const
{
return AirSimSettings::singleton().getVehicleSetting(getVehicleName());
}
};
}
} //namespace
#endif

Просмотреть файл

@ -7,82 +7,84 @@
#include "common/CommonStructs.hpp"
#include "common/AirSimSettings.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class WorldSimApiBase
{
public:
enum class WeatherParameter
{
Rain = 0,
Roadwetness = 1,
Snow = 2,
RoadSnow = 3,
MapleLeaf = 4,
RoadLeaf = 5,
Dust = 6,
Fog = 7,
Enabled = 8
};
virtual ~WorldSimApiBase() = default;
class WorldSimApiBase {
public:
enum class WeatherParameter {
Rain = 0,
Roadwetness = 1,
Snow = 2,
RoadSnow = 3,
MapleLeaf = 4,
RoadLeaf = 5,
Dust = 6,
Fog = 7,
Enabled = 8
// ------ Level setting apis ----- //
virtual bool loadLevel(const std::string& level_name) = 0;
virtual string spawnObject(string& object_name, const string& load_component, const Pose& pose, const Vector3r& scale, bool physics_enabled) = 0;
virtual bool destroyObject(const string& object_name) = 0;
virtual bool isPaused() const = 0;
virtual void reset() = 0;
virtual void pause(bool is_paused) = 0;
virtual void continueForTime(double seconds) = 0;
virtual void continueForFrames(uint32_t frames) = 0;
virtual void setTimeOfDay(bool is_enabled, const std::string& start_datetime, bool is_start_datetime_dst,
float celestial_clock_speed, float update_interval_secs, bool move_sun) = 0;
virtual void enableWeather(bool enable) = 0;
virtual void setWeatherParameter(WeatherParameter param, float val) = 0;
virtual bool setSegmentationObjectID(const std::string& mesh_name, int object_id, bool is_name_regex = false) = 0;
virtual int getSegmentationObjectID(const std::string& mesh_name) const = 0;
virtual bool addVehicle(const std::string& vehicle_name, const std::string& vehicle_type, const Pose& pose, const std::string& pawn_path = "") = 0;
virtual void printLogMessage(const std::string& message,
const std::string& message_param = "", unsigned char severity = 0) = 0;
//----------- Plotting APIs ----------/
virtual void simFlushPersistentMarkers() = 0;
virtual void simPlotPoints(const vector<Vector3r>& points, const vector<float>& color_rgba, float size, float duration, bool is_persistent) = 0;
virtual void simPlotLineStrip(const vector<Vector3r>& points, const vector<float>& color_rgba, float thickness, float duration, bool is_persistent) = 0;
virtual void simPlotLineList(const vector<Vector3r>& points, const vector<float>& color_rgba, float thickness, float duration, bool is_persistent) = 0;
virtual void simPlotArrows(const vector<Vector3r>& points_start, const vector<Vector3r>& points_end, const vector<float>& color_rgba, float thickness, float arrow_size, float duration, bool is_persistent) = 0;
virtual void simPlotStrings(const vector<std::string>& strings, const vector<Vector3r>& positions, float scale, const vector<float>& color_rgba, float duration) = 0;
virtual void simPlotTransforms(const vector<Pose>& poses, float scale, float thickness, float duration, bool is_persistent) = 0;
virtual void simPlotTransformsWithNames(const vector<Pose>& poses, const vector<std::string>& names, float tf_scale, float tf_thickness, float text_scale, const vector<float>& text_color_rgba, float duration) = 0;
virtual std::vector<std::string> listSceneObjects(const std::string& name_regex) const = 0;
virtual Pose getObjectPose(const std::string& object_name) const = 0;
virtual Vector3r getObjectScale(const std::string& object_name) const = 0;
virtual bool setObjectPose(const std::string& object_name, const Pose& pose, bool teleport) = 0;
virtual bool runConsoleCommand(const std::string& command) = 0;
virtual bool setObjectScale(const std::string& object_name, const Vector3r& scale) = 0;
virtual std::unique_ptr<std::vector<std::string>> swapTextures(const std::string& tag, int tex_id = 0, int component_id = 0, int material_id = 0) = 0;
virtual vector<MeshPositionVertexBuffersResponse> getMeshPositionVertexBuffers() const = 0;
virtual bool createVoxelGrid(const Vector3r& position, const int& x_size, const int& y_size, const int& z_size, const float& res, const std::string& output_file) = 0;
// Recording APIs
virtual void startRecording() = 0;
virtual void stopRecording() = 0;
virtual bool isRecording() const = 0;
virtual void setWind(const Vector3r& wind) const = 0;
virtual std::string getSettingsString() const = 0;
};
virtual ~WorldSimApiBase() = default;
// ------ Level setting apis ----- //
virtual bool loadLevel(const std::string& level_name) = 0;
virtual string spawnObject(string& object_name, const string& load_component, const Pose& pose, const Vector3r& scale, bool physics_enabled) = 0;
virtual bool destroyObject(const string& object_name) = 0;
virtual bool isPaused() const = 0;
virtual void reset() = 0;
virtual void pause(bool is_paused) = 0;
virtual void continueForTime(double seconds) = 0;
virtual void continueForFrames(uint32_t frames) = 0;
virtual void setTimeOfDay(bool is_enabled, const std::string& start_datetime, bool is_start_datetime_dst,
float celestial_clock_speed, float update_interval_secs, bool move_sun) = 0;
virtual void enableWeather(bool enable) = 0;
virtual void setWeatherParameter(WeatherParameter param, float val) = 0;
virtual bool setSegmentationObjectID(const std::string& mesh_name, int object_id, bool is_name_regex = false) = 0;
virtual int getSegmentationObjectID(const std::string& mesh_name) const = 0;
virtual bool addVehicle(const std::string& vehicle_name, const std::string& vehicle_type, const Pose& pose, const std::string& pawn_path = "") = 0;
virtual void printLogMessage(const std::string& message,
const std::string& message_param = "", unsigned char severity = 0) = 0;
//----------- Plotting APIs ----------/
virtual void simFlushPersistentMarkers() = 0;
virtual void simPlotPoints(const vector<Vector3r>& points, const vector<float>& color_rgba, float size, float duration, bool is_persistent) = 0;
virtual void simPlotLineStrip(const vector<Vector3r>& points, const vector<float>& color_rgba, float thickness, float duration, bool is_persistent) = 0;
virtual void simPlotLineList(const vector<Vector3r>& points, const vector<float>& color_rgba, float thickness, float duration, bool is_persistent) = 0;
virtual void simPlotArrows(const vector<Vector3r>& points_start, const vector<Vector3r>& points_end, const vector<float>& color_rgba, float thickness, float arrow_size, float duration, bool is_persistent) = 0;
virtual void simPlotStrings(const vector<std::string>& strings, const vector<Vector3r>& positions, float scale, const vector<float>& color_rgba, float duration) = 0;
virtual void simPlotTransforms(const vector<Pose>& poses, float scale, float thickness, float duration, bool is_persistent) = 0;
virtual void simPlotTransformsWithNames(const vector<Pose>& poses, const vector<std::string>& names, float tf_scale, float tf_thickness, float text_scale, const vector<float>& text_color_rgba, float duration) = 0;
virtual std::vector<std::string> listSceneObjects(const std::string& name_regex) const = 0;
virtual Pose getObjectPose(const std::string& object_name) const = 0;
virtual Vector3r getObjectScale(const std::string& object_name) const = 0;
virtual bool setObjectPose(const std::string& object_name, const Pose& pose, bool teleport) = 0;
virtual bool runConsoleCommand(const std::string& command) = 0;
virtual bool setObjectScale(const std::string& object_name, const Vector3r& scale) = 0;
virtual std::unique_ptr<std::vector<std::string>> swapTextures(const std::string& tag, int tex_id = 0, int component_id = 0, int material_id = 0) = 0;
virtual vector<MeshPositionVertexBuffersResponse> getMeshPositionVertexBuffers() const = 0;
virtual bool createVoxelGrid(const Vector3r& position, const int& x_size, const int& y_size, const int& z_size, const float& res, const std::string& output_file) = 0;
// Recording APIs
virtual void startRecording() = 0;
virtual void stopRecording() = 0;
virtual bool isRecording() const = 0;
virtual void setWind(const Vector3r& wind) const = 0;
virtual std::string getSettingsString() const = 0;
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -1310,7 +1310,6 @@ namespace airlib
createDefaultSensorSettings(simmode_name, sensors);
}
};
}
} //namespace
#endif

Просмотреть файл

@ -9,96 +9,100 @@
#include "common/Common.hpp"
#include "common/common_utils/Utils.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class CancelToken {
public:
CancelToken()
: is_cancelled_(false), is_complete_(false), recursion_count_(0)
class CancelToken
{
}
void reset()
{
is_cancelled_ = false;
is_complete_ = false;
recursion_count_ = 0;
}
bool isCancelled() const
{
return is_cancelled_;
}
void cancel()
{
is_cancelled_ = true;
}
bool sleep(double secs)
{
//We can pass duration directly to sleep_for however it is known that on
//some systems, sleep_for makes system call anyway even if passed duration
//is <= 0. This can cause 50us of delay due to context switch.
if (isCancelled()) {
return false;
public:
CancelToken()
: is_cancelled_(false), is_complete_(false), recursion_count_(0)
{
}
TTimePoint start = ClockFactory::get()->nowNanos();
static constexpr std::chrono::duration<double> MinSleepDuration(0);
while (secs > 0 && !isCancelled() &&
ClockFactory::get()->elapsedSince(start) < secs) {
std::this_thread::sleep_for(MinSleepDuration);
void reset()
{
is_cancelled_ = false;
is_complete_ = false;
recursion_count_ = 0;
}
return !isCancelled();
}
bool isCancelled() const
{
return is_cancelled_;
}
void complete(bool is_complete = true)
{
is_complete_ = is_complete;
}
void cancel()
{
is_cancelled_ = true;
}
bool isComplete() const
{
return is_complete_;
}
bool sleep(double secs)
{
//We can pass duration directly to sleep_for however it is known that on
//some systems, sleep_for makes system call anyway even if passed duration
//is <= 0. This can cause 50us of delay due to context switch.
if (isCancelled()) {
return false;
}
int getRecursionCount()
{
return recursion_count_;
}
TTimePoint start = ClockFactory::get()->nowNanos();
static constexpr std::chrono::duration<double> MinSleepDuration(0);
bool try_lock()
{
bool result = wait_mutex_.try_lock();
if (result)
while (secs > 0 && !isCancelled() &&
ClockFactory::get()->elapsedSince(start) < secs) {
std::this_thread::sleep_for(MinSleepDuration);
}
return !isCancelled();
}
void complete(bool is_complete = true)
{
is_complete_ = is_complete;
}
bool isComplete() const
{
return is_complete_;
}
int getRecursionCount()
{
return recursion_count_;
}
bool try_lock()
{
bool result = wait_mutex_.try_lock();
if (result)
++recursion_count_;
return result;
}
void unlock()
{
wait_mutex_.unlock();
if (recursion_count_ > 0)
--recursion_count_;
}
void lock()
{
wait_mutex_.lock();
++recursion_count_;
return result;
}
}
void unlock()
{
wait_mutex_.unlock();
if (recursion_count_ > 0)
--recursion_count_;
}
private:
std::atomic<bool> is_cancelled_;
std::atomic<bool> is_complete_;
std::atomic<int> recursion_count_;
void lock()
{
wait_mutex_.lock();
++recursion_count_;
}
private:
std::atomic<bool> is_cancelled_;
std::atomic<bool> is_complete_;
std::atomic<int> recursion_count_;
std::recursive_mutex wait_mutex_;
};
}} //namespace
std::recursive_mutex wait_mutex_;
};
}
} //namespace
#endif

Просмотреть файл

@ -8,86 +8,89 @@
#include <chrono>
#include "Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class ClockBase {
public:
//returns value indicating nanoseconds elapsed since some reference timepoint in history
//typically nanoseconds from Unix epoch
virtual TTimePoint nowNanos() const = 0;
virtual TTimePoint getStart() const = 0;
ClockBase()
class ClockBase
{
wall_clock_start_ = Utils::getTimeSinceEpochNanos();
}
public:
//returns value indicating nanoseconds elapsed since some reference timepoint in history
//typically nanoseconds from Unix epoch
virtual TTimePoint nowNanos() const = 0;
virtual TTimePoint getStart() const = 0;
TTimeDelta elapsedSince(TTimePoint since) const
{
return elapsedBetween(nowNanos(), since);
}
static TTimeDelta elapsedBetween(TTimePoint second, TTimePoint first)
{
return (second - first) / 1.0E9;
}
TTimePoint addTo(TTimePoint t, TTimeDelta dt)
{
return static_cast<TTimePoint>(t + dt * 1.0E9);
}
TTimeDelta updateSince(TTimePoint& since) const
{
TTimePoint cur = nowNanos();
TTimeDelta elapsed = elapsedBetween(cur, since);
since = cur;
return elapsed;
}
ClockBase()
{
wall_clock_start_ = Utils::getTimeSinceEpochNanos();
}
virtual TTimePoint step()
{
//by default step doesn't do anything
//for steppeble clock, this would advance to next tick
//for wall clocks, step() is no-op
++step_count_;
TTimeDelta elapsedSince(TTimePoint since) const
{
return elapsedBetween(nowNanos(), since);
}
static TTimeDelta elapsedBetween(TTimePoint second, TTimePoint first)
{
return (second - first) / 1.0E9;
}
TTimePoint addTo(TTimePoint t, TTimeDelta dt)
{
return static_cast<TTimePoint>(t + dt * 1.0E9);
}
TTimeDelta updateSince(TTimePoint& since) const
{
TTimePoint cur = nowNanos();
TTimeDelta elapsed = elapsedBetween(cur, since);
since = cur;
return elapsed;
}
return nowNanos();
}
virtual TTimePoint step()
{
//by default step doesn't do anything
//for steppeble clock, this would advance to next tick
//for wall clocks, step() is no-op
++step_count_;
uint64_t getStepCount() const
{
return step_count_;
}
return nowNanos();
}
virtual void sleep_for(TTimeDelta dt)
{
if (dt <= 0)
return;
uint64_t getStepCount() const
{
return step_count_;
}
static constexpr std::chrono::duration<double> MinSleepDuration(0);
TTimePoint start = nowNanos();
//spin wait
while (elapsedSince(start) < dt)
std::this_thread::sleep_for(MinSleepDuration);
}
virtual void sleep_for(TTimeDelta dt)
{
if (dt <= 0)
return;
double getTrueScaleWrtWallClock()
{
TTimePoint wall_clock_now = Utils::getTimeSinceEpochNanos();
TTimeDelta wall_clock_elapsed = elapsedBetween(wall_clock_now, wall_clock_start_);
static constexpr std::chrono::duration<double> MinSleepDuration(0);
TTimePoint start = nowNanos();
//spin wait
while (elapsedSince(start) < dt)
std::this_thread::sleep_for(MinSleepDuration);
}
TTimePoint clock_now = nowNanos();
TTimeDelta clock_elapsed = elapsedBetween(clock_now, getStart());
double getTrueScaleWrtWallClock()
{
TTimePoint wall_clock_now = Utils::getTimeSinceEpochNanos();
TTimeDelta wall_clock_elapsed = elapsedBetween(wall_clock_now, wall_clock_start_);
return static_cast<double>(clock_elapsed) / wall_clock_elapsed;
}
TTimePoint clock_now = nowNanos();
TTimeDelta clock_elapsed = elapsedBetween(clock_now, getStart());
private:
template <typename T>
using duration = std::chrono::duration<T>;
return static_cast<double>(clock_elapsed) / wall_clock_elapsed;
}
uint64_t step_count_ = 0;
TTimePoint wall_clock_start_;
};
private:
template <typename T>
using duration = std::chrono::duration<T>;
}} //namespace
uint64_t step_count_ = 0;
TTimePoint wall_clock_start_;
};
}
} //namespace
#endif

Просмотреть файл

@ -7,32 +7,36 @@
#include "ScalableClock.hpp"
#include <memory>
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class ClockFactory {
public:
//output of this function should not be stored as pointer might change
static ClockBase* get(std::shared_ptr<ClockBase> val = nullptr)
class ClockFactory
{
static std::shared_ptr<ClockBase> clock;
public:
//output of this function should not be stored as pointer might change
static ClockBase* get(std::shared_ptr<ClockBase> val = nullptr)
{
static std::shared_ptr<ClockBase> clock;
if (val != nullptr)
clock = val;
if (val != nullptr)
clock = val;
if (clock == nullptr)
clock = std::make_shared<ScalableClock>();
if (clock == nullptr)
clock = std::make_shared<ScalableClock>();
return clock.get();
}
return clock.get();
}
//don't allow multiple instances of this class
ClockFactory(ClockFactory const&) = delete;
void operator=(ClockFactory const&) = delete;
//don't allow multiple instances of this class
ClockFactory(ClockFactory const&) = delete;
void operator=(ClockFactory const&) = delete;
private:
//disallow instance creation
ClockFactory(){}
};
}} //namespace
private:
//disallow instance creation
ClockFactory() {}
};
}
} //namespace
#endif

Просмотреть файл

@ -21,55 +21,59 @@
#define RpcLibPort 41451
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
//numericals
typedef float real_T;
//this is not required for most compilers
typedef unsigned int uint;
//numericals
typedef float real_T;
//this is not required for most compilers
typedef unsigned int uint;
//well known types
typedef msr::airlib::VectorMathf VectorMath;
typedef VectorMath::Vector3f Vector3r;
typedef VectorMath::Vector2f Vector2r;
typedef VectorMath::Vector1f Vector1r;
typedef VectorMath::Array3f Array3r;
typedef VectorMath::Pose Pose;
typedef VectorMath::Quaternionf Quaternionr;
typedef VectorMath::Matrix3x3f Matrix3x3r;
typedef VectorMath::AngleAxisf AngleAxisr;
typedef common_utils::RandomGeneratorF RandomGeneratorR;
typedef common_utils::RandomGeneratorGaussianF RandomGeneratorGausianR;
typedef std::string string;
typedef common_utils::Utils Utils;
typedef VectorMath::RandomVectorGaussianT RandomVectorGaussianR;
typedef VectorMath::RandomVectorT RandomVectorR;
typedef uint64_t TTimePoint;
typedef double TTimeDelta;
//well known types
typedef msr::airlib::VectorMathf VectorMath;
typedef VectorMath::Vector3f Vector3r;
typedef VectorMath::Vector2f Vector2r;
typedef VectorMath::Vector1f Vector1r;
typedef VectorMath::Array3f Array3r;
typedef VectorMath::Pose Pose;
typedef VectorMath::Quaternionf Quaternionr;
typedef VectorMath::Matrix3x3f Matrix3x3r;
typedef VectorMath::AngleAxisf AngleAxisr;
typedef common_utils::RandomGeneratorF RandomGeneratorR;
typedef common_utils::RandomGeneratorGaussianF RandomGeneratorGausianR;
typedef std::string string;
typedef common_utils::Utils Utils;
typedef VectorMath::RandomVectorGaussianT RandomVectorGaussianR;
typedef VectorMath::RandomVectorT RandomVectorR;
typedef uint64_t TTimePoint;
typedef double TTimeDelta;
template <typename T>
using vector = std::vector<T>;
template <typename TKey, typename TValue>
using unordered_map = std::unordered_map<TKey, TValue>;
template <typename TKey>
using unordered_set = std::unordered_set<TKey>;
template <typename T>
using unique_ptr = std::unique_ptr<T>;
template <typename T>
using shared_ptr = std::shared_ptr<T>;
template <typename T>
using vector_size_type = typename std::vector<T>::size_type;
template <typename T>
using vector = std::vector<T>;
template <typename TKey, typename TValue>
using unordered_map = std::unordered_map<TKey, TValue>;
template <typename TKey>
using unordered_set = std::unordered_set<TKey>;
template <typename T>
using unique_ptr = std::unique_ptr<T>;
template <typename T>
using shared_ptr = std::shared_ptr<T>;
template <typename T>
using vector_size_type = typename std::vector<T>::size_type;
inline std::ostream& operator<<(std::ostream& os, Quaternionr const& q)
{
float p, r, y;
VectorMath::toEulerianAngle(q, p, r, y);
return os << "(" << r << "\t" << p << "\t" << y << ")" << q.w() << q.x() << "\t" << q.y() << "\t" << q.z() << "\t";
}
inline std::ostream& operator<<(std::ostream &os, Quaternionr const &q) {
float p, r, y;
VectorMath::toEulerianAngle(q, p, r, y);
return os << "(" << r << "\t" << p << "\t" << y << ")" << q.w() << q.x() << "\t" << q.y() << "\t" << q.z() << "\t";
inline std::ostream& operator<<(std::ostream& os, Vector3r const& vec)
{
return os << vec.x() << "\t" << vec.y() << "\t" << vec.z() << "\t";
}
}
inline std::ostream& operator<<(std::ostream &os, Vector3r const &vec) {
return os << vec.x() << "\t" << vec.y() << "\t" << vec.z() << "\t";
}
}} //namespace
} //namespace
#endif

Просмотреть файл

@ -7,329 +7,372 @@
#include "common/Common.hpp"
#include <ostream>
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
//velocity
struct Twist {
Vector3r linear, angular;
Twist()
{}
Twist(const Vector3r& linear_val, const Vector3r& angular_val)
: linear(linear_val), angular(angular_val)
//velocity
struct Twist
{
}
Vector3r linear, angular;
static const Twist zero()
Twist()
{
}
Twist(const Vector3r& linear_val, const Vector3r& angular_val)
: linear(linear_val), angular(angular_val)
{
}
static const Twist zero()
{
static const Twist zero_twist(Vector3r::Zero(), Vector3r::Zero());
return zero_twist;
}
};
//force & torque
struct Wrench
{
static const Twist zero_twist(Vector3r::Zero(), Vector3r::Zero());
return zero_twist;
}
};
Vector3r force, torque;
//force & torque
struct Wrench {
Vector3r force, torque;
Wrench()
{
}
Wrench()
{}
Wrench(const Vector3r& force_val, const Vector3r& torque_val)
: force(force_val), torque(torque_val)
{
}
Wrench(const Vector3r& force_val, const Vector3r& torque_val)
: force(force_val), torque(torque_val)
//support basic arithmatic
Wrench operator+(const Wrench& other) const
{
Wrench result;
result.force = this->force + other.force;
result.torque = this->torque + other.torque;
return result;
}
Wrench operator+=(const Wrench& other)
{
force += other.force;
torque += other.torque;
return *this;
}
Wrench operator-(const Wrench& other) const
{
Wrench result;
result.force = this->force - other.force;
result.torque = this->torque - other.torque;
return result;
}
Wrench operator-=(const Wrench& other)
{
force -= other.force;
torque -= other.torque;
return *this;
}
static const Wrench zero()
{
static const Wrench zero_wrench(Vector3r::Zero(), Vector3r::Zero());
return zero_wrench;
}
};
struct Momentums
{
}
Vector3r linear;
Vector3r angular;
//support basic arithmatic
Wrench operator+(const Wrench& other) const
Momentums()
{
}
Momentums(const Vector3r& linear_val, const Vector3r& angular_val)
: linear(linear_val), angular(angular_val)
{
}
static const Momentums zero()
{
static const Momentums zero_val(Vector3r::Zero(), Vector3r::Zero());
return zero_val;
}
};
struct Accelerations
{
Wrench result;
result.force = this->force + other.force;
result.torque = this->torque + other.torque;
return result;
}
Wrench operator+=(const Wrench& other)
Vector3r linear;
Vector3r angular;
Accelerations()
{
}
Accelerations(const Vector3r& linear_val, const Vector3r& angular_val)
: linear(linear_val), angular(angular_val)
{
}
static const Accelerations zero()
{
static const Accelerations zero_val(Vector3r::Zero(), Vector3r::Zero());
return zero_val;
}
};
struct PoseWithCovariance
{
force += other.force;
torque += other.torque;
return *this;
}
Wrench operator-(const Wrench& other) const
VectorMath::Pose pose;
vector<real_T> covariance; //36 elements, 6x6 matrix
PoseWithCovariance()
: covariance(36, 0)
{
}
};
struct PowerSupply
{
Wrench result;
result.force = this->force - other.force;
result.torque = this->torque - other.torque;
return result;
}
Wrench operator-=(const Wrench& other)
vector<real_T> voltage, current;
};
struct TwistWithCovariance
{
force -= other.force;
torque -= other.torque;
return *this;
}
Twist twist;
vector<real_T> covariance; //36 elements, 6x6 matrix
static const Wrench zero()
TwistWithCovariance()
: covariance(36, 0)
{
}
};
struct Joystick
{
static const Wrench zero_wrench(Vector3r::Zero(), Vector3r::Zero());
return zero_wrench;
}
};
vector<float> axes;
vector<int> buttons;
};
struct Momentums {
Vector3r linear;
Vector3r angular;
Momentums()
{}
Momentums(const Vector3r& linear_val, const Vector3r& angular_val)
: linear(linear_val), angular(angular_val)
struct Odometry
{
}
PoseWithCovariance pose;
TwistWithCovariance twist;
};
static const Momentums zero()
struct GeoPoint
{
static const Momentums zero_val(Vector3r::Zero(), Vector3r::Zero());
return zero_val;
}
};
double latitude = 0, longitude = 0;
float altitude = 0;
struct Accelerations {
Vector3r linear;
Vector3r angular;
GeoPoint()
{
}
Accelerations()
{}
GeoPoint(double latitude_val, double longitude_val, float altitude_val)
{
set(latitude_val, longitude_val, altitude_val);
}
Accelerations(const Vector3r& linear_val, const Vector3r& angular_val)
: linear(linear_val), angular(angular_val)
void set(double latitude_val, double longitude_val, float altitude_val)
{
latitude = latitude_val, longitude = longitude_val;
altitude = altitude_val;
}
friend std::ostream& operator<<(std::ostream& os, GeoPoint const& g)
{
return os << "[" << g.latitude << ", " << g.longitude << ", " << g.altitude << "]";
}
std::string to_string() const
{
return std::to_string(latitude) + string(", ") + std::to_string(longitude) + string(", ") + std::to_string(altitude);
}
};
struct HomeGeoPoint
{
}
GeoPoint home_geo_point;
double lat_rad, lon_rad;
double cos_lat, sin_lat;
static const Accelerations zero()
HomeGeoPoint()
{
}
HomeGeoPoint(const GeoPoint& home_geo_point_val)
{
initialize(home_geo_point_val);
}
void initialize(const GeoPoint& home_geo_point_val)
{
home_geo_point = home_geo_point_val;
lat_rad = Utils::degreesToRadians(home_geo_point.latitude);
lon_rad = Utils::degreesToRadians(home_geo_point.longitude);
cos_lat = cos(lat_rad);
sin_lat = sin(lat_rad);
}
};
struct ProjectionMatrix
{
static const Accelerations zero_val(Vector3r::Zero(), Vector3r::Zero());
return zero_val;
}
};
float matrix[4][4];
struct PoseWithCovariance {
VectorMath::Pose pose;
vector<real_T> covariance; //36 elements, 6x6 matrix
void setTo(float val)
{
for (auto i = 0; i < 4; ++i)
for (auto j = 0; j < 4; ++j)
matrix[i][j] = val;
}
};
PoseWithCovariance()
: covariance(36, 0)
{}
};
struct PowerSupply {
vector<real_T> voltage, current;
};
struct TwistWithCovariance {
Twist twist;
vector<real_T> covariance; //36 elements, 6x6 matrix
TwistWithCovariance()
: covariance(36, 0)
{}
};
struct Joystick {
vector<float> axes;
vector<int> buttons;
};
struct Odometry {
PoseWithCovariance pose;
TwistWithCovariance twist;
};
struct GeoPoint {
double latitude = 0, longitude = 0;
float altitude = 0;
GeoPoint()
{}
GeoPoint(double latitude_val, double longitude_val, float altitude_val)
struct CollisionInfo
{
set(latitude_val, longitude_val, altitude_val);
}
bool has_collided = false;
Vector3r normal = Vector3r::Zero();
Vector3r impact_point = Vector3r::Zero();
Vector3r position = Vector3r::Zero();
real_T penetration_depth = 0;
TTimePoint time_stamp = 0;
unsigned int collision_count = 0;
std::string object_name;
int object_id = -1;
void set(double latitude_val, double longitude_val, float altitude_val)
CollisionInfo()
{
}
CollisionInfo(bool has_collided_val, const Vector3r& normal_val,
const Vector3r& impact_point_val, const Vector3r& position_val,
real_T penetration_depth_val, TTimePoint time_stamp_val,
const std::string& object_name_val, int object_id_val)
: has_collided(has_collided_val), normal(normal_val), impact_point(impact_point_val), position(position_val), penetration_depth(penetration_depth_val), time_stamp(time_stamp_val), object_name(object_name_val), object_id(object_id_val)
{
}
};
struct CameraInfo
{
latitude = latitude_val, longitude = longitude_val; altitude = altitude_val;
}
Pose pose;
float fov;
ProjectionMatrix proj_mat;
friend std::ostream& operator<<(std::ostream &os, GeoPoint const &g) {
return os << "[" << g.latitude << ", " << g.longitude << ", " << g.altitude << "]";
}
CameraInfo()
{
}
std::string to_string() const
CameraInfo(const Pose& pose_val, float fov_val, const ProjectionMatrix& proj_mat_val)
: pose(pose_val), fov(fov_val), proj_mat(proj_mat_val)
{
}
};
struct CollisionResponse
{
return std::to_string(latitude) + string(", ") + std::to_string(longitude) + string(", ") + std::to_string(altitude);
}
};
unsigned int collision_count_raw = 0;
unsigned int collision_count_non_resting = 0;
TTimePoint collision_time_stamp = 0;
};
struct HomeGeoPoint {
GeoPoint home_geo_point;
double lat_rad, lon_rad;
double cos_lat, sin_lat;
HomeGeoPoint()
{}
HomeGeoPoint(const GeoPoint& home_geo_point_val)
struct GeoPose
{
initialize(home_geo_point_val);
}
void initialize(const GeoPoint& home_geo_point_val)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Quaternionr orientation;
GeoPoint position;
};
struct RCData
{
home_geo_point = home_geo_point_val;
lat_rad = Utils::degreesToRadians(home_geo_point.latitude);
lon_rad = Utils::degreesToRadians(home_geo_point.longitude);
cos_lat = cos(lat_rad);
sin_lat = sin(lat_rad);
}
};
TTimePoint timestamp = 0;
//pitch, roll, yaw should be in range -1 to 1
//switches should be integer value indicating its state, 0=on, 1=off for example.
float pitch = 0, roll = 0, throttle = 0, yaw = 0;
float left_z = 0, right_z = 0;
uint16_t switches = 0;
std::string vendor_id = "";
bool is_initialized = false; //is RC connected?
bool is_valid = false; //must be true for data to be valid
struct ProjectionMatrix {
float matrix[4][4];
unsigned int getSwitch(uint16_t index) const
{
return switches & (1 << index) ? 1 : 0;
}
void setTo(float val)
void add(const RCData& other)
{
pitch += other.pitch;
roll += other.roll;
throttle += other.throttle;
yaw += other.yaw;
}
void subtract(const RCData& other)
{
pitch -= other.pitch;
roll -= other.roll;
throttle -= other.throttle;
yaw -= other.yaw;
}
void divideBy(float k)
{
pitch /= k;
roll /= k;
throttle /= k;
yaw /= k;
}
bool isAnyMoreThan(float k)
{
using std::abs;
return abs(pitch) > k || abs(roll) > k || abs(throttle) > k || abs(yaw) > k;
}
string toString()
{
return Utils::stringf("RCData[pitch=%f, roll=%f, throttle=%f, yaw=%f]", pitch, roll, throttle, yaw);
}
};
struct LidarData
{
for (auto i = 0; i < 4; ++i)
for (auto j = 0; j < 4; ++j)
matrix[i][j] = val;
}
};
TTimePoint time_stamp = 0;
// data
// - array of floats that represent [x,y,z] coordinate for each point hit within the range
// x0, y0, z0, x1, y1, z1, ..., xn, yn, zn
// TODO: Do we need an intensity place-holder [x,y,z, intensity]?
// - in lidar local NED coordinates
// - in meters
vector<real_T> point_cloud;
Pose pose;
vector<int> segmentation;
struct CollisionInfo {
bool has_collided = false;
Vector3r normal = Vector3r::Zero();
Vector3r impact_point = Vector3r::Zero();
Vector3r position = Vector3r::Zero();
real_T penetration_depth = 0;
TTimePoint time_stamp = 0;
unsigned int collision_count = 0;
std::string object_name;
int object_id = -1;
LidarData()
{
}
};
CollisionInfo()
{}
CollisionInfo(bool has_collided_val, const Vector3r& normal_val,
const Vector3r& impact_point_val, const Vector3r& position_val,
real_T penetration_depth_val, TTimePoint time_stamp_val,
const std::string& object_name_val, int object_id_val)
: has_collided(has_collided_val), normal(normal_val),
impact_point(impact_point_val), position(position_val),
penetration_depth(penetration_depth_val), time_stamp(time_stamp_val),
object_name(object_name_val), object_id(object_id_val)
struct DistanceSensorData
{
}
};
TTimePoint time_stamp;
real_T distance; //meters
real_T min_distance; //m
real_T max_distance; //m
Pose relative_pose;
struct CameraInfo {
Pose pose;
float fov;
ProjectionMatrix proj_mat;
DistanceSensorData()
{
}
};
CameraInfo()
{}
CameraInfo(const Pose& pose_val, float fov_val, const ProjectionMatrix& proj_mat_val)
: pose(pose_val), fov(fov_val), proj_mat(proj_mat_val)
struct MeshPositionVertexBuffersResponse
{
}
};
Vector3r position;
Quaternionr orientation;
struct CollisionResponse {
unsigned int collision_count_raw = 0;
unsigned int collision_count_non_resting = 0;
TTimePoint collision_time_stamp = 0;
};
struct GeoPose {
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Quaternionr orientation;
GeoPoint position;
};
struct RCData {
TTimePoint timestamp = 0;
//pitch, roll, yaw should be in range -1 to 1
//switches should be integer value indicating its state, 0=on, 1=off for example.
float pitch = 0, roll = 0, throttle = 0, yaw = 0;
float left_z = 0, right_z = 0;
uint16_t switches = 0;
std::string vendor_id = "";
bool is_initialized = false; //is RC connected?
bool is_valid = false; //must be true for data to be valid
unsigned int getSwitch(uint16_t index) const
{
return switches & (1 << index) ? 1 : 0;
}
void add(const RCData& other)
{
pitch += other.pitch; roll += other.roll; throttle += other.throttle; yaw += other.yaw;
}
void subtract(const RCData& other)
{
pitch -= other.pitch; roll -= other.roll; throttle -= other.throttle; yaw -= other.yaw;
}
void divideBy(float k)
{
pitch /= k; roll /= k; throttle /= k; yaw /= k;
}
bool isAnyMoreThan(float k)
{
using std::abs;
return abs(pitch) > k || abs(roll) > k || abs(throttle) > k || abs(yaw) > k;
}
string toString()
{
return Utils::stringf("RCData[pitch=%f, roll=%f, throttle=%f, yaw=%f]", pitch, roll, throttle, yaw);
}
};
struct LidarData {
TTimePoint time_stamp = 0;
// data
// - array of floats that represent [x,y,z] coordinate for each point hit within the range
// x0, y0, z0, x1, y1, z1, ..., xn, yn, zn
// TODO: Do we need an intensity place-holder [x,y,z, intensity]?
// - in lidar local NED coordinates
// - in meters
vector<real_T> point_cloud;
Pose pose;
vector<int> segmentation;
LidarData()
{}
};
struct DistanceSensorData {
TTimePoint time_stamp;
real_T distance; //meters
real_T min_distance; //m
real_T max_distance; //m
Pose relative_pose;
DistanceSensorData()
{}
};
struct MeshPositionVertexBuffersResponse {
Vector3r position;
Quaternionr orientation;
std::vector<float> vertices;
std::vector<uint32_t> indices;
std::string name;
};
}} //namespace
std::vector<float> vertices;
std::vector<uint32_t> indices;
std::string name;
};
}
} //namespace
#endif

Просмотреть файл

@ -8,82 +8,86 @@
#include "UpdatableObject.hpp"
#include <list>
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
template<typename T>
class DelayLine : public UpdatableObject {
public:
DelayLine()
{}
DelayLine(TTimeDelta delay) //in seconds
template <typename T>
class DelayLine : public UpdatableObject
{
initialize(delay);
}
void initialize(TTimeDelta delay) //in seconds
{
setDelay(delay);
}
void setDelay(TTimeDelta delay)
{
delay_ = delay;
}
double getDelay() const
{
return delay_;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
values_.clear();
times_.clear();
last_time_ = 0;
last_value_ = T();
}
virtual void update() override
{
UpdatableObject::update();
if (!times_.empty() &&
ClockBase::elapsedBetween(clock()->nowNanos(), times_.front()) >= delay_) {
last_value_ = values_.front();
last_time_ = times_.front();
times_.pop_front();
values_.pop_front();
public:
DelayLine()
{
}
DelayLine(TTimeDelta delay) //in seconds
{
initialize(delay);
}
void initialize(TTimeDelta delay) //in seconds
{
setDelay(delay);
}
void setDelay(TTimeDelta delay)
{
delay_ = delay;
}
double getDelay() const
{
return delay_;
}
}
//*** End: UpdatableState implementation ***//
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
values_.clear();
times_.clear();
last_time_ = 0;
last_value_ = T();
}
T getOutput() const
{
return last_value_;
}
double getOutputTime() const
{
return last_time_;
}
virtual void update() override
{
UpdatableObject::update();
void push_back(const T& val, TTimePoint time_offset = 0)
{
values_.push_back(val);
times_.push_back(clock()->nowNanos() + time_offset);
}
if (!times_.empty() &&
ClockBase::elapsedBetween(clock()->nowNanos(), times_.front()) >= delay_) {
private:
template<typename TItem>
using list = std::list<TItem>;
last_value_ = values_.front();
last_time_ = times_.front();
list<T> values_;
list<TTimePoint> times_;
TTimeDelta delay_;
times_.pop_front();
values_.pop_front();
}
}
//*** End: UpdatableState implementation ***//
T last_value_;
TTimePoint last_time_;
};
T getOutput() const
{
return last_value_;
}
double getOutputTime() const
{
return last_time_;
}
}} //namespace
void push_back(const T& val, TTimePoint time_offset = 0)
{
values_.push_back(val);
times_.push_back(clock()->nowNanos() + time_offset);
}
private:
template <typename TItem>
using list = std::list<TItem>;
list<T> values_;
list<TTimePoint> times_;
TTimeDelta delay_;
T last_value_;
TTimePoint last_time_;
};
}
} //namespace
#endif

Просмотреть файл

@ -6,204 +6,197 @@ https://github.com/mourner/suncalc
#ifndef airsim_core_EarthCelestial_hpp
#define airsim_core_EarthCelestial_hpp
#include "common/Common.hpp"
#include "EarthUtils.hpp"
#include <chrono>
#include <ctime>
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class EarthCelestial {
public:
struct CelestialGlobalCoord
class EarthCelestial
{
double declination;
double rightAscension;
double distance = Utils::nan<double>();
double parallacticAngle = Utils::nan<double>();
public:
struct CelestialGlobalCoord
{
double declination;
double rightAscension;
double distance = Utils::nan<double>();
double parallacticAngle = Utils::nan<double>();
};
struct CelestialLocalCoord
{
double azimuth;
double altitude;
double distance = Utils::nan<double>();
double parallacticAngle = Utils::nan<double>();
};
struct CelestialPhase
{
double fraction;
double phase;
double angle;
};
public:
static CelestialLocalCoord getSunCoordinates(uint64_t date, double lat, double lng)
{
double lw = Utils::degreesToRadians(-lng);
double phi = Utils::degreesToRadians(lat);
double d = toDays(date);
CelestialGlobalCoord c = getGlobalSunCoords(d);
double H = siderealTime(d, lw) - c.rightAscension;
CelestialLocalCoord coord;
coord.azimuth = Utils::radiansToDegrees(azimuth(H, phi, c.declination)) + 180.0;
coord.altitude = Utils::radiansToDegrees(altitude(H, phi, c.declination));
return coord;
}
static CelestialLocalCoord getMoonCoordinates(uint64_t date, double lat, double lng)
{
double lw = Utils::degreesToRadians(-lng);
double phi = Utils::degreesToRadians(lat);
double d = toDays(date);
CelestialGlobalCoord c = getGlobalMoonCoords(d);
double H = siderealTime(d, lw) - c.rightAscension;
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
double pa = std::atan2(std::sin(H), std::tan(phi) * std::cos(c.declination) - std::sin(c.declination) * std::cos(H));
double h = altitude(H, phi, c.declination);
h = h + astroRefraction(h); // altitude correction for refraction
CelestialLocalCoord coord;
coord.azimuth = Utils::radiansToDegrees(azimuth(H, phi, c.declination));
coord.altitude = Utils::radiansToDegrees(h);
coord.distance = c.distance;
coord.parallacticAngle = Utils::radiansToDegrees(pa);
return coord;
};
// calculations for illumination parameters of the moon,
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
static CelestialPhase getMoonPhase(uint64_t date)
{
double d = toDays(date);
CelestialGlobalCoord s = getGlobalSunCoords(d);
CelestialGlobalCoord m = getGlobalMoonCoords(d);
double sdist = EarthUtils::DistanceFromSun / 1000; // distance from Earth to Sun in km
double phi = std::acos(std::sin(s.declination) * std::sin(m.declination) + std::cos(s.declination) * std::cos(m.declination) * std::cos(s.rightAscension - m.rightAscension));
double inc = std::atan2(sdist * std::sin(phi), m.distance - sdist * std::cos(phi));
double angle = std::atan2(std::cos(s.declination) * std::sin(s.rightAscension - m.rightAscension), std::sin(s.declination) * std::cos(m.declination) - std::cos(s.declination) * std::sin(m.declination) * std::cos(s.rightAscension - m.rightAscension));
CelestialPhase moonPhase;
moonPhase.fraction = (1 + cos(inc)) / 2;
moonPhase.phase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / M_PI;
moonPhase.angle = angle;
return moonPhase;
};
private:
static double toDays(uint64_t date)
{
static constexpr double kJulianDaysOnY2000 = 2451545;
static constexpr double kDaysToHours = 60 * 60 * 24;
static constexpr double kJulianDaysOnEpoch = 2440588;
double julian_days = date / kDaysToHours - 0.5 + kJulianDaysOnEpoch;
;
return julian_days - kJulianDaysOnY2000;
}
static double rightAscension(double l, double b)
{
return std::atan2(std::sin(l) * std::cos(EarthUtils::Obliquity) - std::tan(b) * std::sin(EarthUtils::Obliquity), std::cos(l));
}
static double declination(double l, double b)
{
return std::asin(std::sin(b) * std::cos(EarthUtils::Obliquity) + std::cos(b) * std::sin(EarthUtils::Obliquity) * std::sin(l));
}
static double azimuth(double H, double phi, double declination)
{
return std::atan2(std::sin(H), std::cos(H) * std::sin(phi) - std::tan(declination) * std::cos(phi));
}
static double altitude(double H, double phi, double declination)
{
return std::asin(std::sin(phi) * std::sin(declination) + std::cos(phi) * std::cos(declination) * std::cos(H));
}
static double siderealTime(double d, double lw)
{
return Utils::degreesToRadians((280.16 + 360.9856235 * d)) - lw;
}
static double astroRefraction(double h)
{
if (h < 0) // the following formula works for positive altitudes only.
h = 0; // if h = -0.08901179 a div/0 would occur.
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
return 0.0002967 / std::tan(h + 0.00312536 / (h + 0.08901179));
}
static double solarMeanAnomaly(double d)
{
return Utils::degreesToRadians((357.5291 + 0.98560028 * d));
}
static double eclipticLongitude(double M)
{
double C = Utils::degreesToRadians((1.9148 * std::sin(M) + 0.02 * std::sin(2 * M) + 0.0003 * std::sin(3 * M))); // equation of center
return M + C + EarthUtils::Perihelion + M_PI;
}
static CelestialGlobalCoord getGlobalSunCoords(double d)
{
double M = solarMeanAnomaly(d);
double L = eclipticLongitude(M);
CelestialGlobalCoord sunCoords;
sunCoords.declination = declination(L, 0);
sunCoords.rightAscension = rightAscension(L, 0);
return sunCoords;
}
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
static CelestialGlobalCoord getGlobalMoonCoords(double d)
{
// geocentric ecliptic coordinates of the moon
double L = Utils::degreesToRadians((218.316 + 13.176396 * d)); // ecliptic longitude
double M = Utils::degreesToRadians((134.963 + 13.064993 * d)); // mean anomaly
double F = Utils::degreesToRadians((93.272 + 13.229350 * d)); // mean distance
double l = L + Utils::degreesToRadians(6.289 * std::sin(M)); // longitude
double b = Utils::degreesToRadians(5.128 * std::sin(F)); // latitude
double dt = 385001 - 20905 * std::cos(M); // distance to the moon in km
CelestialGlobalCoord moonCoords;
moonCoords.rightAscension = rightAscension(l, b);
moonCoords.declination = declination(l, b);
moonCoords.distance = dt;
return moonCoords;
}
};
struct CelestialLocalCoord
{
double azimuth;
double altitude;
double distance = Utils::nan<double>();
double parallacticAngle = Utils::nan<double>();
};
struct CelestialPhase
{
double fraction;
double phase;
double angle;
};
public:
static CelestialLocalCoord getSunCoordinates(uint64_t date, double lat, double lng)
{
double lw = Utils::degreesToRadians(-lng);
double phi = Utils::degreesToRadians(lat);
double d = toDays(date);
CelestialGlobalCoord c = getGlobalSunCoords(d);
double H = siderealTime(d, lw) - c.rightAscension;
CelestialLocalCoord coord;
coord.azimuth = Utils::radiansToDegrees( azimuth(H, phi, c.declination) ) + 180.0;
coord.altitude = Utils::radiansToDegrees( altitude(H, phi, c.declination) );
return coord;
}
static CelestialLocalCoord getMoonCoordinates(uint64_t date, double lat, double lng)
{
double lw = Utils::degreesToRadians(-lng);
double phi = Utils::degreesToRadians(lat);
double d = toDays(date);
CelestialGlobalCoord c = getGlobalMoonCoords(d);
double H = siderealTime(d, lw) - c.rightAscension;
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
double pa = std::atan2(std::sin(H), std::tan(phi) * std::cos(c.declination) - std::sin(c.declination) * std::cos(H));
double h = altitude(H, phi, c.declination);
h = h + astroRefraction(h); // altitude correction for refraction
CelestialLocalCoord coord;
coord.azimuth = Utils::radiansToDegrees( azimuth(H, phi, c.declination) );
coord.altitude = Utils::radiansToDegrees(h);
coord.distance = c.distance;
coord.parallacticAngle = Utils::radiansToDegrees(pa);
return coord;
};
// calculations for illumination parameters of the moon,
// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and
// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
static CelestialPhase getMoonPhase(uint64_t date)
{
double d = toDays(date);
CelestialGlobalCoord s = getGlobalSunCoords(d);
CelestialGlobalCoord m = getGlobalMoonCoords(d);
double sdist = EarthUtils::DistanceFromSun / 1000; // distance from Earth to Sun in km
double phi = std::acos(std::sin(s.declination) * std::sin(m.declination) + std::cos(s.declination) * std::cos(m.declination) * std::cos(s.rightAscension - m.rightAscension));
double inc = std::atan2(sdist * std::sin(phi), m.distance - sdist * std::cos(phi));
double angle = std::atan2(std::cos(s.declination) * std::sin(s.rightAscension - m.rightAscension), std::sin(s.declination) * std::cos(m.declination) - std::cos(s.declination) * std::sin(m.declination) * std::cos(s.rightAscension - m.rightAscension));
CelestialPhase moonPhase;
moonPhase.fraction = (1 + cos(inc)) / 2;
moonPhase.phase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / M_PI;
moonPhase.angle = angle;
return moonPhase;
};
private:
static double toDays(uint64_t date)
{
static constexpr double kJulianDaysOnY2000 = 2451545;
static constexpr double kDaysToHours = 60 * 60 * 24;
static constexpr double kJulianDaysOnEpoch = 2440588;
double julian_days = date / kDaysToHours - 0.5 + kJulianDaysOnEpoch;;
return julian_days - kJulianDaysOnY2000;
}
static double rightAscension(double l, double b)
{
return std::atan2(std::sin(l) * std::cos(EarthUtils::Obliquity) - std::tan(b) * std::sin(EarthUtils::Obliquity), std::cos(l));
}
static double declination(double l, double b)
{
return std::asin(std::sin(b) * std::cos(EarthUtils::Obliquity) + std::cos(b) * std::sin(EarthUtils::Obliquity) * std::sin(l));
}
static double azimuth(double H, double phi, double declination)
{
return std::atan2(std::sin(H), std::cos(H) * std::sin(phi) - std::tan(declination) * std::cos(phi));
}
static double altitude(double H, double phi, double declination)
{
return std::asin(std::sin(phi) * std::sin(declination) + std::cos(phi) * std::cos(declination) * std::cos(H));
}
static double siderealTime(double d, double lw)
{
return Utils::degreesToRadians((280.16 + 360.9856235 * d)) - lw;
}
static double astroRefraction(double h)
{
if (h < 0) // the following formula works for positive altitudes only.
h = 0; // if h = -0.08901179 a div/0 would occur.
// formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
// 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad:
return 0.0002967 / std::tan(h + 0.00312536 / (h + 0.08901179));
}
static double solarMeanAnomaly(double d)
{
return Utils::degreesToRadians((357.5291 + 0.98560028 * d));
}
static double eclipticLongitude(double M)
{
double C = Utils::degreesToRadians((1.9148 * std::sin(M) + 0.02 * std::sin(2 * M) + 0.0003 * std::sin(3 * M))); // equation of center
return M + C + EarthUtils::Perihelion + M_PI;
}
static CelestialGlobalCoord getGlobalSunCoords(double d)
{
double M = solarMeanAnomaly(d);
double L = eclipticLongitude(M);
CelestialGlobalCoord sunCoords;
sunCoords.declination = declination(L, 0);
sunCoords.rightAscension = rightAscension(L, 0);
return sunCoords;
}
// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas
static CelestialGlobalCoord getGlobalMoonCoords(double d)
{
// geocentric ecliptic coordinates of the moon
double L = Utils::degreesToRadians((218.316 + 13.176396 * d)); // ecliptic longitude
double M = Utils::degreesToRadians((134.963 + 13.064993 * d)); // mean anomaly
double F = Utils::degreesToRadians((93.272 + 13.229350 * d)); // mean distance
double l = L + Utils::degreesToRadians(6.289 * std::sin(M)); // longitude
double b = Utils::degreesToRadians(5.128 * std::sin(F)); // latitude
double dt = 385001 - 20905 * std::cos(M); // distance to the moon in km
CelestialGlobalCoord moonCoords;
moonCoords.rightAscension = rightAscension(l, b);
moonCoords.declination = declination(l, b);
moonCoords.distance = dt;
return moonCoords;
}
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef air_Earth_hpp
#define air_Earth_hpp
@ -10,202 +9,208 @@
#include "common/CommonStructs.hpp"
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class EarthUtils {
private:
/** set this always to the sampling in degrees for the table below */
static constexpr int MAG_SAMPLING_RES = 10;
static constexpr int MAG_SAMPLING_MIN_LAT = -60;
static constexpr int MAG_SAMPLING_MAX_LAT = 60;
static constexpr int MAG_SAMPLING_MIN_LON = -180;
static constexpr int MAG_SAMPLING_MAX_LON = 180;
static constexpr int DECLINATION_TABLE[13][37] =
class EarthUtils
{
{ 46, 45, 44, 42, 41, 40, 38, 36, 33, 28, 23, 16, 10, 4, -1, -5, -9, -14, -19, -26, -33, -40, -48, -55, -61, -66, -71, -74, -75, -72, -61, -25, 22, 40, 45, 47, 46 },
{ 30, 30, 30, 30, 29, 29, 29, 29, 27, 24, 18, 11, 3, -3, -9, -12, -15, -17, -21, -26, -32, -39, -45, -51, -55, -57, -56, -53, -44, -31, -14, 0, 13, 21, 26, 29, 30 },
{ 21, 22, 22, 22, 22, 22, 22, 22, 21, 18, 13, 5, -3, -11, -17, -20, -21, -22, -23, -25, -29, -35, -40, -44, -45, -44, -40, -32, -22, -12, -3, 3, 9, 14, 18, 20, 21 },
{ 16, 17, 17, 17, 17, 17, 16, 16, 16, 13, 8, 0, -9, -16, -21, -24, -25, -25, -23, -20, -21, -24, -28, -31, -31, -29, -24, -17, -9, -3, 0, 4, 7, 10, 13, 15, 16 },
{ 12, 13, 13, 13, 13, 13, 12, 12, 11, 9, 3, -4, -12, -19, -23, -24, -24, -22, -17, -12, -9, -10, -13, -17, -18, -16, -13, -8, -3, 0, 1, 3, 6, 8, 10, 12, 12 },
{ 10, 10, 10, 10, 10, 10, 10, 9, 9, 6, 0, -6, -14, -20, -22, -22, -19, -15, -10, -6, -2, -2, -4, -7, -8, -8, -7, -4, 0, 1, 1, 2, 4, 6, 8, 10, 10 },
{ 9, 9, 9, 9, 9, 9, 8, 8, 7, 4, -1, -8, -15, -19, -20, -18, -14, -9, -5, -2, 0, 1, 0, -2, -3, -4, -3, -2, 0, 0, 0, 1, 3, 5, 7, 8, 9 },
{ 8, 8, 8, 9, 9, 9, 8, 8, 6, 2, -3, -9, -15, -18, -17, -14, -10, -6, -2, 0, 1, 2, 2, 0, -1, -1, -2, -1, 0, 0, 0, 0, 1, 3, 5, 7, 8 },
{ 8, 9, 9, 10, 10, 10, 10, 8, 5, 0, -5, -11, -15, -16, -15, -12, -8, -4, -1, 0, 2, 3, 2, 1, 0, 0, 0, 0, 0, -1, -2, -2, -1, 0, 3, 6, 8 },
{ 6, 9, 10, 11, 12, 12, 11, 9, 5, 0, -7, -12, -15, -15, -13, -10, -7, -3, 0, 1, 2, 3, 3, 3, 2, 1, 0, 0, -1, -3, -4, -5, -5, -2, 0, 3, 6 },
{ 5, 8, 11, 13, 15, 15, 14, 11, 5, -1, -9, -14, -17, -16, -14, -11, -7, -3, 0, 1, 3, 4, 5, 5, 5, 4, 3, 1, -1, -4, -7, -8, -8, -6, -2, 1, 5 },
{ 4, 8, 12, 15, 17, 18, 16, 12, 5, -3, -12, -18, -20, -19, -16, -13, -8, -4, -1, 1, 4, 6, 8, 9, 9, 9, 7, 3, -1, -6, -10, -12, -11, -9, -5, 0, 4 },
{ 3, 9, 14, 17, 20, 21, 19, 14, 4, -8, -19, -25, -26, -25, -21, -17, -12, -7, -2, 1, 5, 9, 13, 15, 16, 16, 13, 7, 0, -7, -12, -15, -14, -11, -6, -1, 3 },
};
public:
//return declination in degrees
//Ref: https://github.com/PX4/ecl/blob/master/EKF/geo.cpp
static real_T getMagDeclination(real_T latitude, real_T longitude)
{
/*
private:
/** set this always to the sampling in degrees for the table below */
static constexpr int MAG_SAMPLING_RES = 10;
static constexpr int MAG_SAMPLING_MIN_LAT = -60;
static constexpr int MAG_SAMPLING_MAX_LAT = 60;
static constexpr int MAG_SAMPLING_MIN_LON = -180;
static constexpr int MAG_SAMPLING_MAX_LON = 180;
static constexpr int DECLINATION_TABLE[13][37] =
{
{ 46, 45, 44, 42, 41, 40, 38, 36, 33, 28, 23, 16, 10, 4, -1, -5, -9, -14, -19, -26, -33, -40, -48, -55, -61, -66, -71, -74, -75, -72, -61, -25, 22, 40, 45, 47, 46 },
{ 30, 30, 30, 30, 29, 29, 29, 29, 27, 24, 18, 11, 3, -3, -9, -12, -15, -17, -21, -26, -32, -39, -45, -51, -55, -57, -56, -53, -44, -31, -14, 0, 13, 21, 26, 29, 30 },
{ 21, 22, 22, 22, 22, 22, 22, 22, 21, 18, 13, 5, -3, -11, -17, -20, -21, -22, -23, -25, -29, -35, -40, -44, -45, -44, -40, -32, -22, -12, -3, 3, 9, 14, 18, 20, 21 },
{ 16, 17, 17, 17, 17, 17, 16, 16, 16, 13, 8, 0, -9, -16, -21, -24, -25, -25, -23, -20, -21, -24, -28, -31, -31, -29, -24, -17, -9, -3, 0, 4, 7, 10, 13, 15, 16 },
{ 12, 13, 13, 13, 13, 13, 12, 12, 11, 9, 3, -4, -12, -19, -23, -24, -24, -22, -17, -12, -9, -10, -13, -17, -18, -16, -13, -8, -3, 0, 1, 3, 6, 8, 10, 12, 12 },
{ 10, 10, 10, 10, 10, 10, 10, 9, 9, 6, 0, -6, -14, -20, -22, -22, -19, -15, -10, -6, -2, -2, -4, -7, -8, -8, -7, -4, 0, 1, 1, 2, 4, 6, 8, 10, 10 },
{ 9, 9, 9, 9, 9, 9, 8, 8, 7, 4, -1, -8, -15, -19, -20, -18, -14, -9, -5, -2, 0, 1, 0, -2, -3, -4, -3, -2, 0, 0, 0, 1, 3, 5, 7, 8, 9 },
{ 8, 8, 8, 9, 9, 9, 8, 8, 6, 2, -3, -9, -15, -18, -17, -14, -10, -6, -2, 0, 1, 2, 2, 0, -1, -1, -2, -1, 0, 0, 0, 0, 1, 3, 5, 7, 8 },
{ 8, 9, 9, 10, 10, 10, 10, 8, 5, 0, -5, -11, -15, -16, -15, -12, -8, -4, -1, 0, 2, 3, 2, 1, 0, 0, 0, 0, 0, -1, -2, -2, -1, 0, 3, 6, 8 },
{ 6, 9, 10, 11, 12, 12, 11, 9, 5, 0, -7, -12, -15, -15, -13, -10, -7, -3, 0, 1, 2, 3, 3, 3, 2, 1, 0, 0, -1, -3, -4, -5, -5, -2, 0, 3, 6 },
{ 5, 8, 11, 13, 15, 15, 14, 11, 5, -1, -9, -14, -17, -16, -14, -11, -7, -3, 0, 1, 3, 4, 5, 5, 5, 4, 3, 1, -1, -4, -7, -8, -8, -6, -2, 1, 5 },
{ 4, 8, 12, 15, 17, 18, 16, 12, 5, -3, -12, -18, -20, -19, -16, -13, -8, -4, -1, 1, 4, 6, 8, 9, 9, 9, 7, 3, -1, -6, -10, -12, -11, -9, -5, 0, 4 },
{ 3, 9, 14, 17, 20, 21, 19, 14, 4, -8, -19, -25, -26, -25, -21, -17, -12, -7, -2, 1, 5, 9, 13, 15, 16, 16, 13, 7, 0, -7, -12, -15, -14, -11, -6, -1, 3 },
};
public:
//return declination in degrees
//Ref: https://github.com/PX4/ecl/blob/master/EKF/geo.cpp
static real_T getMagDeclination(real_T latitude, real_T longitude)
{
/*
* If the values exceed valid ranges, return zero as default
* as we have no way of knowing what the closest real value
* would be.
*/
if (latitude < -90.0f || latitude > 90.0f ||
longitude < -180.0f || longitude > 180.0f) {
throw std::out_of_range(Utils::stringf("invalid latitude (%f) or longitude (%f) value", latitude, longitude));
}
if (latitude < -90.0f || latitude > 90.0f ||
longitude < -180.0f || longitude > 180.0f) {
throw std::out_of_range(Utils::stringf("invalid latitude (%f) or longitude (%f) value", latitude, longitude));
}
/* round down to nearest sampling resolution */
int min_lat = static_cast<int>(latitude / MAG_SAMPLING_RES) * MAG_SAMPLING_RES;
int min_lon = static_cast<int>(longitude / MAG_SAMPLING_RES) * MAG_SAMPLING_RES;
/* round down to nearest sampling resolution */
int min_lat = static_cast<int>(latitude / MAG_SAMPLING_RES) * MAG_SAMPLING_RES;
int min_lon = static_cast<int>(longitude / MAG_SAMPLING_RES) * MAG_SAMPLING_RES;
/* for the rare case of hitting the bounds exactly
/* for the rare case of hitting the bounds exactly
* the rounding logic wouldn't fit, so enforce it.
*/
/* limit to table bounds - required for maxima even when table spans full globe range */
if (latitude <= MAG_SAMPLING_MIN_LAT) {
min_lat = MAG_SAMPLING_MIN_LAT;
/* limit to table bounds - required for maxima even when table spans full globe range */
if (latitude <= MAG_SAMPLING_MIN_LAT) {
min_lat = MAG_SAMPLING_MIN_LAT;
}
if (latitude >= MAG_SAMPLING_MAX_LAT) {
min_lat = static_cast<int>(latitude / MAG_SAMPLING_RES) * MAG_SAMPLING_RES - MAG_SAMPLING_RES;
}
if (longitude <= MAG_SAMPLING_MIN_LON) {
min_lon = MAG_SAMPLING_MIN_LON;
}
if (longitude >= MAG_SAMPLING_MAX_LON) {
min_lon = static_cast<int>(longitude / MAG_SAMPLING_RES) * MAG_SAMPLING_RES - MAG_SAMPLING_RES;
}
/* find index of nearest low sampling point */
int min_lat_index = (-(MAG_SAMPLING_MIN_LAT) + min_lat) / MAG_SAMPLING_RES;
int min_lon_index = (-(MAG_SAMPLING_MIN_LON) + min_lon) / MAG_SAMPLING_RES;
real_T declination_sw = get_mag_lookup_table_val(min_lat_index, min_lon_index);
real_T declination_se = get_mag_lookup_table_val(min_lat_index, min_lon_index + 1);
real_T declination_ne = get_mag_lookup_table_val(min_lat_index + 1, min_lon_index + 1);
real_T declination_nw = get_mag_lookup_table_val(min_lat_index + 1, min_lon_index);
/* perform bilinear interpolation on the four grid corners */
real_T declination_min = ((longitude - min_lon) / MAG_SAMPLING_RES) * (declination_se - declination_sw) + declination_sw;
real_T declination_max = ((longitude - min_lon) / MAG_SAMPLING_RES) * (declination_ne - declination_nw) + declination_nw;
return ((latitude - min_lat) / MAG_SAMPLING_RES) * (declination_max - declination_min) + declination_min;
}
if (latitude >= MAG_SAMPLING_MAX_LAT) {
min_lat = static_cast<int>(latitude / MAG_SAMPLING_RES) * MAG_SAMPLING_RES - MAG_SAMPLING_RES;
//geopot_height = Earth_radius * altitude / (Earth_radius + altitude) /// all in kilometers
//temperature is in Kelvin = 273.15 + celcius
static real_T getStandardTemperature(real_T geopot_height)
{
//standard atmospheric pressure
//Below 51km: Practical Meteorology by Roland Stull, pg 12
//Above 51km: http://www.braeunig.us/space/atmmodel.htm
if (geopot_height <= 11) //troposphere
return 288.15f - (6.5f * geopot_height);
else if (geopot_height <= 20) //Staroshere starts
return 216.65f;
else if (geopot_height <= 32)
return 196.65f + geopot_height;
else if (geopot_height <= 47)
return 228.65f + 2.8f * (geopot_height - 32);
else if (geopot_height <= 51) //Mesosphere starts
return 270.65f;
else if (geopot_height <= 71)
return 270.65f - 2.8f * (geopot_height - 51);
else if (geopot_height <= 84.85f)
return 214.65f - 2 * (geopot_height - 71);
else
return 3;
//Thermospehere has high kinetic temperature (500c to 2000c) but temperature
//as measured by thermometer would be very low because of almost vacuum
//throw std::out_of_range("geopot_height must be less than 85km. Space domain is not supported yet!");
}
if (longitude <= MAG_SAMPLING_MIN_LON) {
min_lon = MAG_SAMPLING_MIN_LON;
static real_T getGeopotential(real_T altitude_km)
{
static constexpr real_T radius_km = EARTH_RADIUS / 1000.0f;
return radius_km * altitude_km / (radius_km + altitude_km);
}
if (longitude >= MAG_SAMPLING_MAX_LON) {
min_lon = static_cast<int>(longitude / MAG_SAMPLING_RES) * MAG_SAMPLING_RES - MAG_SAMPLING_RES;
static real_T getStandardPressure(real_T altitude /* meters */) //return Pa
{
real_T geopot_height = getGeopotential(altitude / 1000.0f);
real_T t = getStandardTemperature(geopot_height);
return getStandardPressure(geopot_height, t);
}
/* find index of nearest low sampling point */
int min_lat_index = (-(MAG_SAMPLING_MIN_LAT) + min_lat) / MAG_SAMPLING_RES;
int min_lon_index = (-(MAG_SAMPLING_MIN_LON) + min_lon) / MAG_SAMPLING_RES;
static real_T getStandardPressure(real_T geopot_height, real_T std_temperature) //return Pa
{
//Below 51km: Practical Meteorology by Roland Stull, pg 12
//Above 51km: http://www.braeunig.us/space/atmmodel.htm
//Validation data: https://www.avs.org/AVS/files/c7/c7edaedb-95b2-438f-adfb-36de54f87b9e.pdf
real_T declination_sw = get_mag_lookup_table_val(min_lat_index, min_lon_index);
real_T declination_se = get_mag_lookup_table_val(min_lat_index, min_lon_index + 1);
real_T declination_ne = get_mag_lookup_table_val(min_lat_index + 1, min_lon_index + 1);
real_T declination_nw = get_mag_lookup_table_val(min_lat_index + 1, min_lon_index);
//TODO: handle -ve altitude better (shouldn't grow indefinitely!)
/* perform bilinear interpolation on the four grid corners */
real_T declination_min = ((longitude - min_lon) / MAG_SAMPLING_RES) * (declination_se - declination_sw) + declination_sw;
real_T declination_max = ((longitude - min_lon) / MAG_SAMPLING_RES) * (declination_ne - declination_nw) + declination_nw;
return ((latitude - min_lat) / MAG_SAMPLING_RES) * (declination_max - declination_min) + declination_min;
}
//geopot_height = Earth_radius * altitude / (Earth_radius + altitude) /// all in kilometers
//temperature is in Kelvin = 273.15 + celcius
static real_T getStandardTemperature(real_T geopot_height)
{
//standard atmospheric pressure
//Below 51km: Practical Meteorology by Roland Stull, pg 12
//Above 51km: http://www.braeunig.us/space/atmmodel.htm
if (geopot_height <= 11) //troposphere
return 288.15f - (6.5f * geopot_height);
else if (geopot_height <= 20) //Staroshere starts
return 216.65f;
else if (geopot_height <= 32)
return 196.65f + geopot_height;
else if (geopot_height <= 47)
return 228.65f + 2.8f * (geopot_height - 32);
else if (geopot_height <= 51) //Mesosphere starts
return 270.65f;
else if (geopot_height <= 71)
return 270.65f - 2.8f * (geopot_height - 51);
else if (geopot_height <= 84.85f)
return 214.65f - 2 * (geopot_height - 71);
else return 3;
//Thermospehere has high kinetic temperature (500c to 2000c) but temperature
//as measured by thermometer would be very low because of almost vacuum
//throw std::out_of_range("geopot_height must be less than 85km. Space domain is not supported yet!");
}
static real_T getGeopotential(real_T altitude_km)
{
static constexpr real_T radius_km = EARTH_RADIUS / 1000.0f;
return radius_km * altitude_km / (radius_km + altitude_km);
}
static real_T getStandardPressure(real_T altitude /* meters */) //return Pa
{
real_T geopot_height = getGeopotential(altitude / 1000.0f);
real_T t = getStandardTemperature(geopot_height);
return getStandardPressure(geopot_height, t);
}
static real_T getStandardPressure(real_T geopot_height, real_T std_temperature) //return Pa
{
//Below 51km: Practical Meteorology by Roland Stull, pg 12
//Above 51km: http://www.braeunig.us/space/atmmodel.htm
//Validation data: https://www.avs.org/AVS/files/c7/c7edaedb-95b2-438f-adfb-36de54f87b9e.pdf
//TODO: handle -ve altitude better (shouldn't grow indefinitely!)
if (geopot_height <= 11)
//at alt 0, return sea level pressure
return SeaLevelPressure * powf(288.15f / std_temperature, -5.255877f);
else if (geopot_height <= 20)
return 22632.06f * expf(-0.1577f * (geopot_height - 11));
else if (geopot_height <= 32)
return 5474.889f * powf(216.65f / std_temperature, 34.16319f);
else if (geopot_height <= 47)
return 868.0187f * powf(228.65f / std_temperature, 12.2011f);
else if (geopot_height <= 51)
return 110.9063f * exp(-0.1262f * (geopot_height - 47));
else if (geopot_height <= 71)
return 66.93887f * powf(270.65f / std_temperature, -12.2011f);
else if (geopot_height <= 84.85f)
return 3.956420f * powf(214.65f / std_temperature, -17.0816f);
else return 1E-3f;
//throw std::out_of_range("altitude must be less than 86km. Space domain is not supported yet!");
}
static real_T getAirDensity(real_T std_pressure, real_T std_temperature) //kg / m^3
{
//http://www.braeunig.us/space/atmmodel.htm
return std_pressure / 287.053f / std_temperature;
}
static real_T getAirDensity(real_T altitude) //kg / m^3
{
real_T geo_pot = getGeopotential(altitude / 1000.0f);
real_T std_temperature = getStandardTemperature(geo_pot);
real_T std_pressure = getStandardPressure(geo_pot, std_temperature);
return getAirDensity(std_pressure, std_temperature);
}
static real_T getSpeedofSound(real_T altitude) // m/s
{
//http://www.braeunig.us/space/atmmodel.htm
return sqrt(1.400f * 287.053f * getStandardTemperature(getGeopotential(altitude)));
}
static real_T getGravity(real_T altitude)
{
//derivation: http://www.citycollegiate.com/gravitation_XId.htm
if (altitude < 10000 && altitude > -10000) //up to 10 km, difference is too small
return EarthUtils::Gravity;
if (altitude < 100000 && altitude > -100000) //use first exproximation using binomial expansion
return EarthUtils::Gravity * (1 - 2 * altitude / EARTH_RADIUS);
else {
real_T factor = 1 + altitude / EARTH_RADIUS;
return EarthUtils::Gravity / factor / factor;
if (geopot_height <= 11)
//at alt 0, return sea level pressure
return SeaLevelPressure * powf(288.15f / std_temperature, -5.255877f);
else if (geopot_height <= 20)
return 22632.06f * expf(-0.1577f * (geopot_height - 11));
else if (geopot_height <= 32)
return 5474.889f * powf(216.65f / std_temperature, 34.16319f);
else if (geopot_height <= 47)
return 868.0187f * powf(228.65f / std_temperature, 12.2011f);
else if (geopot_height <= 51)
return 110.9063f * exp(-0.1262f * (geopot_height - 47));
else if (geopot_height <= 71)
return 66.93887f * powf(270.65f / std_temperature, -12.2011f);
else if (geopot_height <= 84.85f)
return 3.956420f * powf(214.65f / std_temperature, -17.0816f);
else
return 1E-3f;
//throw std::out_of_range("altitude must be less than 86km. Space domain is not supported yet!");
}
}
static Vector3r getMagField(const GeoPoint& geo_point) //return Tesla
{
double declination, inclination;
return getMagField(geo_point, declination, inclination);
}
static real_T getAirDensity(real_T std_pressure, real_T std_temperature) //kg / m^3
{
//http://www.braeunig.us/space/atmmodel.htm
return std_pressure / 287.053f / std_temperature;
}
static Vector3r getMagField(const GeoPoint& geo_point, double& declination, double& inclination) //return Tesla
{
/*
static real_T getAirDensity(real_T altitude) //kg / m^3
{
real_T geo_pot = getGeopotential(altitude / 1000.0f);
real_T std_temperature = getStandardTemperature(geo_pot);
real_T std_pressure = getStandardPressure(geo_pot, std_temperature);
return getAirDensity(std_pressure, std_temperature);
}
static real_T getSpeedofSound(real_T altitude) // m/s
{
//http://www.braeunig.us/space/atmmodel.htm
return sqrt(1.400f * 287.053f * getStandardTemperature(getGeopotential(altitude)));
}
static real_T getGravity(real_T altitude)
{
//derivation: http://www.citycollegiate.com/gravitation_XId.htm
if (altitude < 10000 && altitude > -10000) //up to 10 km, difference is too small
return EarthUtils::Gravity;
if (altitude < 100000 && altitude > -100000) //use first exproximation using binomial expansion
return EarthUtils::Gravity * (1 - 2 * altitude / EARTH_RADIUS);
else {
real_T factor = 1 + altitude / EARTH_RADIUS;
return EarthUtils::Gravity / factor / factor;
}
}
static Vector3r getMagField(const GeoPoint& geo_point) //return Tesla
{
double declination, inclination;
return getMagField(geo_point, declination, inclination);
}
static Vector3r getMagField(const GeoPoint& geo_point, double& declination, double& inclination) //return Tesla
{
/*
We calculate magnetic field using simple dipol model of Earth, i.e., assume
earth as perfect dipole sphere and ignoring all but first order terms.
This obviously is inaccurate because of huge amount of irregularities, magnetic pole that is
@ -235,118 +240,117 @@ public:
geo: 47.646 -122.134 -378
*/
//ref: The Earth's Magnetism: An Introduction for Geologists, Roberto Lanza, Antonio Meloni
//Sec 1.2.5, pg 27-30 https://goo.gl/bRm7wt
//some theory at http://www.tulane.edu/~sanelson/eens634/Hmwk6MagneticField.pdf
//ref: The Earth's Magnetism: An Introduction for Geologists, Roberto Lanza, Antonio Meloni
//Sec 1.2.5, pg 27-30 https://goo.gl/bRm7wt
//some theory at http://www.tulane.edu/~sanelson/eens634/Hmwk6MagneticField.pdf
double lat = Utils::degreesToRadians(geo_point.latitude); //geographic colatitude
double lon = Utils::degreesToRadians(geo_point.longitude);
double altitude = geo_point.altitude + EARTH_RADIUS;
double lat = Utils::degreesToRadians(geo_point.latitude); //geographic colatitude
double lon = Utils::degreesToRadians(geo_point.longitude);
double altitude = geo_point.altitude + EARTH_RADIUS;
//cache value
double sin_MagPoleLat = sin(MagPoleLat);
double cos_MagPoleLat = cos(MagPoleLat);
double cos_lat = cos(lat);
double sin_lat = sin(lat);
//cache value
double sin_MagPoleLat = sin(MagPoleLat);
double cos_MagPoleLat = cos(MagPoleLat);
double cos_lat = cos(lat);
double sin_lat = sin(lat);
//find magnetic colatitude
double mag_clat = acos(cos_lat * cos_MagPoleLat +
sin_lat * sin_MagPoleLat * cos(lon - MagPoleLon) );
//find magnetic colatitude
double mag_clat = acos(cos_lat * cos_MagPoleLat +
sin_lat * sin_MagPoleLat * cos(lon - MagPoleLon));
//calculation of magnetic longitude is not needed but just in case if someone wants it
//double mag_lon = asin(
// (sin(lon - MagPoleLon) * sin(lat)) /
// sin(mag_clat));
//calculation of magnetic longitude is not needed but just in case if someone wants it
//double mag_lon = asin(
// (sin(lon - MagPoleLon) * sin(lat)) /
// sin(mag_clat));
//field strength only depends on magnetic colatitude
//https://en.wikipedia.org/wiki/Dipole_model_of_the_Earth's_magnetic_field
double cos_mag_clat = cos(mag_clat);
double field_mag = MeanMagField * pow(EARTH_RADIUS / altitude, 3) *
sqrt(1 + 3 * cos_mag_clat * cos_mag_clat);
//field strength only depends on magnetic colatitude
//https://en.wikipedia.org/wiki/Dipole_model_of_the_Earth's_magnetic_field
double cos_mag_clat = cos(mag_clat);
double field_mag = MeanMagField * pow(EARTH_RADIUS / altitude, 3) *
sqrt(1 + 3 * cos_mag_clat * cos_mag_clat);
//find inclination and declination
//equation of declination in above referenced book is only partial
//full equation is (4a) at http://www.tulane.edu/~sanelson/eens634/Hmwk6MagneticField.pdf
double lat_test = sin_MagPoleLat * sin_lat;
double dec_factor = cos_MagPoleLat / sin(mag_clat);
if (cos_mag_clat > lat_test)
declination = asin(sin(lon - MagPoleLon) * dec_factor);
else
declination = asin(cos(lon - MagPoleLon) * dec_factor);
inclination = atan(2.0 / tan(mag_clat)); //do not use atan2 here
//find inclination and declination
//equation of declination in above referenced book is only partial
//full equation is (4a) at http://www.tulane.edu/~sanelson/eens634/Hmwk6MagneticField.pdf
double lat_test = sin_MagPoleLat * sin_lat;
double dec_factor = cos_MagPoleLat / sin(mag_clat);
if (cos_mag_clat > lat_test)
declination = asin(sin(lon - MagPoleLon) * dec_factor);
else
declination = asin(cos(lon - MagPoleLon) * dec_factor);
inclination = atan(2.0 / tan(mag_clat)); //do not use atan2 here
//transform magnetic field vector to geographical coordinates
//ref: http://www.geo.mtu.edu/~jdiehl/magnotes.html
double field_xy = field_mag * cos(inclination);
return Vector3r(
static_cast<real_T>(field_xy * cos(declination)),
static_cast<real_T>(field_xy * sin(declination)),
static_cast<real_T>(field_mag * sin(inclination))
);
}
//transform magnetic field vector to geographical coordinates
//ref: http://www.geo.mtu.edu/~jdiehl/magnotes.html
double field_xy = field_mag * cos(inclination);
return Vector3r(
static_cast<real_T>(field_xy * cos(declination)),
static_cast<real_T>(field_xy * sin(declination)),
static_cast<real_T>(field_mag * sin(inclination)));
}
static GeoPoint nedToGeodetic(const Vector3r& v, const HomeGeoPoint& home_geo_point)
{
double x_rad = v.x() / EARTH_RADIUS;
double y_rad = v.y() / EARTH_RADIUS;
double c = sqrt(x_rad*x_rad + y_rad*y_rad);
double sin_c = sin(c), cos_c = cos(c);
double lat_rad, lon_rad;
if (!Utils::isApproximatelyZero(c)) { //avoids large changes?
lat_rad = asin(cos_c * home_geo_point.sin_lat + (x_rad * sin_c * home_geo_point.cos_lat) / c);
lon_rad = (home_geo_point.lon_rad +
atan2(y_rad * sin_c, c * home_geo_point.cos_lat * cos_c - x_rad * home_geo_point.sin_lat * sin_c));
static GeoPoint nedToGeodetic(const Vector3r& v, const HomeGeoPoint& home_geo_point)
{
double x_rad = v.x() / EARTH_RADIUS;
double y_rad = v.y() / EARTH_RADIUS;
double c = sqrt(x_rad * x_rad + y_rad * y_rad);
double sin_c = sin(c), cos_c = cos(c);
double lat_rad, lon_rad;
if (!Utils::isApproximatelyZero(c)) { //avoids large changes?
lat_rad = asin(cos_c * home_geo_point.sin_lat + (x_rad * sin_c * home_geo_point.cos_lat) / c);
lon_rad = (home_geo_point.lon_rad +
atan2(y_rad * sin_c, c * home_geo_point.cos_lat * cos_c - x_rad * home_geo_point.sin_lat * sin_c));
return GeoPoint(Utils::radiansToDegrees(lat_rad), Utils::radiansToDegrees(lon_rad),
home_geo_point.home_geo_point.altitude - v.z());
} else
return GeoPoint(home_geo_point.home_geo_point.latitude, home_geo_point.home_geo_point.longitude, home_geo_point.home_geo_point.altitude - v.z());
}
return GeoPoint(Utils::radiansToDegrees(lat_rad), Utils::radiansToDegrees(lon_rad), home_geo_point.home_geo_point.altitude - v.z());
}
else
return GeoPoint(home_geo_point.home_geo_point.latitude, home_geo_point.home_geo_point.longitude, home_geo_point.home_geo_point.altitude - v.z());
}
//below are approximate versions and would produce errors of more than 10m for points farther than 1km
//for more accurate versions, please use the version in EarthUtils::nedToGeodetic
static Vector3r GeodeticToNedFast(const GeoPoint& geo, const GeoPoint& home)
{
double d_lat = geo.latitude - home.latitude;
double d_lon = geo.longitude - home.longitude;
real_T d_alt = static_cast<real_T>(home.altitude - geo.altitude);
real_T x = static_cast<real_T>(Utils::degreesToRadians(d_lat) * EARTH_RADIUS);
real_T y = static_cast<real_T>(Utils::degreesToRadians(d_lon) * EARTH_RADIUS * cos(Utils::degreesToRadians(geo.latitude)));
return Vector3r(x, y, d_alt);
}
static GeoPoint nedToGeodeticFast(const Vector3r& local, const GeoPoint& home)
{
GeoPoint r;
double d_lat = local.x() / EARTH_RADIUS;
double d_lon = local.y() / (EARTH_RADIUS * cos(Utils::degreesToRadians(home.latitude)));
r.latitude = home.latitude + Utils::radiansToDegrees(d_lat);
r.longitude = home.longitude + Utils::radiansToDegrees(d_lon);
r.altitude = home.altitude - local.z();
//below are approximate versions and would produce errors of more than 10m for points farther than 1km
//for more accurate versions, please use the version in EarthUtils::nedToGeodetic
static Vector3r GeodeticToNedFast(const GeoPoint& geo, const GeoPoint& home)
{
double d_lat = geo.latitude - home.latitude;
double d_lon = geo.longitude - home.longitude;
real_T d_alt = static_cast<real_T>(home.altitude - geo.altitude);
real_T x = static_cast<real_T>(Utils::degreesToRadians(d_lat) * EARTH_RADIUS);
real_T y = static_cast<real_T>(Utils::degreesToRadians(d_lon) * EARTH_RADIUS * cos(Utils::degreesToRadians(geo.latitude)));
return Vector3r(x, y, d_alt);
}
static GeoPoint nedToGeodeticFast(const Vector3r& local, const GeoPoint& home)
{
GeoPoint r;
double d_lat = local.x() / EARTH_RADIUS;
double d_lon = local.y() / (EARTH_RADIUS * cos(Utils::degreesToRadians(home.latitude)));
r.latitude = home.latitude + Utils::radiansToDegrees(d_lat);
r.longitude = home.longitude + Utils::radiansToDegrees(d_lon);
r.altitude = home.altitude - local.z();
return r;
}
return r;
}
public: //consts
//ref: https://www.ngdc.noaa.gov/geomag/GeomagneticPoles.shtml
static constexpr double MagPoleLat = Utils::degreesToRadians(80.31f);
static constexpr double MagPoleLon = Utils::degreesToRadians(-72.62f);
static constexpr double MeanMagField = 3.12E-5; //Tesla, https://en.wikipedia.org/wiki/Dipole_model_of_the_Earth's_magnetic_field
static constexpr float SeaLevelPressure = 101325.0f; //Pascal
static constexpr float SeaLevelAirDensity = 1.225f; //kg/m^3
static constexpr float Gravity = 9.80665f; //m/s^2
static constexpr float Radius = EARTH_RADIUS; //m
static constexpr float SpeedOfLight = 299792458.0f; //m
static constexpr float Obliquity = Utils::degreesToRadians(23.4397f);
static constexpr double Perihelion = Utils::degreesToRadians(102.9372); // perihelion of the Earth
static constexpr double DistanceFromSun = 149597870700.0; // meters
public: //consts
//ref: https://www.ngdc.noaa.gov/geomag/GeomagneticPoles.shtml
static constexpr double MagPoleLat = Utils::degreesToRadians(80.31f);
static constexpr double MagPoleLon = Utils::degreesToRadians(-72.62f);
static constexpr double MeanMagField = 3.12E-5; //Tesla, https://en.wikipedia.org/wiki/Dipole_model_of_the_Earth's_magnetic_field
static constexpr float SeaLevelPressure = 101325.0f; //Pascal
static constexpr float SeaLevelAirDensity = 1.225f; //kg/m^3
static constexpr float Gravity = 9.80665f; //m/s^2
static constexpr float Radius = EARTH_RADIUS; //m
static constexpr float SpeedOfLight = 299792458.0f; //m
static constexpr float Obliquity = Utils::degreesToRadians(23.4397f);
static constexpr double Perihelion = Utils::degreesToRadians(102.9372); // perihelion of the Earth
static constexpr double DistanceFromSun = 149597870700.0; // meters
private:
/* magnetic field */
static float get_mag_lookup_table_val(int lat_index, int lon_index)
{
return static_cast<float>(DECLINATION_TABLE[lat_index][lon_index]);
}
};
}} //namespace
private:
/* magnetic field */
static float get_mag_lookup_table_val(int lat_index, int lon_index)
{
return static_cast<float>(DECLINATION_TABLE[lat_index][lon_index]);
}
};
}
} //namespace
#endif

Просмотреть файл

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef airsimcore_firstorderfilter_hpp
#define airsimcore_firstorderfilter_hpp
@ -9,11 +8,15 @@
#include "UpdatableObject.hpp"
#include "Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
template <typename T>
class FirstOrderFilter : public UpdatableObject {
/*
template <typename T>
class FirstOrderFilter : public UpdatableObject
{
/*
This class can be used to apply a first order filter on a signal.
It allows different acceleration and deceleration time constants.
@ -25,65 +28,64 @@ class FirstOrderFilter : public UpdatableObject {
discretized system (ZoH):
x(k+1) = exp(samplingTime*(-1/tau))*x(k) + (1 - exp(samplingTime*(-1/tau))) * u(k)
*/
public:
FirstOrderFilter()
{
//allow default constructor with later call for initialize
}
FirstOrderFilter(float timeConstant, T initial_input, T initial_output)
{
initialize(timeConstant, initial_input, initial_output);
}
void initialize(float timeConstant, T initial_input, T initial_output)
{
timeConstant_ = timeConstant;
initial_input_ = initial_input;
initial_output_ = initial_output;
}
public:
FirstOrderFilter()
{
//allow default constructor with later call for initialize
}
FirstOrderFilter(float timeConstant, T initial_input, T initial_output)
{
initialize(timeConstant, initial_input, initial_output);
}
void initialize(float timeConstant, T initial_input, T initial_output)
{
timeConstant_ = timeConstant;
initial_input_ = initial_input;
initial_output_ = initial_output;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
input_ = initial_input_;
output_ = initial_output_;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
input_ = initial_input_;
output_ = initial_output_;
}
virtual void update() override
{
UpdatableObject::update();
virtual void update() override
{
UpdatableObject::update();
TTimeDelta dt = clock()->updateSince(last_time_);
TTimeDelta dt = clock()->updateSince(last_time_);
//lower the weight for previous value if its been long time
//TODO: minimize use of exp
double alpha = exp(-dt / timeConstant_);
// x(k+1) = Ad*x(k) + Bd*u(k)
output_ = static_cast<real_T>(output_ * alpha + input_ * (1 - alpha));
}
//*** End: UpdatableState implementation ***//
//lower the weight for previous value if its been long time
//TODO: minimize use of exp
double alpha = exp(-dt / timeConstant_);
// x(k+1) = Ad*x(k) + Bd*u(k)
output_ = static_cast<real_T>(output_ * alpha + input_ * (1 - alpha));
}
//*** End: UpdatableState implementation ***//
void setInput(T input)
{
input_ = input;
}
T getInput() const
{
return input_;
}
void setInput(T input)
{
input_ = input;
}
T getInput() const
{
return input_;
}
T getOutput() const
{
return output_;
}
T getOutput() const
{
return output_;
}
private:
float timeConstant_;
T output_, input_;
T initial_output_, initial_input_;
TTimePoint last_time_;
};
}} //namespace
private:
float timeConstant_;
T output_, input_;
T initial_output_, initial_input_;
TTimePoint last_time_;
};
}
} //namespace
#endif

Просмотреть файл

@ -8,124 +8,126 @@
#include "UpdatableObject.hpp"
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class FrequencyLimiter : public UpdatableObject {
public:
FrequencyLimiter(real_T frequency = Utils::max<float>(), real_T startup_delay = 0)
class FrequencyLimiter : public UpdatableObject
{
initialize(frequency, startup_delay);
}
void initialize(real_T frequency = Utils::max<float>(), real_T startup_delay = 0)
{
frequency_ = frequency;
startup_delay_ = startup_delay;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
first_time_ = last_time_;
if (Utils::isApproximatelyZero(frequency_))
interval_size_sec_ = 1E10; //some high number
else
interval_size_sec_ = 1.0f / frequency_;
elapsed_total_sec_ = 0;
elapsed_interval_sec_ = 0;
last_elapsed_interval_sec_ = 0;
update_count_ = 0;
interval_complete_ = false;
startup_complete_ = false;
}
virtual void failResetUpdateOrdering(std::string err) override
{
// Do nothing.
// Disable checks for reset/update sequence because
// this object may get created but not used.
}
virtual void update() override
{
UpdatableObject::update();
elapsed_total_sec_ = clock()->elapsedSince(first_time_);
elapsed_interval_sec_ = clock()->elapsedSince(last_time_);
++update_count_;
//if startup_delay_ > 0 then we consider startup_delay_ as the first interval
//that needs to be complete
if (!startup_complete_) {
if (Utils::isDefinitelyGreaterThan(startup_delay_, 0.0f)) {
//see if we have spent startup_delay_ time yet
interval_complete_ = elapsed_interval_sec_ >= startup_delay_;
}
else //no special startup delay is needed
startup_complete_ = true;
public:
FrequencyLimiter(real_T frequency = Utils::max<float>(), real_T startup_delay = 0)
{
initialize(frequency, startup_delay);
}
//if startup is complete, we will do regular intervals from now one
if (startup_complete_)
interval_complete_ = elapsed_interval_sec_ >= interval_size_sec_;
//when any interval is done, reset the state and repeat
if (interval_complete_) {
last_elapsed_interval_sec_ = elapsed_interval_sec_;
void initialize(real_T frequency = Utils::max<float>(), real_T startup_delay = 0)
{
frequency_ = frequency;
startup_delay_ = startup_delay;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
first_time_ = last_time_;
if (Utils::isApproximatelyZero(frequency_))
interval_size_sec_ = 1E10; //some high number
else
interval_size_sec_ = 1.0f / frequency_;
elapsed_total_sec_ = 0;
elapsed_interval_sec_ = 0;
startup_complete_ = true;
last_elapsed_interval_sec_ = 0;
update_count_ = 0;
interval_complete_ = false;
startup_complete_ = false;
}
}
//*** End: UpdatableState implementation ***//
virtual void failResetUpdateOrdering(std::string err) override
{
// Do nothing.
// Disable checks for reset/update sequence because
// this object may get created but not used.
}
TTimeDelta getElapsedTotalSec() const
{
return elapsed_total_sec_;
}
virtual void update() override
{
UpdatableObject::update();
TTimeDelta getElapsedIntervalSec() const
{
return elapsed_interval_sec_;
}
elapsed_total_sec_ = clock()->elapsedSince(first_time_);
elapsed_interval_sec_ = clock()->elapsedSince(last_time_);
++update_count_;
TTimeDelta getLastElapsedIntervalSec() const
{
return last_elapsed_interval_sec_;
}
//if startup_delay_ > 0 then we consider startup_delay_ as the first interval
//that needs to be complete
if (!startup_complete_) {
if (Utils::isDefinitelyGreaterThan(startup_delay_, 0.0f)) {
//see if we have spent startup_delay_ time yet
interval_complete_ = elapsed_interval_sec_ >= startup_delay_;
}
else //no special startup delay is needed
startup_complete_ = true;
}
bool isWaitComplete() const
{
return interval_complete_;
}
//if startup is complete, we will do regular intervals from now one
if (startup_complete_)
interval_complete_ = elapsed_interval_sec_ >= interval_size_sec_;
bool isStartupComplete() const
{
return startup_complete_;
}
//when any interval is done, reset the state and repeat
if (interval_complete_) {
last_elapsed_interval_sec_ = elapsed_interval_sec_;
last_time_ = clock()->nowNanos();
elapsed_interval_sec_ = 0;
startup_complete_ = true;
}
}
//*** End: UpdatableState implementation ***//
uint getUpdateCount() const
{
return update_count_;
}
TTimeDelta getElapsedTotalSec() const
{
return elapsed_total_sec_;
}
private:
real_T interval_size_sec_;
TTimeDelta elapsed_total_sec_;
TTimeDelta elapsed_interval_sec_;
TTimeDelta last_elapsed_interval_sec_;
uint update_count_;
real_T frequency_;
real_T startup_delay_;
bool interval_complete_;
bool startup_complete_;
TTimePoint last_time_, first_time_;
TTimeDelta getElapsedIntervalSec() const
{
return elapsed_interval_sec_;
}
};
TTimeDelta getLastElapsedIntervalSec() const
{
return last_elapsed_interval_sec_;
}
}} //namespace
#endif
bool isWaitComplete() const
{
return interval_complete_;
}
bool isStartupComplete() const
{
return startup_complete_;
}
uint getUpdateCount() const
{
return update_count_;
}
private:
real_T interval_size_sec_;
TTimeDelta elapsed_total_sec_;
TTimeDelta elapsed_interval_sec_;
TTimeDelta last_elapsed_interval_sec_;
uint update_count_;
real_T frequency_;
real_T startup_delay_;
bool interval_complete_;
bool startup_complete_;
TTimePoint last_time_, first_time_;
};
}
} //namespace
#endif

Просмотреть файл

@ -9,39 +9,44 @@
#include <list>
#include "common_utils/RandomGenerator.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class GaussianMarkov : public UpdatableObject {
public:
GaussianMarkov()
{}
GaussianMarkov(real_T tau, real_T sigma, real_T initial_output = 0) //in seconds
class GaussianMarkov : public UpdatableObject
{
initialize(tau, sigma, initial_output);
}
void initialize(real_T tau, real_T sigma, real_T initial_output = 0) //in seconds
{
tau_ = tau;
sigma_ = sigma;
rand_ = RandomGeneratorGausianR(0.0f, 1.0f);
if (std::isnan(initial_output))
initial_output_ = getNextRandom() * sigma_;
else
initial_output_ = initial_output;
}
public:
GaussianMarkov()
{
}
GaussianMarkov(real_T tau, real_T sigma, real_T initial_output = 0) //in seconds
{
initialize(tau, sigma, initial_output);
}
void initialize(real_T tau, real_T sigma, real_T initial_output = 0) //in seconds
{
tau_ = tau;
sigma_ = sigma;
rand_ = RandomGeneratorGausianR(0.0f, 1.0f);
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
output_ = initial_output_;
rand_.reset();
}
virtual void update() override
{
/*
if (std::isnan(initial_output))
initial_output_ = getNextRandom() * sigma_;
else
initial_output_ = initial_output;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
output_ = initial_output_;
rand_.reset();
}
virtual void update() override
{
/*
Ref:
A Comparison between Different Error Modeling of MEMS Applied to GPS/INS Integrated Systems
Quinchia, sec 3.2, https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3812568/
@ -50,34 +55,31 @@ public:
John H Wall, 2007, eq 2.5, pg 13, http://etd.auburn.edu/handle/10415/945
*/
UpdatableObject::update();
TTimeDelta dt = clock()->updateSince(last_time_);
UpdatableObject::update();
double alpha = exp(-dt / tau_);
output_ = static_cast<real_T>(alpha * output_ + (1 - alpha) * getNextRandom() * sigma_);
}
//*** End: UpdatableState implementation ***//
TTimeDelta dt = clock()->updateSince(last_time_);
double alpha = exp(-dt / tau_);
output_ = static_cast<real_T>(alpha * output_ + (1 - alpha) * getNextRandom() * sigma_);
}
//*** End: UpdatableState implementation ***//
real_T getNextRandom()
{
return rand_.next();
}
real_T getNextRandom()
{
return rand_.next();
}
real_T getOutput() const
{
return output_;
}
real_T getOutput() const
{
return output_;
}
private:
RandomGeneratorGausianR rand_;
real_T tau_, sigma_;
real_T output_, initial_output_;
TTimePoint last_time_;
};
}} //namespace
private:
RandomGeneratorGausianR rand_;
real_T tau_, sigma_;
real_T output_, initial_output_;
TTimePoint last_time_;
};
}
} //namespace
#endif

Просмотреть файл

@ -7,220 +7,221 @@
#include <cmath>
#include "VectorMath.hpp"
namespace msr { namespace airlib {
class GeodeticConverter
namespace msr
{
namespace airlib
{
public:
GeodeticConverter(double home_latitude = 0, double home_longitude = 0, float home_altitude = 0)
{
setHome(home_latitude, home_longitude, home_altitude);
}
void setHome(double home_latitude, double home_longitude, float home_altitude)
{
home_latitude_ = home_latitude;
home_longitude_ = home_longitude;
home_altitude_ = home_altitude;
// Save NED origin
home_latitude_rad_ = deg2Rad(home_latitude);
home_longitude_rad_ = deg2Rad(home_longitude);
class GeodeticConverter
{
public:
GeodeticConverter(double home_latitude = 0, double home_longitude = 0, float home_altitude = 0)
{
setHome(home_latitude, home_longitude, home_altitude);
}
// Compute ECEF of NED origin
geodetic2Ecef(home_latitude_, home_longitude_, home_altitude_, &home_ecef_x_, &home_ecef_y_, &home_ecef_z_);
void setHome(double home_latitude, double home_longitude, float home_altitude)
{
home_latitude_ = home_latitude;
home_longitude_ = home_longitude;
home_altitude_ = home_altitude;
// Compute ECEF to NED and NED to ECEF matrices
double phiP = atan2(home_ecef_z_, sqrt(pow(home_ecef_x_, 2) + pow(home_ecef_y_, 2)));
// Save NED origin
home_latitude_rad_ = deg2Rad(home_latitude);
home_longitude_rad_ = deg2Rad(home_longitude);
ecef_to_ned_matrix_ = nRe(phiP, home_longitude_rad_);
ned_to_ecef_matrix_ = nRe(home_latitude_rad_, home_longitude_rad_).transpose();
}
// Compute ECEF of NED origin
geodetic2Ecef(home_latitude_, home_longitude_, home_altitude_, &home_ecef_x_, &home_ecef_y_, &home_ecef_z_);
void getHome(double* latitude, double* longitude, float* altitude)
{
*latitude = home_latitude_;
*longitude = home_longitude_;
*altitude = home_altitude_;
}
// Compute ECEF to NED and NED to ECEF matrices
double phiP = atan2(home_ecef_z_, sqrt(pow(home_ecef_x_, 2) + pow(home_ecef_y_, 2)));
void geodetic2Ecef(const double latitude, const double longitude, const double altitude, double* x,
double* y, double* z)
{
// Convert geodetic coordinates to ECEF.
// http://code.google.com/p/pysatel/source/browse/trunk/coord.py?r=22
double lat_rad = deg2Rad(latitude);
double lon_rad = deg2Rad(longitude);
double xi = sqrt(1 - kFirstEccentricitySquared * sin(lat_rad) * sin(lat_rad));
*x = (kSemimajorAxis / xi + altitude) * cos(lat_rad) * cos(lon_rad);
*y = (kSemimajorAxis / xi + altitude) * cos(lat_rad) * sin(lon_rad);
*z = (kSemimajorAxis / xi * (1 - kFirstEccentricitySquared) + altitude) * sin(lat_rad);
}
ecef_to_ned_matrix_ = nRe(phiP, home_longitude_rad_);
ned_to_ecef_matrix_ = nRe(home_latitude_rad_, home_longitude_rad_).transpose();
}
void ecef2Geodetic(const double x, const double y, const double z, double* latitude,
double* longitude, float* altitude)
{
// Convert ECEF coordinates to geodetic coordinates.
// J. Zhu, "Conversion of Earth-centered Earth-fixed coordinates
// to geodetic coordinates," IEEE Transactions on Aerospace and
// Electronic Systems, vol. 30, pp. 957-961, 1994.
void getHome(double* latitude, double* longitude, float* altitude)
{
*latitude = home_latitude_;
*longitude = home_longitude_;
*altitude = home_altitude_;
}
double r = sqrt(x * x + y * y);
double Esq = kSemimajorAxis * kSemimajorAxis - kSemiminorAxis * kSemiminorAxis;
double F = 54 * kSemiminorAxis * kSemiminorAxis * z * z;
double G = r * r + (1 - kFirstEccentricitySquared) * z * z - kFirstEccentricitySquared * Esq;
double C = (kFirstEccentricitySquared * kFirstEccentricitySquared * F * r * r) / pow(G, 3);
double S = cbrt(1 + C + sqrt(C * C + 2 * C));
double P = F / (3 * pow((S + 1 / S + 1), 2) * G * G);
double Q = sqrt(1 + 2 * kFirstEccentricitySquared * kFirstEccentricitySquared * P);
double r_0 = -(P * kFirstEccentricitySquared * r) / (1 + Q)
+ sqrt(
0.5 * kSemimajorAxis * kSemimajorAxis * (1 + 1.0 / Q)
- P * (1 - kFirstEccentricitySquared) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r);
double U = sqrt(pow((r - kFirstEccentricitySquared * r_0), 2) + z * z);
double V = sqrt(
pow((r - kFirstEccentricitySquared * r_0), 2) + (1 - kFirstEccentricitySquared) * z * z);
double Z_0 = kSemiminorAxis * kSemiminorAxis * z / (kSemimajorAxis * V);
*altitude = static_cast<float>(U * (1 - kSemiminorAxis * kSemiminorAxis / (kSemimajorAxis * V)));
*latitude = rad2Deg(atan((z + kSecondEccentricitySquared * Z_0) / r));
*longitude = rad2Deg(atan2(y, x));
}
void geodetic2Ecef(const double latitude, const double longitude, const double altitude, double* x,
double* y, double* z)
{
// Convert geodetic coordinates to ECEF.
// http://code.google.com/p/pysatel/source/browse/trunk/coord.py?r=22
double lat_rad = deg2Rad(latitude);
double lon_rad = deg2Rad(longitude);
double xi = sqrt(1 - kFirstEccentricitySquared * sin(lat_rad) * sin(lat_rad));
*x = (kSemimajorAxis / xi + altitude) * cos(lat_rad) * cos(lon_rad);
*y = (kSemimajorAxis / xi + altitude) * cos(lat_rad) * sin(lon_rad);
*z = (kSemimajorAxis / xi * (1 - kFirstEccentricitySquared) + altitude) * sin(lat_rad);
}
void ecef2Ned(const double x, const double y, const double z, double* north, double* east,
double* down)
{
// Converts ECEF coordinate position into local-tangent-plane NED.
// Coordinates relative to given ECEF coordinate frame.
void ecef2Geodetic(const double x, const double y, const double z, double* latitude,
double* longitude, float* altitude)
{
// Convert ECEF coordinates to geodetic coordinates.
// J. Zhu, "Conversion of Earth-centered Earth-fixed coordinates
// to geodetic coordinates," IEEE Transactions on Aerospace and
// Electronic Systems, vol. 30, pp. 957-961, 1994.
Vector3d vect, ret;
vect(0) = x - home_ecef_x_;
vect(1) = y - home_ecef_y_;
vect(2) = z - home_ecef_z_;
ret = ecef_to_ned_matrix_ * vect;
*north = ret(0);
*east = ret(1);
*down = -ret(2);
}
double r = sqrt(x * x + y * y);
double Esq = kSemimajorAxis * kSemimajorAxis - kSemiminorAxis * kSemiminorAxis;
double F = 54 * kSemiminorAxis * kSemiminorAxis * z * z;
double G = r * r + (1 - kFirstEccentricitySquared) * z * z - kFirstEccentricitySquared * Esq;
double C = (kFirstEccentricitySquared * kFirstEccentricitySquared * F * r * r) / pow(G, 3);
double S = cbrt(1 + C + sqrt(C * C + 2 * C));
double P = F / (3 * pow((S + 1 / S + 1), 2) * G * G);
double Q = sqrt(1 + 2 * kFirstEccentricitySquared * kFirstEccentricitySquared * P);
double r_0 = -(P * kFirstEccentricitySquared * r) / (1 + Q) + sqrt(
0.5 * kSemimajorAxis * kSemimajorAxis * (1 + 1.0 / Q) - P * (1 - kFirstEccentricitySquared) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r);
double U = sqrt(pow((r - kFirstEccentricitySquared * r_0), 2) + z * z);
double V = sqrt(
pow((r - kFirstEccentricitySquared * r_0), 2) + (1 - kFirstEccentricitySquared) * z * z);
double Z_0 = kSemiminorAxis * kSemiminorAxis * z / (kSemimajorAxis * V);
*altitude = static_cast<float>(U * (1 - kSemiminorAxis * kSemiminorAxis / (kSemimajorAxis * V)));
*latitude = rad2Deg(atan((z + kSecondEccentricitySquared * Z_0) / r));
*longitude = rad2Deg(atan2(y, x));
}
void ned2Ecef(const double north, const double east, const float down, double* x, double* y,
double* z)
{
// NED (north/east/down) to ECEF coordinates
Vector3d ned, ret;
ned(0) = north;
ned(1) = east;
ned(2) = -down;
ret = ned_to_ecef_matrix_ * ned;
*x = ret(0) + home_ecef_x_;
*y = ret(1) + home_ecef_y_;
*z = ret(2) + home_ecef_z_;
}
void ecef2Ned(const double x, const double y, const double z, double* north, double* east,
double* down)
{
// Converts ECEF coordinate position into local-tangent-plane NED.
// Coordinates relative to given ECEF coordinate frame.
void geodetic2Ned(const double latitude, const double longitude, const float altitude,
double* north, double* east, double* down)
{
// Geodetic position to local NED frame
double x, y, z;
geodetic2Ecef(latitude, longitude, altitude, &x, &y, &z);
ecef2Ned(x, y, z, north, east, down);
}
Vector3d vect, ret;
vect(0) = x - home_ecef_x_;
vect(1) = y - home_ecef_y_;
vect(2) = z - home_ecef_z_;
ret = ecef_to_ned_matrix_ * vect;
*north = ret(0);
*east = ret(1);
*down = -ret(2);
}
void ned2Geodetic(const double north, const double east, const float down, double* latitude,
double* longitude, float* altitude)
{
// Local NED position to geodetic coordinates
double x, y, z;
ned2Ecef(north, east, down, &x, &y, &z);
ecef2Geodetic(x, y, z, latitude, longitude, altitude);
void ned2Ecef(const double north, const double east, const float down, double* x, double* y,
double* z)
{
// NED (north/east/down) to ECEF coordinates
Vector3d ned, ret;
ned(0) = north;
ned(1) = east;
ned(2) = -down;
ret = ned_to_ecef_matrix_ * ned;
*x = ret(0) + home_ecef_x_;
*y = ret(1) + home_ecef_y_;
*z = ret(2) + home_ecef_z_;
}
//TODO: above returns wrong altitude if down was positive. This is because sqrt return value would be -ve
//but normal sqrt only return +ve. For now we just override it.
*altitude = home_altitude_ - down;
}
void geodetic2Ned(const double latitude, const double longitude, const float altitude,
double* north, double* east, double* down)
{
// Geodetic position to local NED frame
double x, y, z;
geodetic2Ecef(latitude, longitude, altitude, &x, &y, &z);
ecef2Ned(x, y, z, north, east, down);
}
void geodetic2Enu(const double latitude, const double longitude, const double altitude,
double* east, double* north, double* up)
{
// Geodetic position to local ENU frame
double x, y, z;
geodetic2Ecef(latitude, longitude, altitude, &x, &y, &z);
void ned2Geodetic(const double north, const double east, const float down, double* latitude,
double* longitude, float* altitude)
{
// Local NED position to geodetic coordinates
double x, y, z;
ned2Ecef(north, east, down, &x, &y, &z);
ecef2Geodetic(x, y, z, latitude, longitude, altitude);
double aux_north, aux_east, aux_down;
ecef2Ned(x, y, z, &aux_north, &aux_east, &aux_down);
//TODO: above returns wrong altitude if down was positive. This is because sqrt return value would be -ve
//but normal sqrt only return +ve. For now we just override it.
*altitude = home_altitude_ - down;
}
*east = aux_east;
*north = aux_north;
*up = -aux_down;
}
void geodetic2Enu(const double latitude, const double longitude, const double altitude,
double* east, double* north, double* up)
{
// Geodetic position to local ENU frame
double x, y, z;
geodetic2Ecef(latitude, longitude, altitude, &x, &y, &z);
void enu2Geodetic(const double east, const double north, const float up, double* latitude,
double* longitude, float* altitude)
{
// Local ENU position to geodetic coordinates
double aux_north, aux_east, aux_down;
ecef2Ned(x, y, z, &aux_north, &aux_east, &aux_down);
const double aux_north = north;
const double aux_east = east;
const float aux_down = -up;
double x, y, z;
ned2Ecef(aux_north, aux_east, aux_down, &x, &y, &z);
ecef2Geodetic(x, y, z, latitude, longitude, altitude);
}
*east = aux_east;
*north = aux_north;
*up = -aux_down;
}
private:
typedef msr::airlib::VectorMathf VectorMath;
typedef VectorMath::Vector3d Vector3d;
typedef VectorMath::Matrix3x3d Matrix3x3d;
void enu2Geodetic(const double east, const double north, const float up, double* latitude,
double* longitude, float* altitude)
{
// Local ENU position to geodetic coordinates
// Geodetic system parameters
static constexpr double kSemimajorAxis = 6378137;
static constexpr double kSemiminorAxis = 6356752.3142;
static constexpr double kFirstEccentricitySquared = 6.69437999014 * 0.001;
static constexpr double kSecondEccentricitySquared = 6.73949674228 * 0.001;
static constexpr double kFlattening = 1 / 298.257223563;
const double aux_north = north;
const double aux_east = east;
const float aux_down = -up;
double x, y, z;
ned2Ecef(aux_north, aux_east, aux_down, &x, &y, &z);
ecef2Geodetic(x, y, z, latitude, longitude, altitude);
}
inline Matrix3x3d nRe(const double lat_radians, const double lon_radians)
{
const double sLat = sin(lat_radians);
const double sLon = sin(lon_radians);
const double cLat = cos(lat_radians);
const double cLon = cos(lon_radians);
private:
typedef msr::airlib::VectorMathf VectorMath;
typedef VectorMath::Vector3d Vector3d;
typedef VectorMath::Matrix3x3d Matrix3x3d;
Matrix3x3d ret;
ret(0, 0) = -sLat * cLon;
ret(0, 1) = -sLat * sLon;
ret(0, 2) = cLat;
ret(1, 0) = -sLon;
ret(1, 1) = cLon;
ret(1, 2) = 0.0;
ret(2, 0) = cLat * cLon;
ret(2, 1) = cLat * sLon;
ret(2, 2) = sLat;
// Geodetic system parameters
static constexpr double kSemimajorAxis = 6378137;
static constexpr double kSemiminorAxis = 6356752.3142;
static constexpr double kFirstEccentricitySquared = 6.69437999014 * 0.001;
static constexpr double kSecondEccentricitySquared = 6.73949674228 * 0.001;
static constexpr double kFlattening = 1 / 298.257223563;
return ret;
}
inline Matrix3x3d nRe(const double lat_radians, const double lon_radians)
{
const double sLat = sin(lat_radians);
const double sLon = sin(lon_radians);
const double cLat = cos(lat_radians);
const double cLon = cos(lon_radians);
inline double rad2Deg(const double radians)
{
return (radians / M_PI) * 180.0;
}
Matrix3x3d ret;
ret(0, 0) = -sLat * cLon;
ret(0, 1) = -sLat * sLon;
ret(0, 2) = cLat;
ret(1, 0) = -sLon;
ret(1, 1) = cLon;
ret(1, 2) = 0.0;
ret(2, 0) = cLat * cLon;
ret(2, 1) = cLat * sLon;
ret(2, 2) = sLat;
inline double deg2Rad(const double degrees)
{
return (degrees / 180.0) * M_PI;
}
return ret;
}
double home_latitude_rad_, home_latitude_;
double home_longitude_rad_, home_longitude_;
float home_altitude_;
inline double rad2Deg(const double radians)
{
return (radians / M_PI) * 180.0;
}
double home_ecef_x_;
double home_ecef_y_;
double home_ecef_z_;
inline double deg2Rad(const double degrees)
{
return (degrees / 180.0) * M_PI;
}
Matrix3x3d ecef_to_ned_matrix_;
Matrix3x3d ned_to_ecef_matrix_;
double home_latitude_rad_, home_latitude_;
double home_longitude_rad_, home_longitude_;
float home_altitude_;
}; // class GeodeticConverter
double home_ecef_x_;
double home_ecef_y_;
double home_ecef_z_;
}}
Matrix3x3d ecef_to_ned_matrix_;
Matrix3x3d ned_to_ecef_matrix_;
}; // class GeodeticConverter
}
}
#endif // GEODETIC_CONVERTER_H_

Просмотреть файл

@ -7,61 +7,67 @@
#include "common/Common.hpp"
#include "common/common_utils/EnumFlags.hpp"
namespace msr { namespace airlib {
// This is an abstraction for cameras associated with a vehicle. Each camera has a unique id.
class ImageCaptureBase
namespace msr
{
namespace airlib
{
public: //types
enum class ImageType : int { //this indexes to array, -1 is special to indicate main camera
Scene = 0,
DepthPlanar,
DepthPerspective,
DepthVis,
DisparityNormalized,
Segmentation,
SurfaceNormals,
Infrared,
Count //must be last
};
struct ImageRequest {
std::string camera_name;
ImageCaptureBase::ImageType image_type = ImageCaptureBase::ImageType::Scene;
bool pixels_as_float = false;
bool compress = true;
// This is an abstraction for cameras associated with a vehicle. Each camera has a unique id.
class ImageCaptureBase
{
public: //types
enum class ImageType : int
{ //this indexes to array, -1 is special to indicate main camera
Scene = 0,
DepthPlanar,
DepthPerspective,
DepthVis,
DisparityNormalized,
Segmentation,
SurfaceNormals,
Infrared,
Count //must be last
};
ImageRequest()
{}
ImageRequest(const std::string& camera_name_val, ImageCaptureBase::ImageType image_type_val, bool pixels_as_float_val = false, bool compress_val = true)
struct ImageRequest
{
camera_name = camera_name_val;
image_type = image_type_val;
pixels_as_float = pixels_as_float_val;
compress = compress_val;
}
std::string camera_name;
ImageCaptureBase::ImageType image_type = ImageCaptureBase::ImageType::Scene;
bool pixels_as_float = false;
bool compress = true;
ImageRequest()
{
}
ImageRequest(const std::string& camera_name_val, ImageCaptureBase::ImageType image_type_val, bool pixels_as_float_val = false, bool compress_val = true)
{
camera_name = camera_name_val;
image_type = image_type_val;
pixels_as_float = pixels_as_float_val;
compress = compress_val;
}
};
struct ImageResponse
{
vector<uint8_t> image_data_uint8;
vector<float> image_data_float;
std::string camera_name;
Vector3r camera_position = Vector3r::Zero();
Quaternionr camera_orientation = Quaternionr::Identity();
TTimePoint time_stamp = 0;
std::string message;
bool pixels_as_float = false;
bool compress = true;
int width = 0, height = 0;
ImageType image_type;
};
public: //methods
virtual void getImages(const std::vector<ImageRequest>& requests, std::vector<ImageResponse>& responses) const = 0;
};
struct ImageResponse {
vector<uint8_t> image_data_uint8;
vector<float> image_data_float;
std::string camera_name;
Vector3r camera_position = Vector3r::Zero();
Quaternionr camera_orientation = Quaternionr::Identity();
TTimePoint time_stamp = 0;
std::string message;
bool pixels_as_float = false;
bool compress = true;
int width = 0, height = 0;
ImageType image_type;
};
public: //methods
virtual void getImages(const std::vector<ImageRequest>& requests, std::vector<ImageResponse>& responses) const = 0;
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -8,68 +8,71 @@
#include <fstream>
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class LogFileWriter {
public:
LogFileWriter()
{}
LogFileWriter(const string& file_name, bool enabled = true)
class LogFileWriter
{
open(file_name, enabled);
}
~LogFileWriter()
{
close();
}
void open(const string& file_name, bool enabled = true)
{
close();
file_name_ = file_name;
enabled_ = enabled;
if (enabled_)
log_file_ = std::ofstream(file_name);
}
void close()
{
if (log_file_.is_open())
log_file_.close();
}
template<typename T>
void write(const T& val)
{
if (enabled_)
log_file_ << val << "\t";
}
void write(const Vector3r& vec)
{
if (enabled_)
log_file_ << vec.x() << "\t" << vec.y() << "\t" << vec.z() << "\t";
}
void write(const Quaternionr& q)
{
if (enabled_) {
real_T p, r, y;
VectorMath::toEulerianAngle(q, p, r, y);
log_file_ << Utils::radiansToDegrees(r) << "\t" << Utils::radiansToDegrees(p) << "\t" << Utils::radiansToDegrees(y) << "\t";
public:
LogFileWriter()
{
}
}
void endl()
{
if (enabled_) {
log_file_ << std::endl;
LogFileWriter(const string& file_name, bool enabled = true)
{
open(file_name, enabled);
}
}
~LogFileWriter()
{
close();
}
void open(const string& file_name, bool enabled = true)
{
close();
file_name_ = file_name;
enabled_ = enabled;
private:
std::ofstream log_file_;
string file_name_;
bool enabled_ = false;
};
if (enabled_)
log_file_ = std::ofstream(file_name);
}
void close()
{
if (log_file_.is_open())
log_file_.close();
}
template <typename T>
void write(const T& val)
{
if (enabled_)
log_file_ << val << "\t";
}
void write(const Vector3r& vec)
{
if (enabled_)
log_file_ << vec.x() << "\t" << vec.y() << "\t" << vec.z() << "\t";
}
void write(const Quaternionr& q)
{
if (enabled_) {
real_T p, r, y;
VectorMath::toEulerianAngle(q, p, r, y);
log_file_ << Utils::radiansToDegrees(r) << "\t" << Utils::radiansToDegrees(p) << "\t" << Utils::radiansToDegrees(y) << "\t";
}
}
void endl()
{
if (enabled_) {
log_file_ << std::endl;
}
}
}} //namespace
private:
std::ofstream log_file_;
string file_name_;
bool enabled_ = false;
};
}
} //namespace
#endif

Просмотреть файл

@ -6,74 +6,77 @@
#include <chrono>
namespace msr { namespace airlib {
// This class implements a pid controller.
// First call setPoint to set the desired point and the PID control variables
// then call control(x) with new observed values and it will return the updated
// control output needed to achieve the setPoint goal. Integration is done using
// dt measured using system clock.
class PidController
namespace msr
{
namespace airlib
{
private:
float set_point_;
float kProportional_;
float kIntegral_;
float kDerivative_;
float previous_error_;
bool previous_set;
float sum_;
std::chrono::time_point<std::chrono::system_clock> prev_time_;
public:
//set desired point.
void setPoint(float target, float kProportional, float kIntegral, float kDerivative) {
set_point_ = target;
kProportional_ = kProportional;
kIntegral_ = kIntegral;
kDerivative_ = kDerivative;
prev_time_ = std::chrono::system_clock::now();
previous_error_ = 0;
sum_ = 0;
previous_set = false;
}
float control(float processVariable) {
auto t = std::chrono::system_clock::now();
auto diff = std::chrono::system_clock::now() - prev_time_;
float error = set_point_ - processVariable;
if (!previous_set)
{
previous_set = true;
previous_error_ = error;
return 0;
}
// This class implements a pid controller.
// First call setPoint to set the desired point and the PID control variables
// then call control(x) with new observed values and it will return the updated
// control output needed to achieve the setPoint goal. Integration is done using
// dt measured using system clock.
class PidController
{
private:
float set_point_;
float kProportional_;
float kIntegral_;
float kDerivative_;
float previous_error_;
bool previous_set;
float sum_;
std::chrono::time_point<std::chrono::system_clock> prev_time_;
float dt = static_cast<float>(std::chrono::duration_cast<std::chrono::microseconds>(diff).count()) * 0.000001f;
dt = fmax(dt, 0.01f);
float proportionalGain = 0;
float derivativeGain = 0;
float integralGain = 0;
public:
//set desired point.
void setPoint(float target, float kProportional, float kIntegral, float kDerivative)
{
set_point_ = target;
kProportional_ = kProportional;
kIntegral_ = kIntegral;
kDerivative_ = kDerivative;
prev_time_ = std::chrono::system_clock::now();
previous_error_ = 0;
sum_ = 0;
previous_set = false;
}
float control(float processVariable)
{
auto t = std::chrono::system_clock::now();
auto diff = std::chrono::system_clock::now() - prev_time_;
if (kProportional_ != 0) {
proportionalGain = error * kProportional_;
}
if (kDerivative_ != 0) {
float derivative = (error - previous_error_) / dt;
derivativeGain = derivative * kDerivative_;
}
if (kIntegral_ != 0) {
sum_ += error * dt;
integralGain = sum_ * kIntegral_;
}
float error = set_point_ - processVariable;
if (!previous_set) {
previous_set = true;
previous_error_ = error;
return 0;
}
previous_error_ = error;
prev_time_ = t;
float dt = static_cast<float>(std::chrono::duration_cast<std::chrono::microseconds>(diff).count()) * 0.000001f;
dt = fmax(dt, 0.01f);
float proportionalGain = 0;
float derivativeGain = 0;
float integralGain = 0;
return proportionalGain + derivativeGain + integralGain;
}
};
if (kProportional_ != 0) {
proportionalGain = error * kProportional_;
}
if (kDerivative_ != 0) {
float derivative = (error - previous_error_) / dt;
derivativeGain = derivative * kDerivative_;
}
if (kIntegral_ != 0) {
sum_ += error * dt;
integralGain = sum_ * kIntegral_;
}
previous_error_ = error;
prev_time_ = t;
}} //namespace
return proportionalGain + derivativeGain + integralGain;
}
};
}
} //namespace
#endif

Просмотреть файл

@ -7,80 +7,82 @@
#include "ClockBase.hpp"
#include "Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
//ScalableClock is a clock that can be scaled (i.e. slowed down or speeded up)
class ScalableClock : public ClockBase {
public:
//scale > 1 slows down the clock, < 1 speeds up the clock
ScalableClock(double scale = 1, TTimeDelta latency = 0)
: scale_(scale), latency_(latency)
//ScalableClock is a clock that can be scaled (i.e. slowed down or speeded up)
class ScalableClock : public ClockBase
{
offset_ = latency * (scale_ - 1);
start_ = nowNanos();
public:
//scale > 1 slows down the clock, < 1 speeds up the clock
ScalableClock(double scale = 1, TTimeDelta latency = 0)
: scale_(scale), latency_(latency)
{
offset_ = latency * (scale_ - 1);
start_ = nowNanos();
unused(latency_);
}
unused(latency_);
}
virtual ~ScalableClock() {}
virtual ~ScalableClock() {}
virtual TTimePoint nowNanos() const override
{
if (offset_ == 0 && scale_ == 1) //optimized normal route
return Utils::getTimeSinceEpochNanos();
else {
/*
virtual TTimePoint nowNanos() const override
{
if (offset_ == 0 && scale_ == 1) //optimized normal route
return Utils::getTimeSinceEpochNanos();
else {
/*
Apply scaling and latency.
Time point is nanoseconds from some reference r. If latency = 0 then r = 0 .
scaled time point is then given by (r + ((now - r) / scale)).
This becomes (r*(s-1) + now)/scale or (offset + now / scale).
*/
return static_cast<TTimePoint>((Utils::getTimeSinceEpochNanos() + offset_) / scale_);
return static_cast<TTimePoint>((Utils::getTimeSinceEpochNanos() + offset_) / scale_);
}
}
}
virtual TTimePoint getStart() const override
{
return start_;
}
virtual void sleep_for(TTimeDelta dt) override
{
//for intervals > 2ms just sleep otherwise do spilling otherwise delay won't be accurate
if (dt > 2.0 / 1000) {
TTimeDelta dt_scaled = fromWallDelta(dt);
std::this_thread::sleep_for(std::chrono::duration<double>(dt_scaled));
virtual TTimePoint getStart() const override
{
return start_;
}
else
ClockBase::sleep_for(dt);
}
protected:
//converts time interval for wall clock to current clock
//For example, if implementation is scaled clock simulating 5X spped then below
//will retun dt*5. This functions are required to translate time to operating system
//which only has concept of wall clock. For example, to make thread sleep for specific duration.
virtual void sleep_for(TTimeDelta dt) override
{
//for intervals > 2ms just sleep otherwise do spilling otherwise delay won't be accurate
if (dt > 2.0 / 1000) {
TTimeDelta dt_scaled = fromWallDelta(dt);
std::this_thread::sleep_for(std::chrono::duration<double>(dt_scaled));
}
else
ClockBase::sleep_for(dt);
}
//wall clock to sim clock
virtual TTimeDelta fromWallDelta(TTimeDelta dt) const
{
return dt * scale_;
}
//sim clock to wall clock
virtual TTimeDelta toWallDelta(TTimeDelta dt) const
{
return dt / scale_;
}
protected:
//converts time interval for wall clock to current clock
//For example, if implementation is scaled clock simulating 5X spped then below
//will retun dt*5. This functions are required to translate time to operating system
//which only has concept of wall clock. For example, to make thread sleep for specific duration.
//wall clock to sim clock
virtual TTimeDelta fromWallDelta(TTimeDelta dt) const
{
return dt * scale_;
}
//sim clock to wall clock
virtual TTimeDelta toWallDelta(TTimeDelta dt) const
{
return dt / scale_;
}
private:
double scale_;
TTimeDelta latency_;
double offset_;
TTimePoint start_;
};
}} //namespace
private:
double scale_;
TTimeDelta latency_;
double offset_;
TTimePoint start_;
};
}
} //namespace
#endif

Просмотреть файл

@ -18,230 +18,234 @@ STRICT_MODE_ON
#include <mutex>
#include "common_utils/FileSystem.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class Settings {
private:
std::string full_filepath_;
nlohmann::json doc_;
bool load_success_ = false;
private:
static std::mutex& getFileAccessMutex()
class Settings
{
static std::mutex file_access;
return file_access;
}
private:
std::string full_filepath_;
nlohmann::json doc_;
bool load_success_ = false;
public:
static Settings& singleton() {
static Settings instance;
return instance;
}
private:
static std::mutex& getFileAccessMutex()
{
static std::mutex file_access;
return file_access;
}
std::string getFullFilePath() { return full_filepath_; }
public:
static Settings& singleton()
{
static Settings instance;
return instance;
}
static std::string getUserDirectoryFullPath(std::string fileName)
{
std::string path = common_utils::FileSystem::getAppDataFolder();
return common_utils::FileSystem::combine(path, fileName);
}
std::string getFullFilePath() { return full_filepath_; }
static std::string getExecutableFullPath(std::string fileName)
{
std::string path = common_utils::FileSystem::getExecutableFolder();
return common_utils::FileSystem::combine(path, fileName);
}
static std::string getUserDirectoryFullPath(std::string fileName)
{
std::string path = common_utils::FileSystem::getAppDataFolder();
return common_utils::FileSystem::combine(path, fileName);
}
static Settings& loadJSonString(const std::string& json_str)
{
singleton().full_filepath_ = "";
singleton().load_success_ = false;
static std::string getExecutableFullPath(std::string fileName)
{
std::string path = common_utils::FileSystem::getExecutableFolder();
return common_utils::FileSystem::combine(path, fileName);
}
if (json_str.length() > 0) {
static Settings& loadJSonString(const std::string& json_str)
{
singleton().full_filepath_ = "";
singleton().load_success_ = false;
if (json_str.length() > 0) {
std::stringstream ss;
ss << json_str;
ss >> singleton().doc_;
singleton().load_success_ = true;
}
return singleton();
}
std::string saveJSonString()
{
std::lock_guard<std::mutex> guard(getFileAccessMutex());
std::stringstream ss;
ss << json_str;
ss >> singleton().doc_;
singleton().load_success_ = true;
ss << std::setw(2) << singleton().doc_ << std::endl;
return ss.str();
}
return singleton();
}
std::string saveJSonString()
{
std::lock_guard<std::mutex> guard(getFileAccessMutex());
std::stringstream ss;
ss << std::setw(2) << singleton().doc_ << std::endl;
static Settings& loadJSonFile(std::string full_filepath)
{
std::lock_guard<std::mutex> guard(getFileAccessMutex());
singleton().full_filepath_ = full_filepath;
return ss.str();
}
static Settings& loadJSonFile(std::string full_filepath)
{
std::lock_guard<std::mutex> guard(getFileAccessMutex());
singleton().full_filepath_ = full_filepath;
singleton().load_success_ = false;
singleton().load_success_ = false;
std::ifstream s;
common_utils::FileSystem::openTextFile(full_filepath, s);
if (!s.fail()) {
s >> singleton().doc_;
singleton().load_success_ = true;
}
std::ifstream s;
common_utils::FileSystem::openTextFile(full_filepath, s);
if (!s.fail()) {
s >> singleton().doc_;
singleton().load_success_ = true;
return singleton();
}
return singleton();
}
bool isLoadSuccess()
{
return load_success_;
}
bool hasFileName()
{
return !getFullFilePath().empty();
}
void saveJSonFile(std::string full_filepath)
{
std::lock_guard<std::mutex> guard(getFileAccessMutex());
singleton().full_filepath_ = full_filepath;
std::ofstream s;
common_utils::FileSystem::createTextFile(full_filepath, s);
s << std::setw(2) << doc_ << std::endl;
}
bool getChild(const std::string& name, Settings& child) const
{
if (doc_.count(name) == 1 &&
( doc_[name].type() == nlohmann::detail::value_t::object ||
doc_[name].type() == nlohmann::detail::value_t::array
)) {
child.doc_ = doc_[name].get<nlohmann::json>();
return true;
bool isLoadSuccess()
{
return load_success_;
}
return false;
}
size_t size() const {
return doc_.size();
}
bool hasFileName()
{
return !getFullFilePath().empty();
}
template<typename Container>
void getChildNames(Container& c) const
{
for (auto it = doc_.begin(); it != doc_.end(); ++it) {
c.push_back(it.key());
void saveJSonFile(std::string full_filepath)
{
std::lock_guard<std::mutex> guard(getFileAccessMutex());
singleton().full_filepath_ = full_filepath;
std::ofstream s;
common_utils::FileSystem::createTextFile(full_filepath, s);
s << std::setw(2) << doc_ << std::endl;
}
}
bool getChild(size_t index, Settings& child) const
{
if (doc_.size() > index &&
( doc_[index].type() == nlohmann::detail::value_t::object ||
doc_[index].type() == nlohmann::detail::value_t::array
)) {
bool getChild(const std::string& name, Settings& child) const
{
if (doc_.count(name) == 1 &&
(doc_[name].type() == nlohmann::detail::value_t::object ||
doc_[name].type() == nlohmann::detail::value_t::array)) {
child.doc_ = doc_[name].get<nlohmann::json>();
return true;
}
return false;
}
child.doc_ = doc_[index].get<nlohmann::json>();
return true;
size_t size() const
{
return doc_.size();
}
return false;
}
std::string getString(const std::string& name, std::string defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<std::string>();
template <typename Container>
void getChildNames(Container& c) const
{
for (auto it = doc_.begin(); it != doc_.end(); ++it) {
c.push_back(it.key());
}
}
else {
return defaultValue;
}
}
double getDouble(const std::string& name, double defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<double>();
}
else {
return defaultValue;
}
}
bool getChild(size_t index, Settings& child) const
{
if (doc_.size() > index &&
(doc_[index].type() == nlohmann::detail::value_t::object ||
doc_[index].type() == nlohmann::detail::value_t::array)) {
float getFloat(const std::string& name, float defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<float>();
child.doc_ = doc_[index].get<nlohmann::json>();
return true;
}
return false;
}
else {
return defaultValue;
}
}
bool getBool(const std::string& name, bool defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<bool>();
std::string getString(const std::string& name, std::string defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<std::string>();
}
else {
return defaultValue;
}
}
else {
return defaultValue;
}
}
bool hasKey(const std::string& key) const
{
return doc_.find(key) != doc_.end();
}
double getDouble(const std::string& name, double defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<double>();
}
else {
return defaultValue;
}
}
int getInt(const std::string& name, int defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<int>();
float getFloat(const std::string& name, float defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<float>();
}
else {
return defaultValue;
}
}
else {
return defaultValue;
}
}
bool setString(const std::string& name, std::string value)
{
if (doc_.count(name) != 1 || doc_[name].type() != nlohmann::detail::value_t::string || doc_[name] != value) {
doc_[name] = value;
return true;
bool getBool(const std::string& name, bool defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<bool>();
}
else {
return defaultValue;
}
}
return false;
}
bool setDouble(const std::string& name, double value)
{
if (doc_.count(name) != 1 || doc_[name].type() != nlohmann::detail::value_t::number_float || static_cast<double>(doc_[name]) != value) {
doc_[name] = value;
return true;
}
return false;
}
bool setBool(const std::string& name, bool value)
{
if (doc_.count(name) != 1 || doc_[name].type() != nlohmann::detail::value_t::boolean || static_cast<bool>(doc_[name]) != value) {
doc_[name] = value;
return true;
}
return false;
}
bool setInt(const std::string& name, int value)
{
if (doc_.count(name) != 1 || doc_[name].type() != nlohmann::detail::value_t::number_integer || static_cast<int>(doc_[name]) != value) {
doc_[name] = value;
return true;
}
return false;
}
void setChild(const std::string& name, Settings& value)
{
doc_[name] = value.doc_;
}
};
bool hasKey(const std::string& key) const
{
return doc_.find(key) != doc_.end();
}
}} //namespace
int getInt(const std::string& name, int defaultValue) const
{
if (doc_.count(name) == 1) {
return doc_[name].get<int>();
}
else {
return defaultValue;
}
}
bool setString(const std::string& name, std::string value)
{
if (doc_.count(name) != 1 || doc_[name].type() != nlohmann::detail::value_t::string || doc_[name] != value) {
doc_[name] = value;
return true;
}
return false;
}
bool setDouble(const std::string& name, double value)
{
if (doc_.count(name) != 1 || doc_[name].type() != nlohmann::detail::value_t::number_float || static_cast<double>(doc_[name]) != value) {
doc_[name] = value;
return true;
}
return false;
}
bool setBool(const std::string& name, bool value)
{
if (doc_.count(name) != 1 || doc_[name].type() != nlohmann::detail::value_t::boolean || static_cast<bool>(doc_[name]) != value) {
doc_[name] = value;
return true;
}
return false;
}
bool setInt(const std::string& name, int value)
{
if (doc_.count(name) != 1 || doc_[name].type() != nlohmann::detail::value_t::number_integer || static_cast<int>(doc_[name]) != value) {
doc_[name] = value;
return true;
}
return false;
}
void setChild(const std::string& name, Settings& value)
{
doc_[name] = value.doc_;
}
};
}
} //namespace
#endif

Просмотреть файл

@ -9,119 +9,121 @@
#include <iomanip>
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
/*
/*
This class is simple key-value reporting provider. It can't inherit from
UpdatableObject or we will have circular dependency. This class essentially
just provides formatted write APIs over string buffer. The UpdatableObject
version is provided by StateReporterWrapper. We expect everyone to use
StateReporterWrapper instead of StateReporter directly.
*/
class StateReporter {
public:
StateReporter(int float_precision = 3, bool is_scientific_notation = false)
class StateReporter
{
initialize(float_precision, is_scientific_notation);
}
void initialize(int float_precision = 3, bool is_scientific_notation = false)
{
float_precision_ = float_precision;
is_scientific_notation_ = is_scientific_notation;
if (float_precision_ >= 0) {
ss_ << std::setprecision(float_precision_);
if (is_scientific_notation_)
ss_ << std::scientific;
else
ss_ << std::fixed;
public:
StateReporter(int float_precision = 3, bool is_scientific_notation = false)
{
initialize(float_precision, is_scientific_notation);
}
}
void initialize(int float_precision = 3, bool is_scientific_notation = false)
{
float_precision_ = float_precision;
is_scientific_notation_ = is_scientific_notation;
void clear()
{
ss_.str(std::string());
ss_.clear();
}
if (float_precision_ >= 0) {
ss_ << std::setprecision(float_precision_);
if (is_scientific_notation_)
ss_ << std::scientific;
else
ss_ << std::fixed;
}
}
string getOutput() const
{
return ss_.str();
}
void clear()
{
ss_.str(std::string());
ss_.clear();
}
//write APIs - heading
//TODO: need better line end handling
void startHeading(string heading, uint heading_size, uint columns = 20)
{
unused(heading_size);
unused(columns);
ss_ << "\n";
ss_ << heading;
}
void endHeading(bool end_line, uint heading_size, uint columns = 20)
{
if (end_line)
string getOutput() const
{
return ss_.str();
}
//write APIs - heading
//TODO: need better line end handling
void startHeading(string heading, uint heading_size, uint columns = 20)
{
unused(heading_size);
unused(columns);
ss_ << "\n";
for(int lines = heading_size; lines > 0; --lines)
ss_ << std::string(columns, '_') << "\n";
}
void writeHeading(string heading, uint heading_size = 0, uint columns = 20)
{
startHeading(heading, heading_size);
endHeading(true, heading_size, columns);
}
ss_ << heading;
}
void endHeading(bool end_line, uint heading_size, uint columns = 20)
{
if (end_line)
ss_ << "\n";
for (int lines = heading_size; lines > 0; --lines)
ss_ << std::string(columns, '_') << "\n";
}
void writeHeading(string heading, uint heading_size = 0, uint columns = 20)
{
startHeading(heading, heading_size);
endHeading(true, heading_size, columns);
}
//write APIs - specialized objects
void writeValue(string name, const Vector3r& vector)
{
ss_ << name << ": " << "(" << vector.norm() << ") - " << "[" <<
vector.x() << ", " << vector.y() << ", " << vector.z() <<
"]\n";
}
void writeValue(string name, const Quaternionr& quat)
{
real_T pitch, roll, yaw;
VectorMath::toEulerianAngle(quat, pitch, roll, yaw);
//write APIs - specialized objects
void writeValue(string name, const Vector3r& vector)
{
ss_ << name << ": "
<< "(" << vector.norm() << ") - "
<< "[" << vector.x() << ", " << vector.y() << ", " << vector.z() << "]\n";
}
void writeValue(string name, const Quaternionr& quat)
{
real_T pitch, roll, yaw;
VectorMath::toEulerianAngle(quat, pitch, roll, yaw);
ss_ << name << ":\n" <<
" euler: (" << roll << ", " << pitch << ", " << yaw << ")\n" <<
" quat: [" << quat.w() << ", " << quat.x() << ", " << quat.y() << ", " << quat.z() << "]\n";
}
ss_ << name << ":\n"
<< " euler: (" << roll << ", " << pitch << ", " << yaw << ")\n"
<< " quat: [" << quat.w() << ", " << quat.x() << ", " << quat.y() << ", " << quat.z() << "]\n";
}
//write APIs - generic values
template<typename T>
void writeValue(string name, const T& r)
{
writeNameOnly(name);
writeValueOnly(r, true);
}
void writeNameOnly(string name)
{
ss_ << name << ": ";
}
template<typename T>
void writeValueOnly(const T& r, bool end_line_or_tab = false)
{
ss_ << r;
//write APIs - generic values
template <typename T>
void writeValue(string name, const T& r)
{
writeNameOnly(name);
writeValueOnly(r, true);
}
void writeNameOnly(string name)
{
ss_ << name << ": ";
}
template <typename T>
void writeValueOnly(const T& r, bool end_line_or_tab = false)
{
ss_ << r;
if (end_line_or_tab)
ss_ << "\n";
else
ss_ << "\t";
}
void endl()
{
ss_ << std::endl;
}
if (end_line_or_tab)
ss_ << "\n";
else
ss_ << "\t";
}
void endl()
{
ss_ << std::endl;
}
private:
std::stringstream ss_;
private:
std::stringstream ss_;
int float_precision_ = 2;
bool is_scientific_notation_ = false;
};
}} //namespace
int float_precision_ = 2;
bool is_scientific_notation_ = false;
};
}
} //namespace
#endif

Просмотреть файл

@ -13,119 +13,122 @@
#include "UpdatableObject.hpp"
#include "StateReporter.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class StateReporterWrapper : public UpdatableObject {
public:
static constexpr real_T DefaultReportFreq = 3.0f;
StateReporterWrapper(bool enabled = false, int float_precision = 3, bool is_scientific_notation = false)
class StateReporterWrapper : public UpdatableObject
{
initialize(enabled, float_precision, is_scientific_notation);
}
void initialize(bool enabled = false, int float_precision = 3, bool is_scientific_notation = false)
{
enabled_ = enabled;
report_.initialize(float_precision, is_scientific_notation);
report_freq_.initialize(DefaultReportFreq);
}
public:
static constexpr real_T DefaultReportFreq = 3.0f;
void clearReport()
{
report_.clear();
is_wait_complete = false;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
clearReport();
dt_stats_.clear();
report_freq_.reset();
}
virtual void failResetUpdateOrdering(std::string err) override
{
// Do nothing.
// Disable checks for reset/update sequence because
// this object may get created but not used.
}
virtual void update() override
{
UpdatableObject::update();
TTimeDelta dt = clock()->updateSince(last_time_);
if (enabled_) {
dt_stats_.insert(dt);
report_freq_.update();
is_wait_complete = is_wait_complete || report_freq_.isWaitComplete();
StateReporterWrapper(bool enabled = false, int float_precision = 3, bool is_scientific_notation = false)
{
initialize(enabled, float_precision, is_scientific_notation);
}
}
virtual void reportState(StateReporter& reporter) override
{
//TODO: perhaps we should be using supplied reporter?
unused(reporter);
//write dt stats
report_.writeNameOnly("dt");
report_.writeValueOnly(dt_stats_.mean());
report_.writeValueOnly(dt_stats_.variance());
report_.writeValueOnly(dt_stats_.size(), true);
}
//*** End: UpdatableState implementation ***//
bool canReport()
{
return enabled_ && is_wait_complete;
}
StateReporter* getReporter()
{
return &report_;
}
string getOutput()
{
return report_.getOutput();
}
void setReportFreq(real_T freq)
{
report_freq_.initialize(freq);
}
void setEnable(bool enable)
{
if (enable == enabled_)
return;
enabled_ = enable;
if (enable)
void initialize(bool enabled = false, int float_precision = 3, bool is_scientific_notation = false)
{
enabled_ = enabled;
report_.initialize(float_precision, is_scientific_notation);
report_freq_.initialize(DefaultReportFreq);
else
report_freq_.initialize(0);
}
bool getEnable()
{
return enabled_;
}
}
private:
typedef common_utils::OnlineStats OnlineStats;
void clearReport()
{
report_.clear();
is_wait_complete = false;
}
StateReporter report_;
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
clearReport();
dt_stats_.clear();
report_freq_.reset();
}
OnlineStats dt_stats_;
virtual void failResetUpdateOrdering(std::string err) override
{
// Do nothing.
// Disable checks for reset/update sequence because
// this object may get created but not used.
}
FrequencyLimiter report_freq_;
bool enabled_;
bool is_wait_complete = false;
TTimePoint last_time_;
virtual void update() override
{
UpdatableObject::update();
};
TTimeDelta dt = clock()->updateSince(last_time_);
}} //namespace
if (enabled_) {
dt_stats_.insert(dt);
report_freq_.update();
is_wait_complete = is_wait_complete || report_freq_.isWaitComplete();
}
}
virtual void reportState(StateReporter& reporter) override
{
//TODO: perhaps we should be using supplied reporter?
unused(reporter);
//write dt stats
report_.writeNameOnly("dt");
report_.writeValueOnly(dt_stats_.mean());
report_.writeValueOnly(dt_stats_.variance());
report_.writeValueOnly(dt_stats_.size(), true);
}
//*** End: UpdatableState implementation ***//
bool canReport()
{
return enabled_ && is_wait_complete;
}
StateReporter* getReporter()
{
return &report_;
}
string getOutput()
{
return report_.getOutput();
}
void setReportFreq(real_T freq)
{
report_freq_.initialize(freq);
}
void setEnable(bool enable)
{
if (enable == enabled_)
return;
enabled_ = enable;
if (enable)
report_freq_.initialize(DefaultReportFreq);
else
report_freq_.initialize(0);
}
bool getEnable()
{
return enabled_;
}
private:
typedef common_utils::OnlineStats OnlineStats;
StateReporter report_;
OnlineStats dt_stats_;
FrequencyLimiter report_freq_;
bool enabled_;
bool is_wait_complete = false;
TTimePoint last_time_;
};
}
} //namespace
#endif

Просмотреть файл

@ -8,60 +8,63 @@
#include "Common.hpp"
#include <atomic>
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class SteppableClock : public ClockBase {
public:
static constexpr real_T DefaultStepSize = 20E-3f;
//Debug clock allows to advance the clock manually in arbitrary way
//TTimePoint is nano seconds passed since some fixed point in time
//step is how much we would advance the clock by default when calling step()
//by default we advance by 20ms
SteppableClock(TTimeDelta step = DefaultStepSize, TTimePoint start = 0)
: current_(start), step_(step)
class SteppableClock : public ClockBase
{
start_ = current_ = start ? start : Utils::getTimeSinceEpochNanos();
}
public:
static constexpr real_T DefaultStepSize = 20E-3f;
virtual ~SteppableClock() {}
//Debug clock allows to advance the clock manually in arbitrary way
//TTimePoint is nano seconds passed since some fixed point in time
//step is how much we would advance the clock by default when calling step()
//by default we advance by 20ms
SteppableClock(TTimeDelta step = DefaultStepSize, TTimePoint start = 0)
: current_(start), step_(step)
{
start_ = current_ = start ? start : Utils::getTimeSinceEpochNanos();
}
TTimePoint stepBy(TTimeDelta amount)
{
current_ = addTo(current_, amount);
return current_;
}
virtual ~SteppableClock() {}
virtual TTimePoint step() override
{
ClockBase::step();
TTimePoint stepBy(TTimeDelta amount)
{
current_ = addTo(current_, amount);
return current_;
}
current_ = addTo(current_, step_);
return current_;
}
virtual TTimePoint step() override
{
ClockBase::step();
TTimeDelta getStepSize() const
{
return step_;
}
current_ = addTo(current_, step_);
return current_;
}
virtual TTimePoint nowNanos() const override
{
return current_;
}
TTimeDelta getStepSize() const
{
return step_;
}
virtual TTimePoint getStart() const override
{
return start_;
}
virtual TTimePoint nowNanos() const override
{
return current_;
}
virtual TTimePoint getStart() const override
{
return start_;
}
private:
std::atomic<TTimePoint> current_;
std::atomic<TTimePoint> start_;
private:
std::atomic<TTimePoint> current_;
std::atomic<TTimePoint> start_;
TTimeDelta step_;
};
}} //namespace
TTimeDelta step_;
};
}
} //namespace
#endif

Просмотреть файл

@ -7,72 +7,74 @@
#include "UpdatableObject.hpp"
#include "common/Common.hpp"
namespace msr { namespace airlib {
template<typename TUpdatableObjectPtr>
class UpdatableContainer : public UpdatableObject
namespace msr
{
public: //limited container interface
typedef vector<TUpdatableObjectPtr> MembersContainer;
typedef typename MembersContainer::iterator iterator;
typedef typename MembersContainer::const_iterator const_iterator;
typedef typename MembersContainer::value_type value_type;
iterator begin() { return members_.begin(); }
iterator end() { return members_.end(); }
const_iterator begin() const { return members_.begin(); }
const_iterator end() const { return members_.end(); }
uint size() const { return static_cast<uint>(members_.size()); }
const TUpdatableObjectPtr& at(uint index) const { members_.at(index); }
TUpdatableObjectPtr& at(uint index) { return members_.at(index); }
//allow to override membership modifications
virtual void clear()
namespace airlib
{
template <typename TUpdatableObjectPtr>
class UpdatableContainer : public UpdatableObject
{
for (auto m : members_) {
m->setParent(nullptr);
public: //limited container interface
typedef vector<TUpdatableObjectPtr> MembersContainer;
typedef typename MembersContainer::iterator iterator;
typedef typename MembersContainer::const_iterator const_iterator;
typedef typename MembersContainer::value_type value_type;
iterator begin() { return members_.begin(); }
iterator end() { return members_.end(); }
const_iterator begin() const { return members_.begin(); }
const_iterator end() const { return members_.end(); }
uint size() const { return static_cast<uint>(members_.size()); }
const TUpdatableObjectPtr& at(uint index) const { members_.at(index); }
TUpdatableObjectPtr& at(uint index) { return members_.at(index); }
//allow to override membership modifications
virtual void clear()
{
for (auto m : members_) {
m->setParent(nullptr);
}
members_.clear();
}
virtual void insert(TUpdatableObjectPtr member)
{
member->setParent(this);
members_.push_back(member);
}
virtual void erase_remove(TUpdatableObjectPtr member)
{
member->setParent(nullptr);
members_.erase(std::remove(members_.begin(), members_.end(), member), members_.end());
}
members_.clear();
}
virtual void insert(TUpdatableObjectPtr member)
{
member->setParent(this);
members_.push_back(member);
}
virtual void erase_remove(TUpdatableObjectPtr member)
{
member->setParent(nullptr);
members_.erase(std::remove(members_.begin(), members_.end(), member), members_.end());
}
public:
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
for (TUpdatableObjectPtr& member : members_)
member->reset();
}
public:
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
for (TUpdatableObjectPtr& member : members_)
member->reset();
}
virtual void update() override
{
UpdatableObject::update();
virtual void update() override
{
UpdatableObject::update();
for (TUpdatableObjectPtr& member : members_)
member->update();
}
for (TUpdatableObjectPtr& member : members_)
member->update();
}
virtual void reportState(StateReporter& reporter) override
{
for (TUpdatableObjectPtr& member : members_)
member->reportState(reporter);
}
virtual void reportState(StateReporter& reporter) override
{
for (TUpdatableObjectPtr& member : members_)
member->reportState(reporter);
}
//*** End: UpdatableState implementation ***//
//*** End: UpdatableState implementation ***//
virtual ~UpdatableContainer() = default;
virtual ~UpdatableContainer() = default;
private:
MembersContainer members_;
};
}} //namespace
private:
MembersContainer members_;
};
}
} //namespace
#endif

Просмотреть файл

@ -8,9 +8,12 @@
#include "StateReporter.hpp"
#include "ClockFactory.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
/*
/*
UpdatableObject provides generalized framework for things that needs to be "ticked". For example,
physics objects that needs to update its position every 10ms.
Typically this objects will take their current state, do some processing and produce new state
@ -24,89 +27,89 @@ Do not call reset() from constructor or initialization because that will produce
init->reset calls for base-derived class that would be incorrect.
*/
class UpdatableObject
{
public:
void reset()
{
if (reset_in_progress)
return;
reset_in_progress = true;
//TODO: Do we need this check anymore? Maybe reset() should be idempotent.
if (reset_called && !update_called)
failResetUpdateOrdering("Multiple reset() calls detected without call to update()");
reset_called = true;
resetImplementation();
reset_in_progress = false;
}
virtual void update()
class UpdatableObject
{
if (!reset_called)
failResetUpdateOrdering("reset() must be called first before update()");
update_called = true;
}
public:
void reset()
{
if (reset_in_progress)
return;
virtual ~UpdatableObject() = default;
reset_in_progress = true;
//TODO: Do we need this check anymore? Maybe reset() should be idempotent.
virtual void reportState(StateReporter& reporter)
{
unused(reporter);
//default implementation doesn't do anything
}
if (reset_called && !update_called)
failResetUpdateOrdering("Multiple reset() calls detected without call to update()");
virtual UpdatableObject* getPhysicsBody()
{
return nullptr;
}
reset_called = true;
virtual ClockBase* clock()
{
return ClockFactory::get();
}
virtual const ClockBase* clock() const
{
return ClockFactory::get();
}
resetImplementation();
reset_in_progress = false;
}
UpdatableObject* getParent()
{
return parent_;
}
virtual void update()
{
if (!reset_called)
failResetUpdateOrdering("reset() must be called first before update()");
update_called = true;
}
void setParent(UpdatableObject* container)
{
parent_ = container;
}
virtual ~UpdatableObject() = default;
std::string getName()
{
return name_;
}
virtual void reportState(StateReporter& reporter)
{
unused(reporter);
//default implementation doesn't do anything
}
void setName(const std::string& name)
{
this->name_ = name;
}
virtual UpdatableObject* getPhysicsBody()
{
return nullptr;
}
protected:
virtual void resetImplementation() = 0;
virtual void failResetUpdateOrdering(std::string err)
{
throw std::runtime_error(err);
}
virtual ClockBase* clock()
{
return ClockFactory::get();
}
virtual const ClockBase* clock() const
{
return ClockFactory::get();
}
private:
bool reset_called = false;
bool update_called = false;
bool reset_in_progress = false;
UpdatableObject* parent_ = nullptr;
std::string name_;
};
UpdatableObject* getParent()
{
return parent_;
}
}} //namespace
void setParent(UpdatableObject* container)
{
parent_ = container;
}
std::string getName()
{
return name_;
}
void setName(const std::string& name)
{
this->name_ = name;
}
protected:
virtual void resetImplementation() = 0;
virtual void failResetUpdateOrdering(std::string err)
{
throw std::runtime_error(err);
}
private:
bool reset_called = false;
bool update_called = false;
bool reset_in_progress = false;
UpdatableObject* parent_ = nullptr;
std::string name_;
};
}
} //namespace
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -11,66 +11,70 @@
#include "common/ClockFactory.hpp"
#include "common/CancelToken.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class Waiter {
public:
Waiter(TTimeDelta sleep_duration_seconds, TTimeDelta timeout_sec, CancelToken& cancelable_action)
: sleep_duration_(sleep_duration_seconds), timeout_sec_(timeout_sec),
cancelable_action_(cancelable_action), is_complete_(false)
class Waiter
{
proc_start_ = loop_start_ = clock()->nowNanos();
}
public:
Waiter(TTimeDelta sleep_duration_seconds, TTimeDelta timeout_sec, CancelToken& cancelable_action)
: sleep_duration_(sleep_duration_seconds), timeout_sec_(timeout_sec), cancelable_action_(cancelable_action), is_complete_(false)
{
proc_start_ = loop_start_ = clock()->nowNanos();
}
bool sleep()
{
// Sleeps for the time needed to get current running time up to the requested sleep_duration_.
// So this can be used to "throttle" any loop to check something every sleep_duration_ seconds.
bool sleep()
{
// Sleeps for the time needed to get current running time up to the requested sleep_duration_.
// So this can be used to "throttle" any loop to check something every sleep_duration_ seconds.
if (isComplete())
throw std::domain_error("Process was already complete. This instance of Waiter shouldn't be reused!");
if (isTimeout())
return false;
if (isComplete())
throw std::domain_error("Process was already complete. This instance of Waiter shouldn't be reused!");
if (isTimeout())
return false;
//measure time spent since last iteration
TTimeDelta running_time = clock()->elapsedSince(loop_start_);
double remaining = sleep_duration_ - running_time;
bool done = cancelable_action_.sleep(remaining);
loop_start_ = clock()->nowNanos();
return done;
}
//measure time spent since last iteration
TTimeDelta running_time = clock()->elapsedSince(loop_start_);
double remaining = sleep_duration_ - running_time;
bool done = cancelable_action_.sleep(remaining);
loop_start_ = clock()->nowNanos();
return done;
}
//call this mark process as complete
void complete()
{
is_complete_ = true;
}
//call this mark process as complete
void complete()
{
is_complete_ = true;
}
bool isComplete() const
{
return is_complete_;
}
bool isComplete() const
{
return is_complete_;
}
bool isTimeout() const
{
if (isComplete())
return false;
else
return clock()->elapsedSince(proc_start_) >= timeout_sec_;
}
private:
TTimeDelta sleep_duration_, timeout_sec_;
CancelToken& cancelable_action_;
bool is_complete_; //each waiter should maintain its own complete status
bool isTimeout() const
{
if (isComplete())
return false;
else
return clock()->elapsedSince(proc_start_) >= timeout_sec_;
}
TTimePoint proc_start_;
TTimePoint loop_start_;
private:
TTimeDelta sleep_duration_, timeout_sec_;
CancelToken& cancelable_action_;
bool is_complete_; //each waiter should maintain its own complete status
static ClockBase* clock()
{
return ClockFactory::get();
}
};
TTimePoint proc_start_;
TTimePoint loop_start_;
}} //namespace
static ClockBase* clock()
{
return ClockFactory::get();
}
};
}
} //namespace
#endif

Просмотреть файл

@ -16,296 +16,303 @@
#include "ClockFactory.hpp" //TODO: move this out of common_utils
#include "CancelToken.hpp"
namespace msr { namespace airlib {
class CancelableAction : public CancelToken {
protected:
virtual void executeAction() = 0;
public:
CancelableAction()
: is_complete_(false)
{
}
virtual ~CancelableAction();
void reset()
{
is_complete_ = false;
}
void execute()
{
try {
executeAction();
is_complete_ = true;
}
catch (...) {
is_complete_ = false;
throw;
}
}
bool isComplete() const
{
return is_complete_;
}
private:
std::atomic<bool> is_complete_;
};
// This wraps a condition_variable so we can handle the case where we may signal before wait
// and implement the semantics that say wait should be a noop in that case.
class WorkerThreadSignal
namespace msr
{
namespace airlib
{
std::condition_variable cv_;
std::mutex mutex_;
std::atomic<bool> signaled_;
public:
WorkerThreadSignal() : signaled_(false)
{
}
void signal()
class CancelableAction : public CancelToken
{
protected:
virtual void executeAction() = 0;
public:
CancelableAction()
: is_complete_(false)
{
std::unique_lock<std::mutex> lock(mutex_);
signaled_ = true;
}
cv_.notify_one();
}
virtual ~CancelableAction();
template<class _Predicate>
void wait(_Predicate cancel)
{
// wait for signal or cancel predicate
while (!signaled_) {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait_for(lock, std::chrono::milliseconds(1), [this, cancel] {
return cancel();
});
void reset()
{
is_complete_ = false;
}
signaled_ = false;
}
bool waitFor(double timeout_sec)
{
// wait for signal or timeout or cancel predicate
while (!signaled_) {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait_for(lock, std::chrono::milliseconds(
static_cast<long long>(timeout_sec * 1000)));
void execute()
{
try {
executeAction();
is_complete_ = true;
}
catch (...) {
is_complete_ = false;
throw;
}
}
signaled_ = false;
return true;
}
void wait()
{
// wait for signal or timeout or cancel predicate
std::unique_lock<std::mutex> lock(mutex_);
while (!signaled_) {
cv_.wait(lock);
bool isComplete() const
{
return is_complete_;
}
lock.unlock();
signaled_ = false;
}
bool waitForRetry(double timeout_sec, int n_times)
private:
std::atomic<bool> is_complete_;
};
// This wraps a condition_variable so we can handle the case where we may signal before wait
// and implement the semantics that say wait should be a noop in that case.
class WorkerThreadSignal
{
std::unique_lock<std::mutex> lock(mutex_);
while (!signaled_ && n_times > 0) {
cv_.wait_for(lock, std::chrono::milliseconds(static_cast<long long>(timeout_sec * 1000)));
--n_times;
std::condition_variable cv_;
std::mutex mutex_;
std::atomic<bool> signaled_;
public:
WorkerThreadSignal()
: signaled_(false)
{
}
lock.unlock();
if (n_times == 0 && !signaled_) {
return false;
void signal()
{
{
std::unique_lock<std::mutex> lock(mutex_);
signaled_ = true;
}
cv_.notify_one();
}
else {
template <class _Predicate>
void wait(_Predicate cancel)
{
// wait for signal or cancel predicate
while (!signaled_) {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait_for(lock, std::chrono::milliseconds(1), [this, cancel] {
return cancel();
});
}
signaled_ = false;
}
bool waitFor(double timeout_sec)
{
// wait for signal or timeout or cancel predicate
while (!signaled_) {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait_for(lock, std::chrono::milliseconds(static_cast<long long>(timeout_sec * 1000)));
}
signaled_ = false;
return true;
}
}
};
void wait()
{
// wait for signal or timeout or cancel predicate
std::unique_lock<std::mutex> lock(mutex_);
while (!signaled_) {
cv_.wait(lock);
}
lock.unlock();
signaled_ = false;
}
// This class provides a synchronized worker thread that guarantees to execute
// cancelable tasks on a background thread one at a time.
// It guarantees that previous task is canceled before new task is started.
// The queue size is 1, which means it does NOT guarantee all queued tasks are executed.
// If enqueue is called very quickly the thread will not have a chance to execute each
// task before they get canceled, worst case in a tight loop all tasks are starved and
// nothing executes.
class WorkerThread {
public:
WorkerThread()
: thread_running_(false), cancel_request_(false) {
}
bool waitForRetry(double timeout_sec, int n_times)
{
std::unique_lock<std::mutex> lock(mutex_);
while (!signaled_ && n_times > 0) {
cv_.wait_for(lock, std::chrono::milliseconds(static_cast<long long>(timeout_sec * 1000)));
--n_times;
}
lock.unlock();
if (n_times == 0 && !signaled_) {
return false;
}
else {
signaled_ = false;
return true;
}
}
};
~WorkerThread() {
cancel_request_ = true;
cancel();
}
void enqueue(std::shared_ptr<CancelableAction> item) {
//cancel previous item
// This class provides a synchronized worker thread that guarantees to execute
// cancelable tasks on a background thread one at a time.
// It guarantees that previous task is canceled before new task is started.
// The queue size is 1, which means it does NOT guarantee all queued tasks are executed.
// If enqueue is called very quickly the thread will not have a chance to execute each
// task before they get canceled, worst case in a tight loop all tasks are starved and
// nothing executes.
class WorkerThread
{
public:
WorkerThread()
: thread_running_(false), cancel_request_(false)
{
}
~WorkerThread()
{
cancel_request_ = true;
cancel();
}
void enqueue(std::shared_ptr<CancelableAction> item)
{
//cancel previous item
{
std::unique_lock<std::mutex> lock(mutex_);
std::shared_ptr<CancelableAction> pending = pending_item_;
if (pending != nullptr) {
pending->cancel();
}
}
bool running = false;
{
std::unique_lock<std::mutex> lock(mutex_);
pending_item_ = item;
running = thread_running_;
}
if (running) {
item_arrived_.signal();
}
else {
start();
}
}
bool enqueueAndWait(std::shared_ptr<CancelableAction> item, float timeout_sec)
{
//cancel previous item
{
std::unique_lock<std::mutex> lock(mutex_);
std::shared_ptr<CancelableAction> pending = pending_item_;
if (pending != nullptr) {
pending->cancel();
}
}
bool running = false;
//set new item to run
{
std::unique_lock<std::mutex> lock(mutex_);
pending_item_ = item;
running = thread_running_;
}
if (running) {
item_arrived_.signal();
}
else {
start();
}
item->sleep(timeout_sec);
//after the wait if item is still running then cancel it
if (!item->isCancelled() && !item->isComplete())
item->cancel();
return !item->isCancelled();
}
void cancel()
{
std::unique_lock<std::mutex> lock(mutex_);
std::shared_ptr<CancelableAction> pending = pending_item_;
pending_item_ = nullptr;
if (pending != nullptr) {
pending->cancel();
}
}
bool running = false;
{
std::unique_lock<std::mutex> lock(mutex_);
pending_item_ = item;
running = thread_running_;
}
if (running) {
item_arrived_.signal();
}
else {
start();
}
}
bool enqueueAndWait(std::shared_ptr<CancelableAction> item, float timeout_sec)
{
//cancel previous item
{
std::unique_lock<std::mutex> lock(mutex_);
std::shared_ptr<CancelableAction> pending = pending_item_;
if (pending != nullptr) {
pending->cancel();
if (thread_.joinable()) {
item_arrived_.signal();
thread_.join();
}
}
bool running = false;
//set new item to run
private:
void start()
{
std::unique_lock<std::mutex> lock(mutex_);
pending_item_ = item;
running = thread_running_;
//if state == not running
if (!thread_running_) {
//make sure C++ previous thread is done
{
std::unique_lock<std::mutex> lock(mutex_);
if (thread_.joinable()) {
thread_.join();
}
}
Utils::cleanupThread(thread_);
//start the thread
cancel_request_ = false;
thread_ = std::thread(&WorkerThread::run, this);
//wait until thread tells us it has started
thread_started_.wait([this] { return static_cast<bool>(cancel_request_); });
}
}
if (running) {
item_arrived_.signal();
}
else {
start();
}
void run()
{
thread_running_ = true;
item->sleep(timeout_sec);
//after the wait if item is still running then cancel it
if (!item->isCancelled() && !item->isComplete())
item->cancel();
return !item->isCancelled();
}
void cancel()
{
std::unique_lock<std::mutex> lock(mutex_);
std::shared_ptr<CancelableAction> pending = pending_item_;
pending_item_ = nullptr;
if (pending != nullptr) {
pending->cancel();
}
if (thread_.joinable()) {
item_arrived_.signal();
thread_.join();
}
}
private:
void start()
{
//if state == not running
if (!thread_running_) {
//make sure C++ previous thread is done
//tell the thread which started this thread that we are on now
{
std::unique_lock<std::mutex> lock(mutex_);
if (thread_.joinable()) {
thread_.join();
}
}
Utils::cleanupThread(thread_);
//start the thread
cancel_request_ = false;
thread_ = std::thread(&WorkerThread::run, this);
//wait until thread tells us it has started
thread_started_.wait([this] { return static_cast<bool>(cancel_request_); });
}
}
void run()
{
thread_running_ = true;
//tell the thread which started this thread that we are on now
{
std::unique_lock<std::mutex> lock(mutex_);
thread_started_.signal();
}
//until we don't get stopped and have work to do, keep running
while (!cancel_request_ && pending_item_ != nullptr) {
std::shared_ptr<CancelableAction> pending;
//get the pending item
{
std::unique_lock<std::mutex> lock(mutex_);
pending = pending_item_;
thread_started_.signal();
}
//if pending item is not yet cancelled
if (pending != nullptr && !pending->isCancelled()) {
//until we don't get stopped and have work to do, keep running
while (!cancel_request_ && pending_item_ != nullptr) {
std::shared_ptr<CancelableAction> pending;
//execute pending item
try {
pending->execute();
//get the pending item
{
std::unique_lock<std::mutex> lock(mutex_);
pending = pending_item_;
}
catch (std::exception& e) {
//Utils::DebugBreak();
Utils::log(Utils::stringf("WorkerThread caught unhandled exception: %s", e.what()), Utils::kLogLevelError);
//if pending item is not yet cancelled
if (pending != nullptr && !pending->isCancelled()) {
//execute pending item
try {
pending->execute();
}
catch (std::exception& e) {
//Utils::DebugBreak();
Utils::log(Utils::stringf("WorkerThread caught unhandled exception: %s", e.what()), Utils::kLogLevelError);
}
}
if (!cancel_request_) {
//wait for next item to arrive or thread is stopped
item_arrived_.wait([this] { return static_cast<bool>(cancel_request_); });
}
}
if (!cancel_request_) {
//wait for next item to arrive or thread is stopped
item_arrived_.wait([this] { return static_cast<bool>(cancel_request_); });
}
thread_running_ = false;
}
thread_running_ = false;
}
private:
//this is used to wait until our thread actually gets started
WorkerThreadSignal thread_started_;
//when new item arrived, we signal this so waiting thread can continue
WorkerThreadSignal item_arrived_;
private:
//this is used to wait until our thread actually gets started
WorkerThreadSignal thread_started_;
//when new item arrived, we signal this so waiting thread can continue
WorkerThreadSignal item_arrived_;
// thread state
std::shared_ptr<CancelableAction> pending_item_;
std::mutex mutex_;
std::thread thread_;
//while run() is in progress this is true
std::atomic<bool> thread_running_;
//has request to stop this worker thread made?
std::atomic<bool> cancel_request_;
};
}} //namespace
// thread state
std::shared_ptr<CancelableAction> pending_item_;
std::mutex mutex_;
std::thread thread_;
//while run() is in progress this is true
std::atomic<bool> thread_running_;
//has request to stop this worker thread made?
std::atomic<bool> cancel_request_;
};
}
} //namespace
#endif

Просмотреть файл

@ -7,14 +7,16 @@
#include "ctpl_stl.h"
#include <functional>
class AsyncTasker {
class AsyncTasker
{
public:
AsyncTasker(unsigned int thread_count = 4)
: threads_(thread_count), error_handler_([](std::exception e) {unused(e);})
: threads_(thread_count), error_handler_([](std::exception e) { unused(e); })
{
}
void setErrorHandler(std::function<void(std::exception&)> errorHandler) {
void setErrorHandler(std::function<void(std::exception&)> errorHandler)
{
error_handler_ = errorHandler;
}
@ -23,8 +25,7 @@ public:
if (iterations < 1)
return;
if (iterations == 1)
{
if (iterations == 1) {
threads_.push([=](int i) {
unused(i);
try {
@ -56,5 +57,4 @@ private:
std::function<void(std::exception&)> error_handler_;
};
#endif

Просмотреть файл

@ -1,13 +1,14 @@
#ifndef common_utils_OnlineStats_hpp
#define common_utils_OnlineStats_hpp
namespace common_utils {
namespace common_utils
{
class ColorUtils {
class ColorUtils
{
public:
static void valToRGB(double val0To1, unsigned char& r, unsigned char& g, unsigned char& b)
{//actual visible spectrum is 375 to 725 but outside of 400-700 things become too black
{ //actual visible spectrum is 375 to 725 but outside of 400-700 things become too black
wavelengthToRGB(val0To1 * (700 - 400) + 400, r, g, b);
}
@ -19,7 +20,8 @@ public:
* @return RGB color encoded in int. each color is represented with 8 bits and has a layout of
* 00000000RRRRRRRRGGGGGGGGBBBBBBBB where MSB is at the leftmost
*/
static void wavelengthToRGB(double wavelength, unsigned char& r, unsigned char& g, unsigned char& b) {
static void wavelengthToRGB(double wavelength, unsigned char& r, unsigned char& g, unsigned char& b)
{
double x, y, z;
cie1931WavelengthToXYZFit(wavelength, x, y, z);
double dr, dg, db;
@ -40,8 +42,9 @@ public:
* @param xyz XYZ values in a double array in the order of X, Y, Z. each value in the range of [0.0, 1.0]
* @return RGB values in a double array, in the order of R, G, B. each value in the range of [0.0, 1.0]
*/
static void srgbXYZ2RGB(double x, double y, double z, double& r, double& g, double& b) {
double rl = 3.2406255 * x + -1.537208 * y + -0.4986286 * z;
static void srgbXYZ2RGB(double x, double y, double z, double& r, double& g, double& b)
{
double rl = 3.2406255 * x + -1.537208 * y + -0.4986286 * z;
double gl = -0.9689307 * x + 1.8757561 * y + 0.0415175 * z;
double bl = 0.0557101 * x + -0.2040211 * y + 1.0569959 * z;
@ -53,7 +56,8 @@ public:
/**
* helper function for {@link #srgbXYZ2RGB(double[])}
*/
static double srgbXYZ2RGBPostprocess(double c) {
static double srgbXYZ2RGBPostprocess(double c)
{
// clip if c is out of range
c = c > 1 ? 1 : (c < 0 ? 0 : c);
@ -73,7 +77,8 @@ public:
* @param wavelength wavelength in nm
* @return XYZ in a double array in the order of X, Y, Z. each value in the range of [0.0, 1.0]
*/
static void cie1931WavelengthToXYZFit(double wavelength, double& x, double& y, double& z) {
static void cie1931WavelengthToXYZFit(double wavelength, double& x, double& y, double& z)
{
double wave = wavelength;
{
@ -81,28 +86,23 @@ public:
double t2 = (wave - 599.8) * ((wave < 599.8) ? 0.0264 : 0.0323);
double t3 = (wave - 501.1) * ((wave < 501.1) ? 0.0490 : 0.0382);
x = 0.362 * std::exp(-0.5 * t1 * t1)
+ 1.056 * std::exp(-0.5 * t2 * t2)
- 0.065 * std::exp(-0.5 * t3 * t3);
x = 0.362 * std::exp(-0.5 * t1 * t1) + 1.056 * std::exp(-0.5 * t2 * t2) - 0.065 * std::exp(-0.5 * t3 * t3);
}
{
double t1 = (wave - 568.8) * ((wave < 568.8) ? 0.0213 : 0.0247);
double t2 = (wave - 530.9) * ((wave < 530.9) ? 0.0613 : 0.0322);
y = 0.821 * std::exp(-0.5 * t1 * t1)
+ 0.286 * std::exp(-0.5 * t2 * t2);
y = 0.821 * std::exp(-0.5 * t1 * t1) + 0.286 * std::exp(-0.5 * t2 * t2);
}
{
double t1 = (wave - 437.0) * ((wave < 437.0) ? 0.0845 : 0.0278);
double t2 = (wave - 459.0) * ((wave < 459.0) ? 0.0385 : 0.0725);
z = 1.217 * std::exp(-0.5 * t1 * t1)
+ 0.681 * std::exp(-0.5 * t2 * t2);
z = 1.217 * std::exp(-0.5 * t1 * t1) + 0.681 * std::exp(-0.5 * t2 * t2);
}
}
};
} //namespace

Просмотреть файл

@ -4,110 +4,116 @@
#ifndef CommonUtils_EnumFlags_hpp
#define CommonUtils_EnumFlags_hpp
namespace common_utils {
namespace common_utils
{
template<typename TEnum,typename TUnderlying=typename std::underlying_type<TEnum>::type>
template <typename TEnum, typename TUnderlying = typename std::underlying_type<TEnum>::type>
class EnumFlags
{
protected:
TUnderlying flags_;
public:
EnumFlags()
: flags_(0)
{}
EnumFlags(TEnum singleFlag)
: flags_(static_cast<TUnderlying>(singleFlag))
{}
EnumFlags(TUnderlying flags)
: flags_(flags)
{}
EnumFlags(const EnumFlags& original)
: flags_(original.flags_)
{}
TUnderlying flags_;
EnumFlags& operator |=(TEnum add_value)
{
flags_ |= static_cast<TUnderlying>(add_value);
return *this;
}
EnumFlags& operator |=(EnumFlags add_value)
{
flags_ |= add_value.flags_;
return *this;
}
EnumFlags operator |(TEnum add_value) const
public:
EnumFlags()
: flags_(0)
{
EnumFlags result(*this);
result |= add_value;
}
EnumFlags(TEnum singleFlag)
: flags_(static_cast<TUnderlying>(singleFlag))
{
}
EnumFlags(TUnderlying flags)
: flags_(flags)
{
}
EnumFlags(const EnumFlags& original)
: flags_(original.flags_)
{
}
EnumFlags& operator|=(TEnum add_value)
{
flags_ |= static_cast<TUnderlying>(add_value);
return *this;
}
EnumFlags& operator|=(EnumFlags add_value)
{
flags_ |= add_value.flags_;
return *this;
}
EnumFlags operator|(TEnum add_value) const
{
EnumFlags result(*this);
result |= add_value;
return result;
}
EnumFlags operator |(EnumFlags add_value) const
EnumFlags operator|(EnumFlags add_value) const
{
EnumFlags result(*this);
result |= add_value.flags_;
EnumFlags result(*this);
result |= add_value.flags_;
return result;
}
EnumFlags& operator &=(TEnum mask_value)
{
EnumFlags& operator&=(TEnum mask_value)
{
flags_ &= static_cast<TUnderlying>(mask_value);
return *this;
}
EnumFlags& operator &=(EnumFlags mask_value)
{
EnumFlags& operator&=(EnumFlags mask_value)
{
flags_ &= mask_value.flags_;
return *this;
}
EnumFlags operator &(TEnum mask_value) const
{
EnumFlags operator&(TEnum mask_value) const
{
EnumFlags result(*this);
result &= mask_value;
return result;
return result;
}
EnumFlags operator &(EnumFlags mask_value) const
{
EnumFlags operator&(EnumFlags mask_value) const
{
EnumFlags result(*this);
result &= mask_value.flags_;
return result;
}
EnumFlags operator ~() const
{
return result;
}
EnumFlags operator~() const
{
EnumFlags result(*this);
result.flags_ = ~result.flags_;
return result;
}
EnumFlags& operator ^=(TEnum mask_value)
{
flags_ ^= mask_value;
return *this;
}
EnumFlags& operator ^=(EnumFlags mask_value)
{
flags_ ^= mask_value.flags_;
return *this;
}
EnumFlags operator ^(TEnum mask_value) const
{
EnumFlags result(*this);
result.flags_ ^= mask_value;
return result;
}
EnumFlags operator ^(EnumFlags mask_value) const
{
EnumFlags result(*this);
result.flags_ ^= mask_value.flags_;
return result;
}
EnumFlags& operator^=(TEnum mask_value)
{
flags_ ^= mask_value;
return *this;
}
EnumFlags& operator^=(EnumFlags mask_value)
{
flags_ ^= mask_value.flags_;
return *this;
}
EnumFlags operator^(TEnum mask_value) const
{
EnumFlags result(*this);
result.flags_ ^= mask_value;
return result;
}
EnumFlags operator^(EnumFlags mask_value) const
{
EnumFlags result(*this);
result.flags_ ^= mask_value.flags_;
return result;
}
//EnumFlags& operator ~=(TEnum mask_value)
//{
// flags_ ~= static_cast<TUnderlying>(mask_value);
// return *this;
//}
//EnumFlags& operator ~=(EnumFlags mask_value)
//{
// flags_ ~= mask_value.flags_;
// return *this;
//}
//EnumFlags& operator ~=(TEnum mask_value)
//{
// flags_ ~= static_cast<TUnderlying>(mask_value);
// return *this;
//}
//EnumFlags& operator ~=(EnumFlags mask_value)
//{
// flags_ ~= mask_value.flags_;
// return *this;
//}
//equality operators
bool operator==(const EnumFlags& rhs) const
@ -117,26 +123,24 @@ public:
inline bool operator!=(const EnumFlags& rhs) const
{
return !(*this == rhs);
}
}
//type conversion
operator bool() const
{
{
return flags_ != 0;
}
operator TUnderlying() const
{
return flags_;
}
TEnum toEnum() const
{
return static_cast<TEnum>(flags_);
}
};
} //namespace
} //namespace
#endif

Просмотреть файл

@ -20,26 +20,29 @@
#include <cxxabi.h>
#include <cstdlib>
namespace {
void * last_frames[20];
size_t last_size;
std::string exception_name;
namespace
{
void* last_frames[20];
size_t last_size;
std::string exception_name;
std::string demangle(const char *name) {
std::string demangle(const char* name)
{
int status;
std::unique_ptr<char,void(*)(void*)> realname(abi::__cxa_demangle(name, 0, 0, &status), &std::free);
std::unique_ptr<char, void (*)(void*)> realname(abi::__cxa_demangle(name, 0, 0, &status), &std::free);
return status ? "failed" : &*realname;
}
}
}
extern "C" {
void __cxa_throw(void *ex, void *info, void (*dest)(void *)) {
void __cxa_throw(void* ex, void* info, void (*dest)(void*))
{
exception_name = demangle(reinterpret_cast<const std::type_info*>(info)->name());
last_size = backtrace(last_frames, sizeof last_frames/sizeof(void*));
last_size = backtrace(last_frames, sizeof last_frames / sizeof(void*));
static void (*const rethrow)(void*,void*,void(*)(void*)) __attribute__ ((noreturn)) = (void (*)(void*,void*,void(*)(void*)))dlsym(RTLD_NEXT, "__cxa_throw");
rethrow(ex,info,dest);
}
static void (*const rethrow)(void*, void*, void (*)(void*)) __attribute__((noreturn)) = (void (*)(void*, void*, void (*)(void*)))dlsym(RTLD_NEXT, "__cxa_throw");
rethrow(ex, info, dest);
}
}
#pragma GCC diagnostic pop
@ -48,7 +51,7 @@ extern "C" {
void printExceptionStack()
{
#ifdef __GNUC__
backtrace_symbols_fd(last_frames, last_size, 2);
backtrace_symbols_fd(last_frames, last_size, 2);
#endif
}

Просмотреть файл

@ -9,23 +9,23 @@
#include <string>
#include "Utils.hpp"
// This defines a default folder name for all the files created by AirLib so they
// This defines a default folder name for all the files created by AirLib so they
// are all gathered nicely in one place in the user's documents folder.
#ifndef ProductFolderName
#define ProductFolderName "AirSim"
#define ProductFolderName "AirSim"
#endif
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS 1
#endif
namespace common_utils {
namespace common_utils
{
class FileSystem
{
typedef unsigned int uint;
public:
// please use the combine() method instead.
static const char kPathSeparator =
#ifdef _WIN32
@ -38,14 +38,14 @@ public:
static std::string getUserHomeFolder()
{
//Windows uses USERPROFILE, Linux uses HOME
#ifdef _WIN32
//Windows uses USERPROFILE, Linux uses HOME
#ifdef _WIN32
std::wstring userProfile = _wgetenv(L"USERPROFILE");
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
return converter.to_bytes(userProfile);
#else
#else
return std::getenv("HOME");
#endif
#endif
}
static std::string getUserDocumentsFolder();
@ -78,7 +78,7 @@ public:
if (parentFolder.size() > 0 && parentFolder[len - 1] == kPathSeparator) {
// parent already ends with '/'
return parentFolder + child;
}
}
len = child.size();
if (len > 0 && child[0] == kPathSeparator) {
// child already starts with '/'
@ -96,7 +96,6 @@ public:
}
}
static std::string getFileExtension(const std::string& str)
{
// bugbug: this is not unicode safe.
@ -121,8 +120,8 @@ public:
return fullPath;
}
static std::string getLogFileNamePath(const std::string& fullPath, const std::string& prefix, const std::string& suffix, const std::string& extension,
bool file_timestamp)
static std::string getLogFileNamePath(const std::string& fullPath, const std::string& prefix, const std::string& suffix, const std::string& extension,
bool file_timestamp)
{
//TODO: because this bug we are using alternative code with stringstream
//https://answers.unrealengine.com/questions/664905/unreal-crashes-on-two-lines-of-extremely-simple-st.html
@ -143,7 +142,7 @@ public:
}
static void openTextFile(const std::string& filepath, std::ifstream& file)
{
{
#ifdef _WIN32
// WIN32 will create the wrong file names if we don't first convert them to UTF-16.
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
@ -153,9 +152,9 @@ public:
file.open(filepath, std::ios::in);
#endif
}
static void createBinaryFile(const std::string& filepath, std::ofstream& file)
{
{
#ifdef _WIN32
// WIN32 will create the wrong file names if we don't first convert them to UTF-16.
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
@ -165,9 +164,9 @@ public:
file.open(filepath, std::ios::binary | std::ios::trunc);
#endif
}
static void createTextFile(const std::string& filepath, std::ofstream& file)
{
{
#ifdef _WIN32
// WIN32 will create the wrong file names if we don't first convert them to UTF-16.
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
@ -180,7 +179,7 @@ public:
if (file.fail())
throw std::ios_base::failure(std::strerror(errno));
}
static std::string createLogFile(const std::string& suffix, std::ofstream& flog)
{
std::string log_folderpath = common_utils::FileSystem::getLogFolderPath(false);
@ -198,12 +197,12 @@ public:
try {
std::getline(file, line);
}
catch(...) {
catch (...) {
if (!file.eof())
throw;
}
return line;
}
}
static void appendLineToFile(const std::string& filepath, const std::string& line)
{
@ -221,8 +220,6 @@ public:
file.exceptions(file.exceptions() | std::ios::failbit | std::ifstream::badbit);
file << line << std::endl;
}
};
}
}
#endif

Просмотреть файл

@ -8,25 +8,29 @@
#include <algorithm>
#include <tuple>
namespace common_utils {
namespace common_utils
{
template <typename T>
class MedianFilter {
private:
std::vector<T> buffer_, buffer_copy_;
int window_size_, window_size_2x_, window_size_half_;
float outlier_factor_;
int buffer_index_;
public:
MedianFilter();
MedianFilter(int window_size, float outlier_factor);
void initialize(int window_size, float outlier_factor);
std::tuple<double,double> filter(T value);
class MedianFilter
{
private:
std::vector<T> buffer_, buffer_copy_;
int window_size_, window_size_2x_, window_size_half_;
float outlier_factor_;
int buffer_index_;
public:
MedianFilter();
MedianFilter(int window_size, float outlier_factor);
void initialize(int window_size, float outlier_factor);
std::tuple<double, double> filter(T value);
};
template <typename T>
void MedianFilter<T>::initialize(int window_size, float outlier_factor) {
buffer_.resize(window_size);
void MedianFilter<T>::initialize(int window_size, float outlier_factor)
{
buffer_.resize(window_size);
buffer_copy_.resize(window_size);
window_size_ = window_size;
window_size_2x_ = window_size_ * 2;
@ -36,47 +40,51 @@ void MedianFilter<T>::initialize(int window_size, float outlier_factor) {
}
template <typename T>
MedianFilter<T>::MedianFilter() {
MedianFilter<T>::MedianFilter()
{
initialize(buffer_.capacity(), std::numeric_limits<float>::infinity());
}
template <typename T>
MedianFilter<T>::MedianFilter(int window_size, float outlier_factor) {
initialize(window_size, std::numeric_limits<float>::infinity());
MedianFilter<T>::MedianFilter(int window_size, float outlier_factor)
{
initialize(window_size, std::numeric_limits<float>::infinity());
}
template <typename T>
std::tuple<double,double> MedianFilter<T>::filter(T value){
std::tuple<double, double> MedianFilter<T>::filter(T value)
{
buffer_[buffer_index_++ % window_size_] = value;
if (buffer_index_ == window_size_2x_)
buffer_index_ = window_size_;
buffer_index_ = window_size_;
if (buffer_index_ >= window_size_) {
//find median
for(auto i = 0; i < window_size_; ++i)
for (auto i = 0; i < window_size_; ++i)
buffer_copy_[i] = buffer_[i];
std::sort(buffer_copy_.begin(), buffer_copy_.end());
double median = buffer_copy_[window_size_half_];
//average values that fall between upper and lower bound of median
auto lower_bound = median - median * outlier_factor_, upper_bound = median + median * outlier_factor_;
double sum = 0; int count = 0;
for(auto i = 0; i < window_size_; ++i) {
double sum = 0;
int count = 0;
for (auto i = 0; i < window_size_; ++i) {
if (buffer_copy_[i] >= lower_bound && buffer_copy_[i] <= upper_bound) {
sum += buffer_copy_[i];
++count;
}
}
double mean = sum / count;
double std_dev_sum = 0;
for(auto i = 0; i < window_size_; ++i) {
for (auto i = 0; i < window_size_; ++i) {
if (buffer_copy_[i] >= lower_bound && buffer_copy_[i] <= upper_bound) {
double diff = buffer_copy_[i] - mean;
sum += diff*diff;
double diff = buffer_copy_[i] - mean;
sum += diff * diff;
}
}
double variance = std_dev_sum / count;
double variance = std_dev_sum / count;
return std::make_tuple(mean, variance);
}
@ -87,6 +95,5 @@ std::tuple<double,double> MedianFilter<T>::filter(T value){
}
}
} //namespace
#endif

Просмотреть файл

@ -13,45 +13,45 @@ you may have to #undef whatever you are actually using.
#define WIN32_LEAN_AND_MEAN
// The below excludes some other unused services from the windows headers -- see windows.h for details.
#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_
#define NOVIRTUALKEYCODES // VK_*
#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_*
#define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
#define NOSYSMETRICS // SM_*
#define NOMENUS // MF_*
#define NOICONS // IDI_*
#define NOKEYSTATES // MK_*
#define NOSYSCOMMANDS // SC_*
#define NORASTEROPS // Binary and Tertiary raster ops
#define NOSHOWWINDOW // SW_*
#define OEMRESOURCE // OEM Resource values
#define NOATOM // Atom Manager routines
#define NOCLIPBOARD // Clipboard routines
#define NOCOLOR // Screen colors
#define NOCTLMGR // Control and Dialog routines
#define NODRAWTEXT // DrawText() and DT_*
#define NOGDI // All GDI #defines and routines
#define NOKERNEL // All KERNEL #defines and routines
#define NOUSER // All USER #defines and routines
#define NONLS // All NLS #defines and routines
#define NOMB // MB_* and MessageBox()
#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines
#define NOMETAFILE // typedef METAFILEPICT
#define NOMINMAX // Macros min(a,b) and max(a,b)
#define NOMSG // typedef MSG and associated routines
#define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_*
#define NOSCROLL // SB_* and scrolling routines
#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc.
#define NOSOUND // Sound driver routines
#define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines
#define NOWH // SetWindowsHook and WH_*
#define NOWINOFFSETS // GWL_*, GCL_*, associated routines
#define NOCOMM // COMM driver routines
#define NOKANJI // Kanji support stuff.
#define NOHELP // Help engine interface.
#define NOPROFILER // Profiler interface.
#define NODEFERWINDOWPOS // DeferWindowPos routines
#define NOMCX // Modem Configuration Extensions
#define NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_
#define NOVIRTUALKEYCODES // VK_*
#define NOWINMESSAGES // WM_*, EM_*, LB_*, CB_*
#define NOWINSTYLES // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
#define NOSYSMETRICS // SM_*
#define NOMENUS // MF_*
#define NOICONS // IDI_*
#define NOKEYSTATES // MK_*
#define NOSYSCOMMANDS // SC_*
#define NORASTEROPS // Binary and Tertiary raster ops
#define NOSHOWWINDOW // SW_*
#define OEMRESOURCE // OEM Resource values
#define NOATOM // Atom Manager routines
#define NOCLIPBOARD // Clipboard routines
#define NOCOLOR // Screen colors
#define NOCTLMGR // Control and Dialog routines
#define NODRAWTEXT // DrawText() and DT_*
#define NOGDI // All GDI #defines and routines
#define NOKERNEL // All KERNEL #defines and routines
#define NOUSER // All USER #defines and routines
#define NONLS // All NLS #defines and routines
#define NOMB // MB_* and MessageBox()
#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines
#define NOMETAFILE // typedef METAFILEPICT
#define NOMINMAX // Macros min(a,b) and max(a,b)
#define NOMSG // typedef MSG and associated routines
#define NOOPENFILE // OpenFile(), OemToAnsi, AnsiToOem, and OF_*
#define NOSCROLL // SB_* and scrolling routines
#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc.
#define NOSOUND // Sound driver routines
#define NOTEXTMETRIC // typedef TEXTMETRIC and associated routines
#define NOWH // SetWindowsHook and WH_*
#define NOWINOFFSETS // GWL_*, GCL_*, associated routines
#define NOCOMM // COMM driver routines
#define NOKANJI // Kanji support stuff.
#define NOHELP // Help engine interface.
#define NOPROFILER // Profiler interface.
#define NODEFERWINDOWPOS // DeferWindowPos routines
#define NOMCX // Modem Configuration Extensions
#define NOCRYPT
#define NOTAPE
#define NOIMAGE

Просмотреть файл

@ -6,11 +6,13 @@
#include <cmath>
namespace common_utils {
namespace common_utils
{
class OnlineStats {
class OnlineStats
{
public:
OnlineStats()
OnlineStats()
{
clear();
}
@ -32,7 +34,7 @@ public:
delta_n2 = delta_n * delta_n;
term1 = delta * delta_n * n1;
m1 += delta_n;
m4 += term1 * delta_n2 * (n*n - 3*n + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3;
m4 += term1 * delta_n2 * (n * n - 3 * n + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3;
m3 += term1 * delta_n * (n - 2) - 3 * delta_n * m2;
m2 += term1;
}
@ -49,7 +51,7 @@ public:
double variance() const
{
return m2/(n-1.0f);
return m2 / (n - 1.0f);
}
double standardDeviation() const
@ -59,12 +61,12 @@ public:
double skewness() const
{
return sqrt(double(n)) * m3/ pow(m2, 1.5f);
return sqrt(double(n)) * m3 / pow(m2, 1.5f);
}
double kurtosis() const
{
return double(n)*m4 / (m2*m2) - 3.0f;
return double(n) * m4 / (m2 * m2) - 3.0f;
}
OnlineStats operator+(const OnlineStats& rhs)
@ -74,29 +76,28 @@ public:
combined.n = this->n + rhs.n;
double delta = rhs.m1 - this->m1;
double delta2 = delta*delta;
double delta3 = delta*delta2;
double delta4 = delta2*delta2;
double delta2 = delta * delta;
double delta3 = delta * delta2;
double delta4 = delta2 * delta2;
combined.m1 = (this->n*this->m1 + rhs.n*rhs.m1) / combined.n;
combined.m1 = (this->n * this->m1 + rhs.n * rhs.m1) / combined.n;
combined.m2 = this->m2 + rhs.m2 +
delta2 * this->n * rhs.n / combined.n;
combined.m2 = this->m2 + rhs.m2 +
delta2 * this->n * rhs.n / combined.n;
combined.m3 = this->m3 + rhs.m3 +
delta3 * this->n * rhs.n * (this->n - rhs.n)/(combined.n*combined.n);
combined.m3 += 3.0f*delta * (this->n*rhs.m2 - rhs.n*this->m2) / combined.n;
combined.m3 = this->m3 + rhs.m3 +
delta3 * this->n * rhs.n * (this->n - rhs.n) / (combined.n * combined.n);
combined.m3 += 3.0f * delta * (this->n * rhs.m2 - rhs.n * this->m2) / combined.n;
combined.m4 = this->m4 + rhs.m4 + delta4*this->n*rhs.n * (this->n*this->n - this->n*rhs.n + rhs.n*rhs.n) /
(combined.n*combined.n*combined.n);
combined.m4 += 6.0f*delta2 * (this->n*this->n*rhs.m2 + rhs.n*rhs.n*this->m2)/(combined.n*combined.n) +
4.0f*delta*(this->n*rhs.m3 - rhs.n*this->m3) / combined.n;
combined.m4 = this->m4 + rhs.m4 + delta4 * this->n * rhs.n * (this->n * this->n - this->n * rhs.n + rhs.n * rhs.n) / (combined.n * combined.n * combined.n);
combined.m4 += 6.0f * delta2 * (this->n * this->n * rhs.m2 + rhs.n * rhs.n * this->m2) / (combined.n * combined.n) +
4.0f * delta * (this->n * rhs.m3 - rhs.n * this->m3) / combined.n;
return combined;
}
OnlineStats& operator+=(const OnlineStats& rhs)
{
{
OnlineStats combined = *this + rhs;
*this = combined;
return *this;
@ -108,5 +109,5 @@ private:
}; //class
} //namespace
} //namespace
#endif

Просмотреть файл

@ -10,7 +10,8 @@
#include <mutex>
#include <condition_variable>
namespace common_utils {
namespace common_utils
{
/*
This queue can support multiple producers consumers, but it should be used carefully
@ -39,11 +40,10 @@ public:
is_done_ = false;
}
T pop()
T pop()
{
std::unique_lock<std::mutex> global_lock(mutex_);
while (queue_.empty())
{
while (queue_.empty()) {
//this may be spurious wake-up
//in multi-consumer scenario
cond_.wait(global_lock);
@ -56,7 +56,7 @@ public:
bool tryPop(T& item)
{
std::unique_lock<std::mutex> global_lock(mutex_);
if(queue_.empty())
if (queue_.empty())
return false;
item = queue_.front();
@ -89,7 +89,7 @@ public:
global_lock.unlock();
cond_.notify_one();
}
//is_done_ flag is just convinience flag for external use
//its not used by this class
bool getIsDone()
@ -101,10 +101,9 @@ public:
is_done_ = val;
}
// non-copiable
ProsumerQueue(const ProsumerQueue&) = delete;
ProsumerQueue& operator=(const ProsumerQueue&) = delete;
ProsumerQueue(const ProsumerQueue&) = delete;
ProsumerQueue& operator=(const ProsumerQueue&) = delete;
private:
std::queue<T> queue_;
@ -112,6 +111,5 @@ private:
std::condition_variable cond_;
std::atomic<bool> is_done_;
};
}
#endif

Просмотреть файл

@ -6,14 +6,16 @@
#include <random>
namespace common_utils {
namespace common_utils
{
template<typename TReturn, typename TDistribution, unsigned int Seed=42>
class RandomGenerator {
template <typename TReturn, typename TDistribution, unsigned int Seed = 42>
class RandomGenerator
{
public:
//for uniform distribution supply min and max (inclusive)
//for gaussian distribution supply mean and sigma
template<typename... DistArgs>
template <typename... DistArgs>
RandomGenerator(DistArgs... dist_args)
: dist_(dist_args...), rand_(Seed)
{
@ -47,6 +49,5 @@ typedef RandomGenerator<unsigned int, std::uniform_int_distribution<unsigned int
//TODO: below we should have float instead of double but VC++2017 has a bug :(
typedef RandomGenerator<float, std::normal_distribution<double>> RandomGeneratorGaussianF;
typedef RandomGenerator<double, std::normal_distribution<double>> RandomGeneratorGaussianD;
}
#endif

Просмотреть файл

@ -12,13 +12,15 @@
#include <mutex>
#include <cstdint>
namespace common_utils {
namespace common_utils
{
class ScheduledExecutor
class ScheduledExecutor
{
public:
ScheduledExecutor()
{}
{
}
ScheduledExecutor(const std::function<bool(uint64_t)>& callback, uint64_t period_nanos)
{
@ -44,7 +46,7 @@ public:
is_first_period_ = true;
initializePauseState();
sleep_time_avg_ = 0;
Utils::cleanupThread(th_);
th_ = std::thread(&ScheduledExecutor::executorLoop, this);
@ -85,7 +87,7 @@ public:
void setFrameNumber(uint32_t frameNumber)
{
currentFrameNumber_ = frameNumber;
currentFrameNumber_ = frameNumber;
}
void stop()
@ -99,7 +101,7 @@ public:
th_.join();
}
}
catch(const std::system_error& /* e */) {
catch (const std::system_error& /* e */) {
}
}
}
@ -177,14 +179,14 @@ private:
TTimeDelta since_last_call = period_start - call_end;
if (frame_countdown_enabled_) {
if (targetFrameNumber_ <= currentFrameNumber_){
if (! isPaused())
if (targetFrameNumber_ <= currentFrameNumber_) {
if (!isPaused())
pause(true);
frame_countdown_enabled_ = false;
}
}
if (pause_period_start_ > 0) {
if (nanos() - pause_period_start_ >= pause_period_) {
pause(!isPaused());
@ -203,10 +205,10 @@ private:
started_ = result;
}
}
}
}
else
is_first_period_ = false;
call_end = nanos();
TTimeDelta elapsed_period = nanos() - period_start;
@ -231,11 +233,10 @@ private:
uint32_t currentFrameNumber_;
uint32_t targetFrameNumber_;
std::atomic_bool frame_countdown_enabled_;
double sleep_time_avg_;
std::mutex mutex_;
};
}
#endif

Просмотреть файл

@ -33,22 +33,25 @@ return 0;
*/
namespace common_utils {
namespace common_utils
{
template <typename... Args>
class Signal {
class Signal
{
public:
Signal() : current_id_(0) {}
Signal()
: current_id_(0) {}
// copy creates new signal
Signal(Signal const& other) : current_id_(0) {}
Signal(Signal const& other)
: current_id_(0) {}
// connects a member function to this Signal
template <typename T>
int connect_member(T *inst, void (T::*func)(Args...)) {
int connect_member(T* inst, void (T::*func)(Args...))
{
return connect([=](Args... args) {
(inst->*func)(args...);
});
@ -56,7 +59,8 @@ public:
// connects a const member function to this Signal
template <typename T>
int connect_member(T *inst, void (T::*func)(Args...) const) {
int connect_member(T* inst, void (T::*func)(Args...) const)
{
return connect([=](Args... args) {
(inst->*func)(args...);
});
@ -64,31 +68,36 @@ public:
// connects a std::function to the signal. The returned
// value can be used to disconnect the function again
int connect(std::function<void(Args...)> const& slot) const {
int connect(std::function<void(Args...)> const& slot) const
{
slots_.insert(std::make_pair(++current_id_, slot));
return current_id_;
}
// disconnects a previously connected function
void disconnect(int id) const {
void disconnect(int id) const
{
slots_.erase(id);
}
// disconnects all previously connected functions
void disconnect_all() const {
void disconnect_all() const
{
slots_.clear();
}
// calls all connected functions
void emit(Args... p) {
for(auto it=slots_.begin(); it!=slots_.end(); ) {
void emit(Args... p)
{
for (auto it = slots_.begin(); it != slots_.end();) {
// Increment here so that the entry can be erased from inside the method as well
(it++)->second(p...);
}
}
// assignment creates new Signal
Signal& operator=(Signal const& other) {
Signal& operator=(Signal const& other)
{
disconnect_all();
}
@ -96,7 +105,6 @@ private:
mutable std::map<int, std::function<void(Args...)>> slots_;
mutable int current_id_;
};
}
#endif /* common_utils_Signal_hpp */

Просмотреть файл

@ -8,32 +8,36 @@
#include <algorithm>
#include <tuple>
namespace common_utils {
namespace common_utils
{
// SmoothingFilter is a filter that removes the outliers that fall outside a given percentage from the min/max
// range of numbers over a given window size.
// range of numbers over a given window size.
template <typename T>
class SmoothingFilter {
private:
std::vector<T> buffer_;
int window_size_;
int window_size_2x_;
float outlier_factor_;
int buffer_index_;
public:
SmoothingFilter();
SmoothingFilter(int window_size, float outlier_factor);
void initialize(int window_size, float outlier_factor);
// Each call to the filter method adds to the current window, and returns
// the mean and variance over that window, after removing any outliers.
// It returns an error variance = -1 until the window is full. So you must
// ignore the first window_size values returned by this filter.
std::tuple<double,double> filter(T value);
class SmoothingFilter
{
private:
std::vector<T> buffer_;
int window_size_;
int window_size_2x_;
float outlier_factor_;
int buffer_index_;
public:
SmoothingFilter();
SmoothingFilter(int window_size, float outlier_factor);
void initialize(int window_size, float outlier_factor);
// Each call to the filter method adds to the current window, and returns
// the mean and variance over that window, after removing any outliers.
// It returns an error variance = -1 until the window is full. So you must
// ignore the first window_size values returned by this filter.
std::tuple<double, double> filter(T value);
};
template <typename T>
void SmoothingFilter<T>::initialize(int window_size, float outlier_factor) {
void SmoothingFilter<T>::initialize(int window_size, float outlier_factor)
{
buffer_.resize(window_size);
window_size_ = window_size;
window_size_2x_ = window_size * 2;
@ -42,54 +46,57 @@ void SmoothingFilter<T>::initialize(int window_size, float outlier_factor) {
}
template <typename T>
SmoothingFilter<T>::SmoothingFilter() {
SmoothingFilter<T>::SmoothingFilter()
{
initialize(static_cast<int>(buffer_.capacity()), std::numeric_limits<float>::infinity());
}
template <typename T>
SmoothingFilter<T>::SmoothingFilter(int window_size, float outlier_factor) {
initialize(window_size, std::numeric_limits<float>::infinity());
SmoothingFilter<T>::SmoothingFilter(int window_size, float outlier_factor)
{
initialize(window_size, std::numeric_limits<float>::infinity());
}
template <typename T>
std::tuple<double,double> SmoothingFilter<T>::filter(T value){
std::tuple<double, double> SmoothingFilter<T>::filter(T value)
{
buffer_[buffer_index_++ % window_size_] = value;
if (buffer_index_ == window_size_2x_)
buffer_index_ = window_size_;
buffer_index_ = window_size_;
if (buffer_index_ >= window_size_) {
// find min/max and range of the current buffer.
double min = *std::min_element(buffer_.begin(), buffer_.end());
double max = *std::max_element(buffer_.begin(), buffer_.end());
auto range = (max - min);
// outliers fall outside this lower and upper bound.
// outliers fall outside this lower and upper bound.
auto lower_bound = min + (range * outlier_factor_);
auto upper_bound = max - (range * outlier_factor_);
double sum = 0; int count = 0;
for(auto i = 0; i < window_size_; ++i) {
double sum = 0;
int count = 0;
for (auto i = 0; i < window_size_; ++i) {
if (buffer_[i] >= lower_bound && buffer_[i] <= upper_bound) {
sum += buffer_[i];
++count;
}
}
if (count == 0)
{
if (count == 0) {
// this can happen if the numbers are oddly clustered around the min/max values.
return std::make_tuple(double(min + range / 2), -1);
}
double mean = sum / count;
double std_dev_sum = 0;
for(auto i = 0; i < window_size_; ++i) {
for (auto i = 0; i < window_size_; ++i) {
if (buffer_[i] >= lower_bound && buffer_[i] <= upper_bound) {
double diff = buffer_[i] - mean;
std_dev_sum += diff*diff;
std_dev_sum += diff * diff;
}
}
double variance = std_dev_sum / count;
double variance = std_dev_sum / count;
return std::make_tuple(mean, variance);
}
@ -100,6 +107,5 @@ std::tuple<double,double> SmoothingFilter<T>::filter(T value){
}
}
} //namespace
#endif

Просмотреть файл

@ -3,49 +3,48 @@
#if defined(_MSC_VER)
//'=': conversion from 'double' to 'float', possible loss of data
#define STRICT_MODE_OFF \
__pragma(warning(push)) \
__pragma(warning( disable : 4100 4189 4244 4245 4239 4267 4365 4464 4456 4505 4514 4571 4624 4625 4626 4668 4701 4710 4820 4917 5026 5027 5031))
#define STRICT_MODE_ON \
__pragma(warning(pop))
#define STRICT_MODE_OFF \
__pragma(warning(push)) \
__pragma(warning(disable : 4100 4189 4244 4245 4239 4267 4365 4464 4456 4505 4514 4571 4624 4625 4626 4668 4701 4710 4820 4917 5026 5027 5031))
#define STRICT_MODE_ON \
__pragma(warning(pop))
//TODO: limit scope of below statements required to suppress VC++ warnings
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:4996)
#pragma warning(disable : 4996)
#endif
// special way to quiet the warning: warning: format string is not a string literal
#ifdef __CLANG__
#define IGNORE_FORMAT_STRING_ON \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"")
#define IGNORE_FORMAT_STRING_ON \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"")
#define IGNORE_FORMAT_STRING_OFF \
_Pragma("clang diagnostic pop")
#define IGNORE_FORMAT_STRING_OFF \
_Pragma("clang diagnostic pop")
#else
#define IGNORE_FORMAT_STRING_ON
#define IGNORE_FORMAT_STRING_OFF
#define IGNORE_FORMAT_STRING_OFF
#endif
// Please keep this list sorted so it is easier to find stuff, also make sure there
// Please keep this list sorted so it is easier to find stuff, also make sure there
// is no whitespace after the traling \, GCC doesn't like that.
#ifdef __CLANG__
#define STRICT_MODE_OFF \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wctor-dtor-privacy\"") \
_Pragma("clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"") \
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") \
_Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
_Pragma("clang diagnostic ignored \"-Wredundant-decls\"") \
_Pragma("clang diagnostic ignored \"-Wreturn-type\"") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
_Pragma("clang diagnostic ignored \"-Wstrict-overflow\"") \
_Pragma("clang diagnostic ignored \"-Wswitch-default\"") \
_Pragma("clang diagnostic ignored \"-Wundef\"") \
_Pragma("clang diagnostic ignored \"-Wunused-variable\"") \
_Pragma("clang diagnostic ignored \"-Wcast-qual\"") \
_Pragma("clang diagnostic ignored \"-Wunused-parameter\"")
#define STRICT_MODE_OFF \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wctor-dtor-privacy\"") \
_Pragma("clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"") \
_Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") \
_Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
_Pragma("clang diagnostic ignored \"-Wredundant-decls\"") \
_Pragma("clang diagnostic ignored \"-Wreturn-type\"") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
_Pragma("clang diagnostic ignored \"-Wstrict-overflow\"") \
_Pragma("clang diagnostic ignored \"-Wswitch-default\"") \
_Pragma("clang diagnostic ignored \"-Wundef\"") \
_Pragma("clang diagnostic ignored \"-Wunused-variable\"") \
_Pragma("clang diagnostic ignored \"-Wcast-qual\"") \
_Pragma("clang diagnostic ignored \"-Wunused-parameter\"")
/* Addition options that can be enabled
_Pragma("clang diagnostic ignored \"-Wpedantic\"") \
@ -55,27 +54,26 @@ _Pragma("clang diagnostic ignored \"-Werror=\"") \
_Pragma("clang diagnostic ignored \"-Wunused-variable\"") \
*/
#define STRICT_MODE_ON \
_Pragma("clang diagnostic pop")
#define STRICT_MODE_ON \
_Pragma("clang diagnostic pop")
#else
#ifdef __GNUC__
#define STRICT_MODE_OFF \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wctor-dtor-privacy\"") \
_Pragma("GCC diagnostic ignored \"-Wdelete-non-virtual-dtor\"") \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
_Pragma("GCC diagnostic ignored \"-Wold-style-cast\"") \
_Pragma("GCC diagnostic ignored \"-Wredundant-decls\"") \
_Pragma("GCC diagnostic ignored \"-Wreturn-type\"") \
_Pragma("GCC diagnostic ignored \"-Wshadow\"") \
_Pragma("GCC diagnostic ignored \"-Wstrict-overflow\"") \
_Pragma("GCC diagnostic ignored \"-Wswitch-default\"") \
_Pragma("GCC diagnostic ignored \"-Wundef\"") \
_Pragma("GCC diagnostic ignored \"-Wunused-variable\"") \
_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
#define STRICT_MODE_OFF \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wctor-dtor-privacy\"") \
_Pragma("GCC diagnostic ignored \"-Wdelete-non-virtual-dtor\"") \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
_Pragma("GCC diagnostic ignored \"-Wold-style-cast\"") \
_Pragma("GCC diagnostic ignored \"-Wredundant-decls\"") \
_Pragma("GCC diagnostic ignored \"-Wreturn-type\"") \
_Pragma("GCC diagnostic ignored \"-Wshadow\"") \
_Pragma("GCC diagnostic ignored \"-Wstrict-overflow\"") \
_Pragma("GCC diagnostic ignored \"-Wswitch-default\"") \
_Pragma("GCC diagnostic ignored \"-Wundef\"") \
_Pragma("GCC diagnostic ignored \"-Wunused-variable\"") \
_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
/* Addition options that can be enabled
_Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
@ -87,8 +85,8 @@ _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") \
*/
#define STRICT_MODE_ON \
_Pragma("GCC diagnostic pop")
#define STRICT_MODE_ON \
_Pragma("GCC diagnostic pop")
#endif
#endif

Просмотреть файл

@ -3,54 +3,59 @@
#include <chrono>
#include "Utils.hpp"
namespace common_utils {
class Timer {
public:
Timer()
{
started_ = false;
}
void start()
{
started_ = true;
start_ = now();
}
void stop()
{
started_ = false;
namespace common_utils
{
class Timer
{
public:
Timer()
{
started_ = false;
}
void start()
{
started_ = true;
start_ = now();
}
void stop()
{
started_ = false;
end_ = now();
}
double seconds()
{
auto diff = static_cast<double>(end() - start_);
return diff / 1000000.0;
}
double milliseconds()
{
return static_cast<double>(end() - start_) / 1000.0;
}
double microseconds()
{
return static_cast<double>(end() - start_);
}
bool started()
{
return started_;
}
private:
int64_t now()
{
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
int64_t end()
{
if (started_) {
// not stopped yet, so return "elapsed time so far".
end_ = now();
}
double seconds()
{
auto diff = static_cast<double>(end() - start_);
return diff / 1000000.0;
}
double milliseconds()
{
return static_cast<double>(end() - start_) / 1000.0;
}
double microseconds()
{
return static_cast<double>(end() - start_);
}
bool started()
{
return started_;
}
private:
int64_t now() {
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
int64_t end() {
if (started_) {
// not stopped yet, so return "elapsed time so far".
end_ = now();
}
return end_;
}
int64_t start_;
int64_t end_;
bool started_;
};
return end_;
}
int64_t start_;
int64_t end_;
bool started_;
};
}
#endif

Просмотреть файл

@ -7,12 +7,14 @@
#include <set>
#include "Utils.hpp"
namespace common_utils {
namespace common_utils
{
//This class allows to maintain unique set of values while
//This class allows to maintain unique set of values while
//still allowing key to value maps
template <class TKey, class TVal>
class UniqueValueMap {
class UniqueValueMap
{
public:
void insert(const TKey& key, const TVal& val)
{
@ -77,7 +79,5 @@ private:
std::map<TKey, TVal> map_;
std::set<TVal> vals_;
};
}
#endif

Просмотреть файл

@ -56,8 +56,7 @@
*/
#ifndef _MSC_VER
__attribute__((__format__ (__printf__, 1, 0)))
static int _vscprintf(const char * format, va_list pargs)
__attribute__((__format__(__printf__, 1, 0))) static int _vscprintf(const char* format, va_list pargs)
{
int retval;
va_list argcopy;
@ -71,12 +70,17 @@ static int _vscprintf(const char * format, va_list pargs)
#endif
// Call this on a function parameter to suppress the unused paramter warning
template <class T> inline
void unused(T const & result) { static_cast<void>(result); }
template <class T>
inline void unused(T const& result)
{
static_cast<void>(result);
}
namespace common_utils {
namespace common_utils
{
class Utils {
class Utils
{
private:
typedef std::chrono::system_clock system_clock;
typedef std::chrono::steady_clock steady_clock;
@ -85,11 +89,11 @@ private:
//this is not required for most compilers
typedef unsigned int uint;
template <typename T>
using time_point = std::chrono::time_point<T>;
using time_point = std::chrono::time_point<T>;
public:
class Logger {
class Logger
{
public:
virtual void log(int level, const std::string& message)
{
@ -99,13 +103,14 @@ public:
std::cerr << message << std::endl;
}
};
static void enableImmediateConsoleFlush() {
static void enableImmediateConsoleFlush()
{
//disable buffering
setbuf(stdout, NULL);
}
template<typename T>
template <typename T>
static T getRandomFromGaussian(T stddev = 1, T mean = 0)
{
static std::default_random_engine random_gen;
@ -113,25 +118,30 @@ public:
return gaussian_dist(random_gen) * stddev + mean;
}
static constexpr double degreesToRadians(double degrees) {
static constexpr double degreesToRadians(double degrees)
{
return static_cast<double>(M_PIl * degrees / 180.0);
}
static constexpr float degreesToRadians(float degrees) {
static constexpr float degreesToRadians(float degrees)
{
return static_cast<float>(M_PI * degrees / 180.0f);
}
static constexpr double radiansToDegrees(double radians) {
static constexpr double radiansToDegrees(double radians)
{
return static_cast<double>(radians * 180.0 / M_PIl);
}
static constexpr float radiansToDegrees(float radians) {
static constexpr float radiansToDegrees(float radians)
{
return static_cast<float>(radians * 180.0f / M_PI);
}
static bool startsWith(const string& s, const string& prefix) {
static bool startsWith(const string& s, const string& prefix)
{
return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;
}
template <template<class, class, class...> class TContainer, typename TKey, typename TVal, typename... Args>
template <template <class, class, class...> class TContainer, typename TKey, typename TVal, typename... Args>
static const TVal& findOrDefault(const TContainer<TKey, TVal, Args...>& m, TKey const& key, const TVal& default_val)
{
typename TContainer<TKey, TVal, Args...>::const_iterator it = m.find(key);
@ -140,7 +150,7 @@ public:
return it->second;
}
template <template<class, class, class...> class TContainer, typename TKey, typename TVal, typename... Args>
template <template <class, class, class...> class TContainer, typename TKey, typename TVal, typename... Args>
static const TVal& findOrDefault(const TContainer<TKey, TVal, Args...>& m, TKey const& key)
{
static TVal default_val;
@ -168,58 +178,60 @@ public:
if (level >= getSetMinLogLevel())
getSetLogger()->log(level, message);
}
static int getSetMinLogLevel(bool set_or_get = false,
int set_min_log_level = std::numeric_limits<int>::min())
static int getSetMinLogLevel(bool set_or_get = false,
int set_min_log_level = std::numeric_limits<int>::min())
{
static int min_log_level = std::numeric_limits<int>::min();
if (set_or_get)
min_log_level = set_min_log_level;
return min_log_level;
}
template <typename T>
static int sign(T val) {
static int sign(T val)
{
return T(0) < val ? 1 : (T(0) > val ? -1 : 0);
}
}
/// Limits absolute value whole preserving sign
template <typename T>
static T limitAbsValue(T val, T min_value, T max_value) {
template <typename T>
static T limitAbsValue(T val, T min_value, T max_value)
{
T val_abs = std::abs(val);
T val_limited = std::max(val_abs, min_value);
val_limited = std::min(val_limited, max_value);
return sign(val) * val_limited;
}
/// Limits absolute value whole preserving sign
template <typename T>
static T clip(T val, T min_value, T max_value) {
template <typename T>
static T clip(T val, T min_value, T max_value)
{
return std::max(min_value, std::min(val, max_value));
}
template<typename Range>
template <typename Range>
static const string printRange(Range&& range, const string& delim = ", ",
const string& prefix="(", const string& suffix=")")
const string& prefix = "(", const string& suffix = ")")
{
return printRange(std::begin(range), std::end(range), delim, prefix, suffix);
}
template<typename Iterator>
template <typename Iterator>
static const string printRange(Iterator start, Iterator last, const string& delim = ", ",
const string& prefix="(", const string& suffix=")")
const string& prefix = "(", const string& suffix = ")")
{
stringstream ss;
ss << prefix;
for (Iterator i = start; i != last; ++i)
{
for (Iterator i = start; i != last; ++i) {
if (i != start)
ss << delim;
ss << *i;
}
ss << suffix;
return ss.str();
return ss.str();
}
static std::string getFileExtension(const string& str)
@ -227,8 +239,7 @@ public:
int len = static_cast<int>(str.size());
const char* ptr = str.c_str();
int i = 0;
for (i = len - 1; i >= 0; i--)
{
for (i = len - 1; i >= 0; i--) {
if (ptr[i] == '.')
break;
}
@ -236,10 +247,11 @@ public:
return str.substr(i, len - i);
}
#ifndef _MSC_VER
__attribute__((__format__ (__printf__, 1, 0)))
#endif
static string stringf(const char* format, ...)
#ifndef _MSC_VER
__attribute__((__format__(__printf__, 1, 0)))
#endif
static string
stringf(const char* format, ...)
{
va_list args;
va_start(args, format);
@ -247,17 +259,17 @@ public:
IGNORE_FORMAT_STRING_ON
auto size = _vscprintf(format, args) + 1U;
IGNORE_FORMAT_STRING_OFF
std::unique_ptr<char[]> buf(new char[size] );
std::unique_ptr<char[]> buf(new char[size]);
#ifndef _MSC_VER
IGNORE_FORMAT_STRING_ON
vsnprintf(buf.get(), size, format, args);
IGNORE_FORMAT_STRING_OFF
#else
vsnprintf_s(buf.get(), size, _TRUNCATE, format, args);
#endif
#ifndef _MSC_VER
IGNORE_FORMAT_STRING_ON
vsnprintf(buf.get(), size, format, args);
IGNORE_FORMAT_STRING_OFF
#else
vsnprintf_s(buf.get(), size, _TRUNCATE, format, args);
#endif
va_end(args);
va_end(args);
return string(buf.get());
}
@ -267,14 +279,12 @@ public:
int len = static_cast<int>(str.size());
const char* ptr = str.c_str();
int i = 0;
for (i = 0; i < len; i++)
{
for (i = 0; i < len; i++) {
if (ptr[i] != ch)
break;
}
int j = 0;
for (j = len - 1; j >= i; j--)
{
for (j = len - 1; j >= i; j--) {
if (ptr[j] != ch)
break;
}
@ -285,29 +295,24 @@ public:
{
auto start = s.begin();
std::vector<string> result;
for (auto it = s.begin(); it != s.end(); it++)
{
for (auto it = s.begin(); it != s.end(); it++) {
char ch = *it;
bool split = false;
for (int i = 0; i < numSplitChars; i++)
{
for (int i = 0; i < numSplitChars; i++) {
if (ch == splitChars[i]) {
split = true;
break;
}
}
if (split)
{
if (start < it)
{
if (split) {
if (start < it) {
result.push_back(string(start, it));
}
start = it;
start++;
}
}
if (start < s.end())
{
if (start < s.end()) {
result.push_back(string(start, s.end()));
}
return result;
@ -321,25 +326,24 @@ public:
auto start = line.begin();
std::vector<std::string> result;
auto end = line.end();
for (auto it = line.begin(); it != end; )
{
for (auto it = line.begin(); it != end;) {
bool split = false;
char ch = *it;
if (ch == '\'' || ch == '"') {
// skip quoted literal
if (start < it)
{
if (start < it) {
result.push_back(string(start, it));
}
it++;
start = it;
for (; it != end; it++) {
for (; it != end; it++) {
if (*it == ch) {
break;
}
}
}
split = true;
} else {
}
else {
for (int i = 0; i < numSeparators; i++) {
if (ch == separators[i]) {
split = true;
@ -347,10 +351,8 @@ public:
}
}
}
if (split)
{
if (start < it)
{
if (split) {
if (start < it) {
result.push_back(string(start, it));
}
start = it;
@ -360,8 +362,7 @@ public:
it++;
}
}
if (start < end)
{
if (start < end) {
result.push_back(string(start, end));
}
return result;
@ -377,8 +378,7 @@ public:
_strlwr_s(buf.get(), len + 1U);
#else
char* p = buf.get();
for (int i = len; i > 0; i--)
{
for (int i = len; i > 0; i--) {
*p = tolower(*p);
p++;
}
@ -394,8 +394,7 @@ public:
// return (onecount != 0)
// ? (static_cast<R>(-1) >> ((sizeof(R) * CHAR_BIT) - onecount))
// : 0;
return static_cast<R>(-(onecount != 0))
& (static_cast<R>(-1) >> ((sizeof(R) * CHAR_BIT) - onecount));
return static_cast<R>(-(onecount != 0)) & (static_cast<R>(-1) >> ((sizeof(R) * CHAR_BIT) - onecount));
}
static void cleanupThread(std::thread& th)
@ -408,36 +407,39 @@ public:
static inline int floorToInt(float x)
{
return static_cast<int> (std::floor(x));
return static_cast<int>(std::floor(x));
}
template<typename T>
static constexpr T nan() {
template <typename T>
static constexpr T nan()
{
return std::numeric_limits<T>::quiet_NaN();
}
template<typename T>
static constexpr T max() {
template <typename T>
static constexpr T max()
{
return std::numeric_limits<T>::max();
}
template<typename T>
static constexpr T min() {
template <typename T>
static constexpr T min()
{
return std::numeric_limits<T>::min();
}
template<typename T>
template <typename T>
static void setValue(T arr[], size_t length, const T& val)
{
std::fill(arr, arr + length, val);
}
template<typename T, size_t N>
template <typename T, size_t N>
static void setValue(T (&arr)[N], const T& val)
{
std::fill(arr, arr+N, val);
std::fill(arr, arr + N, val);
}
template< class T, size_t N>
static std::size_t length(const T(&)[N])
template <class T, size_t N>
static std::size_t length(const T (&)[N])
{
return N;
}
@ -447,7 +449,7 @@ public:
std::ofstream file(file_name, std::ios::binary);
file.write(data, size);
}
template<typename Container>
template <typename Container>
static typename std::enable_if<type_utils::is_container<Container>::value, void>::type
append(Container& to, const Container& from)
{
@ -455,15 +457,15 @@ public:
using std::end;
to.insert(end(to), begin(from), end(from));
}
template<typename Container>
template <typename Container>
static typename std::enable_if<type_utils::is_container<Container>::value, void>::type
copy(const Container& from, Container& to)
copy(const Container& from, Container& to)
{
using std::begin;
using std::end;
std::copy(begin(from), end(from), begin(to));
}
template<typename T>
template <typename T>
static void copy(const T* from, T* to, uint count)
{
std::copy(from, from + count, to);
@ -500,7 +502,8 @@ public:
char str[1024];
if (std::strftime(str, sizeof(str), format, std::localtime(&tt)))
return string(str);
else return string();
else
return string();
}
static string to_string(time_point<system_clock> time, const char* format = "%Y-%m-%d-%H-%M-%S")
@ -509,7 +512,8 @@ public:
char str[1024];
if (std::strftime(str, sizeof(str), format, std::localtime(&tt)))
return string(str);
else return string();
else
return string();
}
static string getLogFileTimeStamp()
{
@ -537,27 +541,27 @@ public:
static double getTimeSinceEpochSecs(std::chrono::system_clock::time_point* t = nullptr)
{
using Clock = std::chrono::system_clock; //high res clock has epoch since boot instead of since 1970 for VC++
return std::chrono::duration<double>((t != nullptr ? *t : Clock::now() ).time_since_epoch()).count();
return std::chrono::duration<double>((t != nullptr ? *t : Clock::now()).time_since_epoch()).count();
}
static uint64_t getTimeSinceEpochNanos(std::chrono::system_clock::time_point* t = nullptr)
{
using Clock = std::chrono::system_clock; //high res clock has epoch since boot instead of since 1970 for VC++
return std::chrono::duration_cast<std::chrono::nanoseconds>(
(t != nullptr ? *t : Clock::now())
.time_since_epoch()).
count();
(t != nullptr ? *t : Clock::now())
.time_since_epoch())
.count();
}
template<typename T>
static void clear(std::queue<T> &q, size_t max_elements = SIZE_MAX)
template <typename T>
static void clear(std::queue<T>& q, size_t max_elements = SIZE_MAX)
{
while(!q.empty() && max_elements > 0) {
while (!q.empty() && max_elements > 0) {
q.pop();
--max_elements;
}
}
template<typename T>
template <typename T>
static const std::vector<T>& emptyVector()
{
static const std::vector<T> empty_vector;
@ -579,30 +583,30 @@ public:
return celcius + 273.15f;
}
template<typename TReal>
template <typename TReal>
static constexpr TReal epsilon()
{
return std::numeric_limits<TReal>::epsilon();
}
//implements relative method - do not use for comparing with zero
//use this most of the time, tolerance needs to be meaningful in your context
template<typename TReal>
static bool isApproximatelyEqual(TReal a, TReal b, TReal tolerance = epsilon<TReal>())
{
TReal diff = std::fabs(a - b);
if (diff <= tolerance)
return true;
//implements relative method - do not use for comparing with zero
//use this most of the time, tolerance needs to be meaningful in your context
template <typename TReal>
static bool isApproximatelyEqual(TReal a, TReal b, TReal tolerance = epsilon<TReal>())
{
TReal diff = std::fabs(a - b);
if (diff <= tolerance)
return true;
if (diff < std::fmax(std::fabs(a), std::fabs(b)) * tolerance)
return true;
if (diff < std::fmax(std::fabs(a), std::fabs(b)) * tolerance)
return true;
return false;
}
return false;
}
//supply tolerance that is meaningful in your context
//for example, default tolerance may not work if you are comparing double with float
template<typename TReal>
template <typename TReal>
static bool isApproximatelyZero(TReal a, TReal tolerance = epsilon<TReal>())
{
if (std::fabs(a) <= tolerance)
@ -610,10 +614,9 @@ public:
return false;
}
//use this when you want to be on safe side
//for example, don't start rover unless signal is above 1
template<typename TReal>
template <typename TReal>
static bool isDefinitelyLessThan(TReal a, TReal b, TReal tolerance = epsilon<TReal>())
{
TReal diff = a - b;
@ -625,7 +628,7 @@ public:
return false;
}
template<typename TReal>
template <typename TReal>
static bool isDefinitelyGreaterThan(TReal a, TReal b, TReal tolerance = epsilon<TReal>())
{
TReal diff = a - b;
@ -642,7 +645,7 @@ public:
//use this when you are only concerned about floating point precision issue
//for example, if you want to see if a is 1.0 by checking if its within
//10 closest representable floating point numbers around 1.0.
template<typename TReal>
template <typename TReal>
static bool isWithinPrecisionInterval(TReal a, TReal b, unsigned int interval_size = 1)
{
TReal min_a = a - (a - std::nextafter(a, std::numeric_limits<TReal>::lowest())) * interval_size;
@ -656,17 +659,19 @@ public:
#ifdef _MSC_VER
__debugbreak();
#else
//TODO: Use GCC and Clang version from https://github.com/scottt/debugbreak
//TODO: Use GCC and Clang version from https://github.com/scottt/debugbreak
#endif
}
//convert strongly typed enum to underlying scaler types
template <typename E>
static constexpr typename std::underlying_type<E>::type toNumeric(E e) {
static constexpr typename std::underlying_type<E>::type toNumeric(E e)
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
template <typename E>
static constexpr E toEnum(typename std::underlying_type<E>::type u) {
static constexpr E toEnum(typename std::underlying_type<E>::type u)
{
return static_cast<E>(u);
}
@ -674,33 +679,33 @@ public:
static bool isLittleEndian()
{
int intval = 1;
unsigned char *uval = reinterpret_cast<unsigned char *>(&intval);
unsigned char* uval = reinterpret_cast<unsigned char*>(&intval);
return uval[0] == 1;
}
static void writePFMfile(const float * const image_data, int width, int height, const std::string& path, float scalef=1)
static void writePFMfile(const float* const image_data, int width, int height, const std::string& path, float scalef = 1)
{
std::ofstream file(path.c_str(), std::ios::binary);
std::string bands;
float fvalue; // scale factor and temp value to hold pixel value
bands = "Pf"; // grayscale
float fvalue; // scale factor and temp value to hold pixel value
bands = "Pf"; // grayscale
// sign of scalefact indicates endianness, see pfm specs
if(isLittleEndian())
if (isLittleEndian())
scalef = -scalef;
// insert header information
file << bands << "\n";
file << width << " ";
file << height << "\n";
file << scalef << "\n";
// insert header information
file << bands << "\n";
file << width << " ";
file << height << "\n";
file << scalef << "\n";
if(bands == "Pf"){ // handle 1-band image
for (int i=0; i < height; i++) {
for(int j=0; j < width; ++j){
if (bands == "Pf") { // handle 1-band image
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; ++j) {
fvalue = image_data[i * width + j];
file.write(reinterpret_cast<char *>(&fvalue), sizeof(fvalue));
file.write(reinterpret_cast<char*>(&fvalue), sizeof(fvalue));
}
}
}
@ -713,29 +718,29 @@ public:
std::ofstream file(path.c_str(), std::ios::binary);
// Header information
file << "P6\n"; // Magic type for PPM files
file << "P6\n"; // Magic type for PPM files
file << width << " " << height << "\n";
file << "255\n"; // Max color value
file << "255\n"; // Max color value
auto write_binary = [&file](const uint8_t &data) {
auto write_binary = [&file](const uint8_t& data) {
file.write(reinterpret_cast<const char*>(&data), sizeof(data));
};
for (int i=0; i<height; i++) {
for (int j=0; j<width; j++) {
int id = (i*width + j)*3; // Pixel index
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int id = (i * width + j) * 3; // Pixel index
// Image is in BGR, write as RGB
write_binary(image_data[id+2]); // R
write_binary(image_data[id+1]); // G
write_binary(image_data[id]); // B
write_binary(image_data[id + 2]); // R
write_binary(image_data[id + 1]); // G
write_binary(image_data[id]); // B
}
}
file.close();
}
template<typename T>
template <typename T>
static std::string toBinaryString(const T& x)
{
std::stringstream ss;

Просмотреть файл

@ -11,7 +11,7 @@
#include "Windows/AllowWindowsPlatformAtomics.h"
//remove warnings for VC++
#pragma warning(push)
#pragma warning(disable:4191 6000 28251)
#pragma warning(disable:4996) //warning C4996: This function or variable may be unsafe. Consider using xxx instead.
#pragma warning(disable:4005) //warning C4005: 'TEXT': macro redefinition
#pragma warning(disable : 4191 6000 28251)
#pragma warning(disable : 4996) //warning C4996: This function or variable may be unsafe. Consider using xxx instead.
#pragma warning(disable : 4005) //warning C4005: 'TEXT': macro redefinition
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -16,7 +16,6 @@
*
*********************************************************/
#ifndef __ctpl_stl_thread_pool_H__
#define __ctpl_stl_thread_pool_H__
@ -30,225 +29,242 @@
#include <mutex>
#include <queue>
// thread pool to run user's functors with signature
// ret func(int id, other_params)
// where id is the index of the thread that runs the functor
// ret is some return type
namespace ctpl
{
namespace ctpl {
namespace detail {
template <typename T>
class Queue {
public:
bool push(T const & value) {
std::unique_lock<std::mutex> lock(this->mutex);
this->q.push(value);
return true;
}
// deletes the retrieved element, do not use for non integral types
bool pop(T & v) {
std::unique_lock<std::mutex> lock(this->mutex);
if (this->q.empty())
return false;
v = this->q.front();
this->q.pop();
return true;
}
bool empty() {
std::unique_lock<std::mutex> lock(this->mutex);
return this->q.empty();
}
private:
std::queue<T> q;
std::mutex mutex;
};
}
class thread_pool {
namespace detail
{
template <typename T>
class Queue
{
public:
thread_pool() { this->init(); }
thread_pool(int nThreads) { this->init(); this->resize(nThreads); }
// the destructor waits for all the functions in the queue to be finished
~thread_pool() {
this->stop(true);
}
// get the number of running threads in the pool
int size() { return static_cast<int>(this->threads.size()); }
// number of idle threads
int n_idle() { return this->nWaiting; }
std::thread & get_thread(int i) { return *this->threads[i]; }
// change the number of threads in the pool
// should be called from one thread, otherwise be careful to not interleave, also with this->stop()
// nThreads must be >= 0
void resize(int nThreads) {
if (!this->isStop && !this->isDone) {
int oldNThreads = static_cast<int>(this->threads.size());
if (oldNThreads <= nThreads) { // if the number of threads is increased
this->threads.resize(nThreads);
this->flags.resize(nThreads);
for (int i = oldNThreads; i < nThreads; ++i) {
this->flags[i] = std::make_shared<std::atomic<bool>>(false);
this->set_thread(i);
}
}
else { // the number of threads is decreased
for (int i = oldNThreads - 1; i >= nThreads; --i) {
*this->flags[i] = true; // this thread will finish
this->threads[i]->detach();
}
{
// stop the detached threads that were waiting
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all();
}
this->threads.resize(nThreads); // safe to delete because the threads are detached
this->flags.resize(nThreads); // safe to delete because the threads have copies of shared_ptr of the flags, not originals
}
}
}
// empty the queue
void clear_queue() {
std::function<void(int id)> * _f;
while (this->q.pop(_f))
delete _f; // empty the queue
}
// pops a functional wrapper to the original function
std::function<void(int)> pop() {
std::function<void(int id)> * _f = nullptr;
this->q.pop(_f);
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
std::function<void(int)> f;
if (_f)
f = *_f;
return f;
}
// wait for all computing threads to finish and stop all threads
// may be called asynchronously to not pause the calling thread while waiting
// if isWait == true, all the functions in the queue are run, otherwise the queue is cleared without running the functions
void stop(bool isWait = false) {
if (!isWait) {
if (this->isStop)
return;
this->isStop = true;
for (int i = 0, n = this->size(); i < n; ++i) {
*this->flags[i] = true; // command the threads to stop
}
this->clear_queue(); // empty the queue
}
else {
if (this->isDone || this->isStop)
return;
this->isDone = true; // give the waiting threads a command to finish
}
{
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all(); // stop all waiting threads
}
for (int i = 0; i < static_cast<int>(this->threads.size()); ++i) { // wait for the computing threads to finish
if (this->threads[i]->joinable())
this->threads[i]->join();
}
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
// therefore delete them here
this->clear_queue();
this->threads.clear();
this->flags.clear();
}
template<typename F, typename... Rest>
auto push(F && f, Rest&&... rest) ->std::future<decltype(f(0, rest...))> {
auto pck = std::make_shared<std::packaged_task<decltype(f(0, rest...))(int)>>(
std::bind(std::forward<F>(f), std::placeholders::_1, std::forward<Rest>(rest)...)
);
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
this->q.push(_f);
bool push(T const& value)
{
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
this->q.push(value);
return true;
}
// run the user's function that excepts argument int - id of the running thread. returned value is templatized
// operator returns std::future, where the user can get the result and rethrow the catched exceptins
template<typename F>
auto push(F && f) ->std::future<decltype(f(0))> {
auto pck = std::make_shared<std::packaged_task<decltype(f(0))(int)>>(std::forward<F>(f));
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
this->q.push(_f);
// deletes the retrieved element, do not use for non integral types
bool pop(T& v)
{
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
if (this->q.empty())
return false;
v = this->q.front();
this->q.pop();
return true;
}
bool empty()
{
std::unique_lock<std::mutex> lock(this->mutex);
return this->q.empty();
}
private:
// deleted
thread_pool(const thread_pool &);// = delete;
thread_pool(thread_pool &&);// = delete;
thread_pool & operator=(const thread_pool &);// = delete;
thread_pool & operator=(thread_pool &&);// = delete;
void set_thread(int i) {
std::shared_ptr<std::atomic<bool>> flag(this->flags[i]); // a copy of the shared ptr to the flag
auto f = [this, i, flag/* a copy of the shared ptr to the flag */]() {
std::atomic<bool> & _flag = *flag;
std::function<void(int id)> * _f;
bool isPop = this->q.pop(_f);
while (true) {
while (isPop) { // if there is anything in the queue
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
(*_f)(i);
if (_flag)
return; // the thread is wanted to stop, return even if the queue is not empty yet
else
isPop = this->q.pop(_f);
}
// the queue is empty here, wait for the next command
std::unique_lock<std::mutex> lock(this->mutex);
++this->nWaiting;
this->cv.wait(lock, [this, &_f, &isPop, &_flag](){ isPop = this->q.pop(_f); return isPop || this->isDone || _flag; });
--this->nWaiting;
if (!isPop)
return; // if the queue is empty and this->isDone == true or *flag then return
}
};
if (this->threads[i] != nullptr && this->threads[i]->joinable())
this->threads[i]->detach();
this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique()
}
void init() { this->nWaiting = 0; this->isStop = false; this->isDone = false; }
std::vector<std::unique_ptr<std::thread>> threads;
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
detail::Queue<std::function<void(int id)> *> q;
std::atomic<bool> isDone;
std::atomic<bool> isStop;
std::atomic<int> nWaiting; // how many threads are waiting
std::queue<T> q;
std::mutex mutex;
std::condition_variable cv;
};
}
class thread_pool
{
public:
thread_pool() { this->init(); }
thread_pool(int nThreads)
{
this->init();
this->resize(nThreads);
}
// the destructor waits for all the functions in the queue to be finished
~thread_pool()
{
this->stop(true);
}
// get the number of running threads in the pool
int size() { return static_cast<int>(this->threads.size()); }
// number of idle threads
int n_idle() { return this->nWaiting; }
std::thread& get_thread(int i) { return *this->threads[i]; }
// change the number of threads in the pool
// should be called from one thread, otherwise be careful to not interleave, also with this->stop()
// nThreads must be >= 0
void resize(int nThreads)
{
if (!this->isStop && !this->isDone) {
int oldNThreads = static_cast<int>(this->threads.size());
if (oldNThreads <= nThreads) { // if the number of threads is increased
this->threads.resize(nThreads);
this->flags.resize(nThreads);
for (int i = oldNThreads; i < nThreads; ++i) {
this->flags[i] = std::make_shared<std::atomic<bool>>(false);
this->set_thread(i);
}
}
else { // the number of threads is decreased
for (int i = oldNThreads - 1; i >= nThreads; --i) {
*this->flags[i] = true; // this thread will finish
this->threads[i]->detach();
}
{
// stop the detached threads that were waiting
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all();
}
this->threads.resize(nThreads); // safe to delete because the threads are detached
this->flags.resize(nThreads); // safe to delete because the threads have copies of shared_ptr of the flags, not originals
}
}
}
// empty the queue
void clear_queue()
{
std::function<void(int id)>* _f;
while (this->q.pop(_f))
delete _f; // empty the queue
}
// pops a functional wrapper to the original function
std::function<void(int)> pop()
{
std::function<void(int id)>* _f = nullptr;
this->q.pop(_f);
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
std::function<void(int)> f;
if (_f)
f = *_f;
return f;
}
// wait for all computing threads to finish and stop all threads
// may be called asynchronously to not pause the calling thread while waiting
// if isWait == true, all the functions in the queue are run, otherwise the queue is cleared without running the functions
void stop(bool isWait = false)
{
if (!isWait) {
if (this->isStop)
return;
this->isStop = true;
for (int i = 0, n = this->size(); i < n; ++i) {
*this->flags[i] = true; // command the threads to stop
}
this->clear_queue(); // empty the queue
}
else {
if (this->isDone || this->isStop)
return;
this->isDone = true; // give the waiting threads a command to finish
}
{
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all(); // stop all waiting threads
}
for (int i = 0; i < static_cast<int>(this->threads.size()); ++i) { // wait for the computing threads to finish
if (this->threads[i]->joinable())
this->threads[i]->join();
}
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
// therefore delete them here
this->clear_queue();
this->threads.clear();
this->flags.clear();
}
template <typename F, typename... Rest>
auto push(F&& f, Rest&&... rest) -> std::future<decltype(f(0, rest...))>
{
auto pck = std::make_shared<std::packaged_task<decltype(f(0, rest...))(int)>>(
std::bind(std::forward<F>(f), std::placeholders::_1, std::forward<Rest>(rest)...));
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
this->q.push(_f);
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
}
// run the user's function that excepts argument int - id of the running thread. returned value is templatized
// operator returns std::future, where the user can get the result and rethrow the catched exceptins
template <typename F>
auto push(F&& f) -> std::future<decltype(f(0))>
{
auto pck = std::make_shared<std::packaged_task<decltype(f(0))(int)>>(std::forward<F>(f));
auto _f = new std::function<void(int id)>([pck](int id) {
(*pck)(id);
});
this->q.push(_f);
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_one();
return pck->get_future();
}
private:
// deleted
thread_pool(const thread_pool&); // = delete;
thread_pool(thread_pool&&); // = delete;
thread_pool& operator=(const thread_pool&); // = delete;
thread_pool& operator=(thread_pool&&); // = delete;
void set_thread(int i)
{
std::shared_ptr<std::atomic<bool>> flag(this->flags[i]); // a copy of the shared ptr to the flag
auto f = [this, i, flag /* a copy of the shared ptr to the flag */]() {
std::atomic<bool>& _flag = *flag;
std::function<void(int id)>* _f;
bool isPop = this->q.pop(_f);
while (true) {
while (isPop) { // if there is anything in the queue
std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
(*_f)(i);
if (_flag)
return; // the thread is wanted to stop, return even if the queue is not empty yet
else
isPop = this->q.pop(_f);
}
// the queue is empty here, wait for the next command
std::unique_lock<std::mutex> lock(this->mutex);
++this->nWaiting;
this->cv.wait(lock, [this, &_f, &isPop, &_flag]() { isPop = this->q.pop(_f); return isPop || this->isDone || _flag; });
--this->nWaiting;
if (!isPop)
return; // if the queue is empty and this->isDone == true or *flag then return
}
};
if (this->threads[i] != nullptr && this->threads[i]->joinable())
this->threads[i]->detach();
this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique()
}
void init()
{
this->nWaiting = 0;
this->isStop = false;
this->isDone = false;
}
std::vector<std::unique_ptr<std::thread>> threads;
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
detail::Queue<std::function<void(int id)>*> q;
std::atomic<bool> isDone;
std::atomic<bool> isStop;
std::atomic<int> nWaiting; // how many threads are waiting
std::mutex mutex;
std::condition_variable cv;
};
}
#endif // __ctpl_stl_thread_pool_H__

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -24,422 +24,486 @@
namespace pretty_print
{
namespace detail
namespace detail
{
// SFINAE type trait to detect whether T::const_iterator exists.
struct sfinae_base
{
// SFINAE type trait to detect whether T::const_iterator exists.
struct sfinae_base
{
using yes = char;
using no = yes[2];
};
template <typename T>
struct has_const_iterator : private sfinae_base
{
private:
template <typename C> static yes & test(typename C::const_iterator*);
template <typename C> static no & test(...);
public:
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
using type = T;
};
template <typename T>
struct has_begin_end : private sfinae_base
{
private:
template <typename C>
static yes & f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
typename C::const_iterator(C::*)() const>::value>::type *);
template <typename C> static no & f(...);
template <typename C>
static yes & g(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
typename C::const_iterator(C::*)() const>::value, void>::type*);
template <typename C> static no & g(...);
public:
static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
};
} // namespace detail
// Holds the delimiter values for a specific character type
template <typename TChar>
struct delimiters_values
{
using char_type = TChar;
const char_type * prefix;
const char_type * delimiter;
const char_type * postfix;
using yes = char;
using no = yes[2];
};
// Defines the delimiter values for a specific container and character type
template <typename T, typename TChar>
struct delimiters
template <typename T>
struct has_const_iterator : private sfinae_base
{
using type = delimiters_values<TChar>;
static const type values;
private:
template <typename C>
static yes& test(typename C::const_iterator*);
template <typename C>
static no& test(...);
public:
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
using type = T;
};
// Functor to print containers. You can use this directly if you want
// to specificy a non-default delimiters type. The printing logic can
// be customized by specializing the nested template.
template <typename T,
typename TChar = char,
typename TCharTraits = ::std::char_traits<TChar>,
typename TDelimiters = delimiters<T, TChar>>
struct print_container_helper
template <typename T>
struct has_begin_end : private sfinae_base
{
using delimiters_type = TDelimiters;
using ostream_type = std::basic_ostream<TChar, TCharTraits>;
private:
template <typename C>
static yes& f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)),
typename C::const_iterator (C::*)() const>::value>::type*);
template <typename U>
struct printer
template <typename C>
static no& f(...);
template <typename C>
static yes& g(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::end)),
typename C::const_iterator (C::*)() const>::value,
void>::type*);
template <typename C>
static no& g(...);
public:
static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
};
} // namespace detail
// Holds the delimiter values for a specific character type
template <typename TChar>
struct delimiters_values
{
using char_type = TChar;
const char_type* prefix;
const char_type* delimiter;
const char_type* postfix;
};
// Defines the delimiter values for a specific container and character type
template <typename T, typename TChar>
struct delimiters
{
using type = delimiters_values<TChar>;
static const type values;
};
// Functor to print containers. You can use this directly if you want
// to specificy a non-default delimiters type. The printing logic can
// be customized by specializing the nested template.
template <typename T,
typename TChar = char,
typename TCharTraits = ::std::char_traits<TChar>,
typename TDelimiters = delimiters<T, TChar>>
struct print_container_helper
{
using delimiters_type = TDelimiters;
using ostream_type = std::basic_ostream<TChar, TCharTraits>;
template <typename U>
struct printer
{
static void print_body(const U& c, ostream_type& stream)
{
static void print_body(const U & c, ostream_type & stream)
{
using std::begin;
using std::end;
using std::begin;
using std::end;
auto it = begin(c);
const auto the_end = end(c);
auto it = begin(c);
const auto the_end = end(c);
if (it != the_end)
{
for ( ; ; )
{
stream << *it;
if (it != the_end) {
for (;;) {
stream << *it;
if (++it == the_end) break;
if (delimiters_type::values.delimiter != NULL)
stream << delimiters_type::values.delimiter;
}
}
}
};
}
};
print_container_helper(const T & container)
print_container_helper(const T& container)
: container_(container)
{ }
inline void operator()(ostream_type & stream) const
{
if (delimiters_type::values.prefix != NULL)
stream << delimiters_type::values.prefix;
printer<T>::print_body(container_, stream);
if (delimiters_type::values.postfix != NULL)
stream << delimiters_type::values.postfix;
}
private:
const T & container_;
};
// Specialization for pairs
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename T1, typename T2>
struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>>
{
using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
static void print_body(const std::pair<T1, T2> & c, ostream_type & stream)
{
stream << c.first;
if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
stream << c.second;
}
};
// Specialization for tuples
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename ...Args>
struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>>
{
using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
using element_type = std::tuple<Args...>;
template <std::size_t I> struct Int { };
static void print_body(const element_type & c, ostream_type & stream)
{
tuple_print(c, stream, Int<0>());
}
static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>)
{
}
static void tuple_print(const element_type & c, ostream_type & stream,
typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type)
{
stream << std::get<0>(c);
tuple_print(c, stream, Int<1>());
}
template <std::size_t N>
static void tuple_print(const element_type & c, ostream_type & stream, Int<N>)
{
if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
stream << std::get<N>(c);
tuple_print(c, stream, Int<N + 1>());
}
};
// Prints a print_container_helper to the specified stream.
template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
inline std::basic_ostream<TChar, TCharTraits> & operator<<(
std::basic_ostream<TChar, TCharTraits> & stream,
const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
{
helper(stream);
return stream;
}
inline void operator()(ostream_type& stream) const
{
if (delimiters_type::values.prefix != NULL)
stream << delimiters_type::values.prefix;
// Basic is_container template; specialize to derive from std::true_type for all desired container types
printer<T>::print_body(container_, stream);
template <typename T>
struct is_container : public std::integral_constant<bool,
detail::has_const_iterator<T>::value &&
detail::has_begin_end<T>::beg_value &&
detail::has_begin_end<T>::end_value> { };
if (delimiters_type::values.postfix != NULL)
stream << delimiters_type::values.postfix;
}
template <typename T, std::size_t N>
struct is_container<T[N]> : std::true_type { };
private:
const T& container_;
};
// Specialization for pairs
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename T1, typename T2>
struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>>
{
using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
static void print_body(const std::pair<T1, T2>& c, ostream_type& stream)
{
stream << c.first;
if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
stream << c.second;
}
};
// Specialization for tuples
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename... Args>
struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>>
{
using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
using element_type = std::tuple<Args...>;
template <std::size_t I>
struct Int
{
};
static void print_body(const element_type& c, ostream_type& stream)
{
tuple_print(c, stream, Int<0>());
}
static void tuple_print(const element_type&, ostream_type&, Int<sizeof...(Args)>)
{
}
static void tuple_print(const element_type& c, ostream_type& stream,
typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type)
{
stream << std::get<0>(c);
tuple_print(c, stream, Int<1>());
}
template <std::size_t N>
struct is_container<char[N]> : std::false_type { };
template <typename T>
struct is_container<std::valarray<T>> : std::true_type { };
template <typename T1, typename T2>
struct is_container<std::pair<T1, T2>> : std::true_type { };
template <typename ...Args>
struct is_container<std::tuple<Args...>> : std::true_type { };
// Default delimiters
template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
// Delimiters for (multi)set and unordered_(multi)set
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
// Delimiters for pair and tuple
template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; };
template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };
template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };
// Type-erasing helper class for easy use of custom delimiters.
// Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
// Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
struct custom_delims_base
static void tuple_print(const element_type& c, ostream_type& stream, Int<N>)
{
virtual ~custom_delims_base() { }
virtual std::ostream & stream(::std::ostream &) = 0;
virtual std::wostream & stream(::std::wostream &) = 0;
};
if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
template <typename T, typename Delims>
struct custom_delims_wrapper : custom_delims_base
stream << std::get<N>(c);
tuple_print(c, stream, Int<N + 1>());
}
};
// Prints a print_container_helper to the specified stream.
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
inline std::basic_ostream<TChar, TCharTraits>& operator<<(
std::basic_ostream<TChar, TCharTraits>& stream,
const print_container_helper<T, TChar, TCharTraits, TDelimiters>& helper)
{
helper(stream);
return stream;
}
// Basic is_container template; specialize to derive from std::true_type for all desired container types
template <typename T>
struct is_container : public std::integral_constant<bool, detail::has_const_iterator<T>::value && detail::has_begin_end<T>::beg_value && detail::has_begin_end<T>::end_value>
{
};
template <typename T, std::size_t N>
struct is_container<T[N]> : std::true_type
{
};
template <std::size_t N>
struct is_container<char[N]> : std::false_type
{
};
template <typename T>
struct is_container<std::valarray<T>> : std::true_type
{
};
template <typename T1, typename T2>
struct is_container<std::pair<T1, T2>> : std::true_type
{
};
template <typename... Args>
struct is_container<std::tuple<Args...>> : std::true_type
{
};
// Default delimiters
template <typename T>
struct delimiters<T, char>
{
static const delimiters_values<char> values;
};
template <typename T>
const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
template <typename T>
struct delimiters<T, wchar_t>
{
static const delimiters_values<wchar_t> values;
};
template <typename T>
const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
// Delimiters for (multi)set and unordered_(multi)set
template <typename T, typename TComp, typename TAllocator>
struct delimiters<::std::set<T, TComp, TAllocator>, char>
{
static const delimiters_values<char> values;
};
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters<::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters<::std::set<T, TComp, TAllocator>, wchar_t>
{
static const delimiters_values<wchar_t> values;
};
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters<::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters<::std::multiset<T, TComp, TAllocator>, char>
{
static const delimiters_values<char> values;
};
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters<::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters<::std::multiset<T, TComp, TAllocator>, wchar_t>
{
static const delimiters_values<wchar_t> values;
};
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters<::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters<::std::unordered_set<T, THash, TEqual, TAllocator>, char>
{
static const delimiters_values<char> values;
};
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters<::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters<::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>
{
static const delimiters_values<wchar_t> values;
};
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters<::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters<::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>
{
static const delimiters_values<char> values;
};
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters<::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters<::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>
{
static const delimiters_values<wchar_t> values;
};
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters<::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
// Delimiters for pair and tuple
template <typename T1, typename T2>
struct delimiters<std::pair<T1, T2>, char>
{
static const delimiters_values<char> values;
};
template <typename T1, typename T2>
const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
template <typename T1, typename T2>
struct delimiters<::std::pair<T1, T2>, wchar_t>
{
static const delimiters_values<wchar_t> values;
};
template <typename T1, typename T2>
const delimiters_values<wchar_t> delimiters<::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
template <typename... Args>
struct delimiters<std::tuple<Args...>, char>
{
static const delimiters_values<char> values;
};
template <typename... Args>
const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };
template <typename... Args>
struct delimiters<::std::tuple<Args...>, wchar_t>
{
static const delimiters_values<wchar_t> values;
};
template <typename... Args>
const delimiters_values<wchar_t> delimiters<::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };
// Type-erasing helper class for easy use of custom delimiters.
// Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
// Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
struct custom_delims_base
{
virtual ~custom_delims_base() {}
virtual std::ostream& stream(::std::ostream&) = 0;
virtual std::wostream& stream(::std::wostream&) = 0;
};
template <typename T, typename Delims>
struct custom_delims_wrapper : custom_delims_base
{
custom_delims_wrapper(const T& t_)
: t(t_) {}
std::ostream& stream(std::ostream& s)
{
custom_delims_wrapper(const T & t_) : t(t_) { }
std::ostream & stream(std::ostream & s)
{
return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t);
}
std::wostream & stream(std::wostream & s)
{
return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t);
}
private:
const T & t;
};
template <typename Delims>
struct custom_delims
{
template <typename Container>
custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
std::unique_ptr<custom_delims_base> base;
};
template <typename TChar, typename TCharTraits, typename Delims>
inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p)
{
return p.base->stream(s);
return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t);
}
// A wrapper for a C-style array given as pointer-plus-size.
// Usage: std::cout << pretty_print_array(arr, n) << std::endl;
template<typename T>
struct array_wrapper_n
std::wostream& stream(std::wostream& s)
{
typedef const T * const_iterator;
typedef T value_type;
return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t);
}
array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { }
inline const_iterator begin() const { return _array; }
inline const_iterator end() const { return _array + _n; }
private:
const T& t;
};
private:
const T * const _array;
size_t _n;
};
// A wrapper for hash-table based containers that offer local iterators to each bucket.
// Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.)
template <typename T>
struct bucket_print_wrapper
template <typename Delims>
struct custom_delims
{
template <typename Container>
custom_delims(const Container& c)
: base(new custom_delims_wrapper<Container, Delims>(c))
{
typedef typename T::const_local_iterator const_iterator;
typedef typename T::size_type size_type;
}
const_iterator begin() const
{
return m_map.cbegin(n);
}
std::unique_ptr<custom_delims_base> base;
};
const_iterator end() const
{
return m_map.cend(n);
}
template <typename TChar, typename TCharTraits, typename Delims>
inline std::basic_ostream<TChar, TCharTraits>& operator<<(std::basic_ostream<TChar, TCharTraits>& s, const custom_delims<Delims>& p)
{
return p.base->stream(s);
}
bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { }
// A wrapper for a C-style array given as pointer-plus-size.
// Usage: std::cout << pretty_print_array(arr, n) << std::endl;
private:
const T & m_map;
const size_type n;
};
template <typename T>
struct array_wrapper_n
{
typedef const T* const_iterator;
typedef T value_type;
} // namespace pretty_print
array_wrapper_n(const T* const a, size_t n)
: _array(a), _n(n) {}
inline const_iterator begin() const { return _array; }
inline const_iterator end() const { return _array + _n; }
private:
const T* const _array;
size_t _n;
};
// A wrapper for hash-table based containers that offer local iterators to each bucket.
// Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.)
template <typename T>
struct bucket_print_wrapper
{
typedef typename T::const_local_iterator const_iterator;
typedef typename T::size_type size_type;
const_iterator begin() const
{
return m_map.cbegin(n);
}
const_iterator end() const
{
return m_map.cend(n);
}
bucket_print_wrapper(const T& m, size_type bucket)
: m_map(m), n(bucket) {}
private:
const T& m_map;
const size_type n;
};
} // namespace pretty_print
// Global accessor functions for the convenience wrappers
template<typename T>
inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
template <typename T>
inline pretty_print::array_wrapper_n<T> pretty_print_array(const T* const a, size_t n)
{
return pretty_print::array_wrapper_n<T>(a, n);
}
template <typename T> pretty_print::bucket_print_wrapper<T>
bucket_print(const T & m, typename T::size_type n)
template <typename T>
pretty_print::bucket_print_wrapper<T>
bucket_print(const T& m, typename T::size_type n)
{
return pretty_print::bucket_print_wrapper<T>(m, n);
}
// Main magic entry point: An overload snuck into namespace std.
// Can we do better?
namespace std
{
// Prints a container to the stream using default delimiters
// Prints a container to the stream using default delimiters
template<typename T, typename TChar, typename TCharTraits>
inline typename enable_if< ::pretty_print::is_container<T>::value,
basic_ostream<TChar, TCharTraits> &>::type
operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container)
{
return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
}
template <typename T, typename TChar, typename TCharTraits>
inline typename enable_if<::pretty_print::is_container<T>::value,
basic_ostream<TChar, TCharTraits>&>::type
operator<<(basic_ostream<TChar, TCharTraits>& stream, const T& container)
{
return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
}
}
#endif // H_PRETTY_PRINT
#endif // H_PRETTY_PRINT

Просмотреть файл

@ -4,7 +4,7 @@
#ifndef commn_utils_sincos_hpp
#define commn_utils_sincos_hpp
#include<cmath>
#include <cmath>
/*
GCC seem to define sincos already. However there is a bug currently which causes compiler to optimise
@ -14,22 +14,23 @@ http://man7.org/linux/man-pages/man3/sincos.3.html
https://android.googlesource.com/platform/bionic/+/master/libm/sincos.c
*/
#ifdef _MSC_VER //GNU/Linux compilers have these functions
//inline here is forced and is hack. Ideally these definitions needs to be in cpp file. http://stackoverflow.com/a/6469881/207661
inline void sincos(double x, double* p_sin, double* p_cos) {
*p_sin = sin(x);
*p_cos = cos(x);
inline void sincos(double x, double* p_sin, double* p_cos)
{
*p_sin = sin(x);
*p_cos = cos(x);
}
inline void sincosf(float x, float* p_sinf, float* p_cosf) {
*p_sinf = sinf(x);
*p_cosf = cosf(x);
inline void sincosf(float x, float* p_sinf, float* p_cosf)
{
*p_sinf = sinf(x);
*p_cosf = cosf(x);
}
inline void sincosl(long double x, long double* p_sinl, long double* p_cosl) {
*p_sinl = sinl(x);
*p_cosl = cosl(x);
inline void sincosl(long double x, long double* p_sinl, long double* p_cosl)
{
*p_sinl = sinl(x);
*p_cosl = cosl(x);
}
#endif
#endif

Просмотреть файл

@ -7,9 +7,12 @@
#include <type_traits>
#include <valarray>
namespace common_utils { namespace type_utils {
//from: https://raw.githubusercontent.com/louisdx/cxx-prettyprint/master/prettyprint.hpp
//also see https://gist.github.com/louisdx/1076849
namespace common_utils
{
namespace type_utils
{
//from: https://raw.githubusercontent.com/louisdx/cxx-prettyprint/master/prettyprint.hpp
//also see https://gist.github.com/louisdx/1076849
namespace detail
{
// SFINAE type trait to detect whether T::const_iterator exists.
@ -17,18 +20,21 @@ namespace common_utils { namespace type_utils {
struct sfinae_base
{
using yes = char;
using no = yes[2];
using no = yes[2];
};
template <typename T>
struct has_const_iterator : private sfinae_base
{
private:
template <typename C> static yes & test(typename C::const_iterator*);
template <typename C> static no & test(...);
template <typename C>
static yes& test(typename C::const_iterator*);
template <typename C>
static no& test(...);
public:
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
using type = T;
using type = T;
void dummy(); //for GCC to suppress -Wctor-dtor-privacy
};
@ -38,20 +44,23 @@ namespace common_utils { namespace type_utils {
{
private:
template <typename C>
static yes & f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
typename C::const_iterator(C::*)() const>::value>::type *);
static yes& f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)),
typename C::const_iterator (C::*)() const>::value>::type*);
template <typename C> static no & f(...);
template <typename C>
static no& f(...);
// using template parameter symbol 'D' instead of 'C' as a workaround for
// VS2017 compiler issue (internal compiler error) starting 15.9.X releases.
template <typename D>
static yes & g(typename std::enable_if<
std::is_same<decltype(static_cast<typename D::const_iterator(D::*)() const>(&D::end)),
typename D::const_iterator(D::*)() const>::value, void>::type*);
static yes& g(typename std::enable_if<
std::is_same<decltype(static_cast<typename D::const_iterator (D::*)() const>(&D::end)),
typename D::const_iterator (D::*)() const>::value,
void>::type*);
template <typename D> static no & g(...);
template <typename D>
static no& g(...);
public:
static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
@ -60,30 +69,39 @@ namespace common_utils { namespace type_utils {
void dummy(); //for GCC to suppress -Wctor-dtor-privacy
};
} // namespace detail
} // namespace detail
// Basic is_container template; specialize to derive from std::true_type for all desired container types
template <typename T>
struct is_container : public std::integral_constant<bool,
detail::has_const_iterator<T>::value &&
detail::has_begin_end<T>::beg_value &&
detail::has_begin_end<T>::end_value> { };
struct is_container : public std::integral_constant<bool, detail::has_const_iterator<T>::value && detail::has_begin_end<T>::beg_value && detail::has_begin_end<T>::end_value>
{
};
template <typename T, std::size_t N>
struct is_container<T[N]> : std::true_type { };
struct is_container<T[N]> : std::true_type
{
};
template <std::size_t N>
struct is_container<char[N]> : std::false_type { };
struct is_container<char[N]> : std::false_type
{
};
template <typename T>
struct is_container<std::valarray<T>> : std::true_type { };
struct is_container<std::valarray<T>> : std::true_type
{
};
template <typename T1, typename T2>
struct is_container<std::pair<T1, T2>> : std::true_type { };
struct is_container<std::pair<T1, T2>> : std::true_type
{
};
template <typename ...Args>
struct is_container<std::tuple<Args...>> : std::true_type { };
}} //namespace
template <typename... Args>
struct is_container<std::tuple<Args...>> : std::true_type
{
};
}
} //namespace
#endif

Просмотреть файл

@ -8,154 +8,158 @@
#include <exception>
#include <iostream>
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class DebugPhysicsBody : public PhysicsBody
{
private:
class WrenchVertex : public PhysicsBodyVertex
{
public:
WrenchVertex(const Vector3r& position, const Vector3r& normal, const Vector3r& force = Vector3r::Zero())
: PhysicsBodyVertex(position, normal), force_(force)
{
}
protected:
virtual void setWrench(Wrench& wrench) override
{
wrench.force = force_;
}
private:
Vector3r force_;
};
class DebugPhysicsBody : public PhysicsBody {
private:
class WrenchVertex : public PhysicsBodyVertex {
public:
WrenchVertex(const Vector3r& position, const Vector3r& normal, const Vector3r& force = Vector3r::Zero())
: PhysicsBodyVertex(position, normal), force_(force)
void initialize(Kinematics* kinematics, Environment* environment)
{
computeInertiaMatrix(inertia_, mass_, body_box_);
createWrenchVertices(wrench_vertices_, body_box_.x(), body_box_.y(), body_box_.z(), mass_);
createDragVertices(drag_vertices_, 1.3f, body_box_.x(), body_box_.y(), body_box_.z());
PhysicsBody::initialize(mass_, inertia_, kinematics, environment);
}
protected:
virtual void setWrench(Wrench& wrench) override
virtual void updateKinematics(const Kinematics::State& kinematics) override
{
wrench.force = force_;
PhysicsBody::updateKinematics(kinematics);
std::cout << " Pos: " << VectorMath::toString(kinematics.pose.position);
std::cout << " Ori: " << VectorMath::toString(kinematics.pose.orientation) << std::endl;
std::cout << " Lin Vel: " << VectorMath::toString(kinematics.twist.linear);
std::cout << " Ang Vel: " << VectorMath::toString(kinematics.twist.angular) << std::endl;
std::cout << " ------------------------------------------------" << std::endl;
}
virtual void updateKinematics() override
{
PhysicsBody::updateKinematics();
}
virtual real_T getRestitution() const override
{
return restitution_;
}
virtual real_T getFriction() const override
{
return friction_;
}
virtual uint wrenchVertexCount() const override
{
return static_cast<uint>(wrench_vertices_.size());
}
virtual PhysicsBodyVertex& getWrenchVertex(uint index) override
{
return wrench_vertices_.at(index);
}
virtual const PhysicsBodyVertex& getWrenchVertex(uint index) const override
{
return wrench_vertices_.at(index);
}
virtual uint dragVertexCount() const override
{
return static_cast<uint>(drag_vertices_.size());
}
virtual PhysicsBodyVertex& getDragVertex(uint index) override
{
return drag_vertices_.at(index);
}
virtual const PhysicsBodyVertex& getDragVertex(uint index) const override
{
return drag_vertices_.at(index);
}
Vector3r getShapeVertex(uint index) const
{
real_T x = (index & 1) == 0 ? body_box_.x() / 2 : -body_box_.x() / 2;
real_T y = (index & 2) == 0 ? body_box_.y() / 2 : -body_box_.y() / 2;
real_T z = (index & 4) == 0 ? body_box_.z() / 2 : -body_box_.z() / 2;
return Vector3r(x, y, z);
}
uint shapeVertexCount()
{
return 8; //for box
}
private:
Vector3r force_;
static void createDragVertices(vector<PhysicsBodyVertex>& drag_vertices, real_T drag_coefficient, real_T body_x, real_T body_y, real_T body_z)
{
real_T top_bottom_area = body_x * body_y;
real_T left_right_area = body_x * body_z;
real_T front_back_area = body_y * body_z;
Vector3r drag_factor_unit = Vector3r(front_back_area, left_right_area, top_bottom_area) * drag_coefficient / 2; //Vector3r drag_factor_unit = Vector3r::Zero();
//add six drag vertices representing 6 sides
drag_vertices.clear();
drag_vertices.emplace_back(Vector3r(0, 0, -body_z), Vector3r(0, 0, -1), drag_factor_unit.z());
drag_vertices.emplace_back(Vector3r(0, 0, body_z), Vector3r(0, 0, 1), drag_factor_unit.z());
drag_vertices.emplace_back(Vector3r(0, -body_y, 0), Vector3r(0, -1, 0), drag_factor_unit.y());
drag_vertices.emplace_back(Vector3r(0, body_y, 0), Vector3r(0, 1, 0), drag_factor_unit.y());
drag_vertices.emplace_back(Vector3r(-body_x, 0, 0), Vector3r(-1, 0, 0), drag_factor_unit.x());
drag_vertices.emplace_back(Vector3r(body_x, 0, 0), Vector3r(1, 0, 0), drag_factor_unit.x());
}
static void createWrenchVertices(vector<WrenchVertex>& wrench_vertices, real_T body_x, real_T body_y, real_T body_z, real_T mass)
{
wrench_vertices.clear();
wrench_vertices.emplace_back(Vector3r(0, 0, -body_z), Vector3r(0, 0, -1), Vector3r(0, 0, -18 * mass));
wrench_vertices.emplace_back(Vector3r(0, 0, body_z), Vector3r(0, 0, 1));
wrench_vertices.emplace_back(Vector3r(0, -body_y, 0), Vector3r(0, -1, 0));
wrench_vertices.emplace_back(Vector3r(0, body_y, 0), Vector3r(0, 1, 0));
wrench_vertices.emplace_back(Vector3r(-body_x, 0, 0), Vector3r(-1, 0, 0));
wrench_vertices.emplace_back(Vector3r(body_x, 0, 0), Vector3r(1, 0, 0));
}
//TODO: put in common place?
static void computeInertiaMatrix(Matrix3x3r& inertia, real_T box_mass, const Vector3r& body_box)
{
inertia = Matrix3x3r::Zero();
//http://farside.ph.utexas.edu/teaching/336k/Newtonhtml/node64.html
inertia(0, 0) = box_mass / 12.0f * (body_box.y() * body_box.y() + body_box.z() * body_box.z());
inertia(1, 1) = box_mass / 12.0f * (body_box.x() * body_box.x() + body_box.z() * body_box.z());
inertia(2, 2) = box_mass / 12.0f * (body_box.x() * body_box.x() + body_box.y() * body_box.y());
}
private:
Vector3r body_box_ = Vector3r(0.20f, 0.12f, 0.04f);
real_T mass_ = 1.0f;
real_T restitution_ = 0.5f;
real_T friction_ = 0.7f;
Matrix3x3r inertia_;
vector<PhysicsBodyVertex> drag_vertices_;
vector<WrenchVertex> wrench_vertices_;
};
public:
void initialize(Kinematics* kinematics, Environment* environment)
{
computeInertiaMatrix(inertia_, mass_, body_box_);
createWrenchVertices(wrench_vertices_, body_box_.x(), body_box_.y(), body_box_.z(), mass_);
createDragVertices(drag_vertices_, 1.3f, body_box_.x(), body_box_.y(), body_box_.z());
PhysicsBody::initialize(mass_, inertia_, kinematics, environment);
}
virtual void updateKinematics(const Kinematics::State& kinematics) override
{
PhysicsBody::updateKinematics(kinematics);
std::cout << " Pos: " << VectorMath::toString(kinematics.pose.position);
std::cout << " Ori: " << VectorMath::toString(kinematics.pose.orientation) << std::endl;
std::cout << " Lin Vel: " << VectorMath::toString(kinematics.twist.linear);
std::cout << " Ang Vel: " << VectorMath::toString(kinematics.twist.angular) << std::endl;
std::cout << " ------------------------------------------------" << std::endl;
}
virtual void updateKinematics() override
{
PhysicsBody::updateKinematics();
}
virtual real_T getRestitution() const override
{
return restitution_;
}
virtual real_T getFriction() const override
{
return friction_;
}
virtual uint wrenchVertexCount() const override
{
return static_cast<uint>(wrench_vertices_.size());
}
virtual PhysicsBodyVertex& getWrenchVertex(uint index) override
{
return wrench_vertices_.at(index);
}
virtual const PhysicsBodyVertex& getWrenchVertex(uint index) const override
{
return wrench_vertices_.at(index);
}
virtual uint dragVertexCount() const override
{
return static_cast<uint>(drag_vertices_.size());
}
virtual PhysicsBodyVertex& getDragVertex(uint index) override
{
return drag_vertices_.at(index);
}
virtual const PhysicsBodyVertex& getDragVertex(uint index) const override
{
return drag_vertices_.at(index);
}
Vector3r getShapeVertex(uint index) const
{
real_T x = (index & 1) == 0 ? body_box_.x() / 2 : - body_box_.x() / 2;
real_T y = (index & 2) == 0 ? body_box_.y() / 2 : - body_box_.y() / 2;
real_T z = (index & 4) == 0 ? body_box_.z() / 2 : - body_box_.z() / 2;
return Vector3r(x, y, z);
}
uint shapeVertexCount()
{
return 8; //for box
}
private:
static void createDragVertices(vector<PhysicsBodyVertex>& drag_vertices, real_T drag_coefficient, real_T body_x, real_T body_y, real_T body_z)
{
real_T top_bottom_area = body_x * body_y;
real_T left_right_area = body_x * body_z;
real_T front_back_area = body_y * body_z;
Vector3r drag_factor_unit = Vector3r(front_back_area, left_right_area, top_bottom_area) * drag_coefficient / 2; //Vector3r drag_factor_unit = Vector3r::Zero();
//add six drag vertices representing 6 sides
drag_vertices.clear();
drag_vertices.emplace_back(Vector3r(0, 0, -body_z), Vector3r(0, 0, -1), drag_factor_unit.z());
drag_vertices.emplace_back(Vector3r(0, 0, body_z), Vector3r(0, 0, 1), drag_factor_unit.z());
drag_vertices.emplace_back(Vector3r(0, -body_y, 0), Vector3r(0, -1, 0), drag_factor_unit.y());
drag_vertices.emplace_back(Vector3r(0, body_y, 0), Vector3r(0, 1, 0), drag_factor_unit.y());
drag_vertices.emplace_back(Vector3r(-body_x, 0, 0), Vector3r(-1, 0, 0), drag_factor_unit.x());
drag_vertices.emplace_back(Vector3r( body_x, 0, 0), Vector3r( 1, 0, 0), drag_factor_unit.x());
}
static void createWrenchVertices(vector<WrenchVertex>& wrench_vertices, real_T body_x, real_T body_y, real_T body_z, real_T mass)
{
wrench_vertices.clear();
wrench_vertices.emplace_back(Vector3r(0, 0, -body_z), Vector3r(0, 0, -1), Vector3r(0, 0, -18 * mass));
wrench_vertices.emplace_back(Vector3r(0, 0, body_z), Vector3r(0, 0, 1));
wrench_vertices.emplace_back(Vector3r(0, -body_y, 0), Vector3r(0, -1, 0));
wrench_vertices.emplace_back(Vector3r(0, body_y, 0), Vector3r(0, 1, 0));
wrench_vertices.emplace_back(Vector3r(-body_x, 0, 0), Vector3r(-1, 0, 0));
wrench_vertices.emplace_back(Vector3r( body_x, 0, 0), Vector3r( 1, 0, 0));
}
//TODO: put in common place?
static void computeInertiaMatrix(Matrix3x3r& inertia, real_T box_mass, const Vector3r& body_box)
{
inertia = Matrix3x3r::Zero();
//http://farside.ph.utexas.edu/teaching/336k/Newtonhtml/node64.html
inertia(0, 0) = box_mass / 12.0f * (body_box.y()*body_box.y() + body_box.z()*body_box.z());
inertia(1, 1) = box_mass / 12.0f * (body_box.x()*body_box.x() + body_box.z()*body_box.z());
inertia(2, 2) = box_mass / 12.0f * (body_box.x()*body_box.x() + body_box.y()*body_box.y());
}
private:
Vector3r body_box_ = Vector3r(0.20f, 0.12f, 0.04f);
real_T mass_ = 1.0f;
real_T restitution_ = 0.5f;
real_T friction_ = 0.7f;
Matrix3x3r inertia_;
vector<PhysicsBodyVertex> drag_vertices_;
vector<WrenchVertex> wrench_vertices_;
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -9,113 +9,120 @@
#include "common/CommonStructs.hpp"
#include "common/EarthUtils.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class Environment : public UpdatableObject {
public:
struct State {
//these fields must be set at initialization time
Vector3r position;
GeoPoint geo_point;
//these fields are computed
Vector3r gravity;
real_T air_pressure;
real_T temperature;
real_T air_density;
State()
{}
State(const Vector3r& position_val, const GeoPoint& geo_point_val)
: position(position_val), geo_point(geo_point_val)
class Environment : public UpdatableObject
{
public:
struct State
{
//these fields must be set at initialization time
Vector3r position;
GeoPoint geo_point;
//these fields are computed
Vector3r gravity;
real_T air_pressure;
real_T temperature;
real_T air_density;
State()
{
}
State(const Vector3r& position_val, const GeoPoint& geo_point_val)
: position(position_val), geo_point(geo_point_val)
{
}
};
public:
Environment()
{
//allow default constructor with later call for initialize
}
Environment(const State& initial)
{
initialize(initial);
}
void initialize(const State& initial)
{
initial_ = initial;
setHomeGeoPoint(initial_.geo_point);
updateState(initial_, home_geo_point_);
}
void setHomeGeoPoint(const GeoPoint& home_geo_point)
{
home_geo_point_ = HomeGeoPoint(home_geo_point);
}
GeoPoint getHomeGeoPoint() const
{
return home_geo_point_.home_geo_point;
}
//in local NED coordinates
void setPosition(const Vector3r& position)
{
current_.position = position;
}
const State& getInitialState() const
{
return initial_;
}
const State& getState() const
{
return current_;
}
State& getState()
{
return current_;
}
virtual void update() override
{
updateState(current_, home_geo_point_);
}
protected:
virtual void resetImplementation() override
{
current_ = initial_;
}
virtual void failResetUpdateOrdering(std::string err) override
{
unused(err);
//Do nothing.
//The environment gets reset() twice without an update() inbetween,
//via MultirotorPawnSimApi::reset() and CarSimApi::reset(), because
//those functions directly reset an environment, and also call other reset()s that reset the same environment.
}
private:
static void updateState(State& state, const HomeGeoPoint& home_geo_point)
{
state.geo_point = EarthUtils::nedToGeodetic(state.position, home_geo_point);
real_T geo_pot = EarthUtils::getGeopotential(state.geo_point.altitude / 1000.0f);
state.temperature = EarthUtils::getStandardTemperature(geo_pot);
state.air_pressure = EarthUtils::getStandardPressure(geo_pot, state.temperature);
state.air_density = EarthUtils::getAirDensity(state.air_pressure, state.temperature);
//TODO: avoid recalculating square roots
state.gravity = Vector3r(0, 0, EarthUtils::getGravity(state.geo_point.altitude));
}
private:
State initial_, current_;
HomeGeoPoint home_geo_point_;
};
public:
Environment()
{
//allow default constructor with later call for initialize
}
Environment(const State& initial)
{
initialize(initial);
}
void initialize(const State& initial)
{
initial_ = initial;
setHomeGeoPoint(initial_.geo_point);
updateState(initial_, home_geo_point_);
}
void setHomeGeoPoint(const GeoPoint& home_geo_point)
{
home_geo_point_ = HomeGeoPoint(home_geo_point);
}
GeoPoint getHomeGeoPoint() const
{
return home_geo_point_.home_geo_point;
}
//in local NED coordinates
void setPosition(const Vector3r& position)
{
current_.position = position;
}
const State& getInitialState() const
{
return initial_;
}
const State& getState() const
{
return current_;
}
State& getState()
{
return current_;
}
virtual void update() override
{
updateState(current_, home_geo_point_);
}
protected:
virtual void resetImplementation() override
{
current_ = initial_;
}
virtual void failResetUpdateOrdering(std::string err) override
{
unused(err);
//Do nothing.
//The environment gets reset() twice without an update() inbetween,
//via MultirotorPawnSimApi::reset() and CarSimApi::reset(), because
//those functions directly reset an environment, and also call other reset()s that reset the same environment.
}
private:
static void updateState(State& state, const HomeGeoPoint& home_geo_point)
{
state.geo_point = EarthUtils::nedToGeodetic(state.position, home_geo_point);
real_T geo_pot = EarthUtils::getGeopotential(state.geo_point.altitude / 1000.0f);
state.temperature = EarthUtils::getStandardTemperature(geo_pot);
state.air_pressure = EarthUtils::getStandardPressure(geo_pot, state.temperature);
state.air_density = EarthUtils::getAirDensity(state.air_pressure, state.temperature);
//TODO: avoid recalculating square roots
state.gravity = Vector3r(0, 0, EarthUtils::getGravity(state.geo_point.altitude));
}
private:
State initial_, current_;
HomeGeoPoint home_geo_point_;
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -14,45 +14,43 @@
#include "common/SteppableClock.hpp"
#include <cinttypes>
namespace msr
{
namespace airlib
namespace msr
{
namespace airlib
{
class ExternalPhysicsEngine : public PhysicsEngineBase {
public:
ExternalPhysicsEngine()
{
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
class ExternalPhysicsEngine : public PhysicsEngineBase
{
}
virtual void update() override
{
PhysicsEngineBase::update();
for (PhysicsBody* body_ptr : *this) {
body_ptr->updateKinematics();
body_ptr->update();
public:
ExternalPhysicsEngine()
{
}
}
virtual void reportState(StateReporter& reporter) override
{
for (PhysicsBody* body_ptr : *this) {
reporter.writeValue("ExternalPhysicsEngine",true);
reporter.writeValue("Is Grounded", body_ptr->isGrounded());
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
}
//call base
UpdatableObject::reportState(reporter);
}
//*** End: UpdatableState implementation ***//
};
virtual void update() override
{
PhysicsEngineBase::update();
for (PhysicsBody* body_ptr : *this) {
body_ptr->updateKinematics();
body_ptr->update();
}
}
virtual void reportState(StateReporter& reporter) override
{
for (PhysicsBody* body_ptr : *this) {
reporter.writeValue("ExternalPhysicsEngine", true);
reporter.writeValue("Is Grounded", body_ptr->isGrounded());
}
//call base
UpdatableObject::reportState(reporter);
}
//*** End: UpdatableState implementation ***//
};
} //namespace
} //namespace

Просмотреть файл

@ -14,173 +14,172 @@
#include "common/SteppableClock.hpp"
#include <cinttypes>
namespace msr { namespace airlib {
class FastPhysicsEngine : public PhysicsEngineBase
namespace msr
{
namespace airlib
{
public:
FastPhysicsEngine(bool enable_ground_lock = true, Vector3r wind = Vector3r::Zero())
: enable_ground_lock_(enable_ground_lock), wind_(wind)
{
setName("FastPhysicsEngine");
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
class FastPhysicsEngine : public PhysicsEngineBase
{
for (PhysicsBody* body_ptr : *this) {
public:
FastPhysicsEngine(bool enable_ground_lock = true, Vector3r wind = Vector3r::Zero())
: enable_ground_lock_(enable_ground_lock), wind_(wind)
{
setName("FastPhysicsEngine");
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
for (PhysicsBody* body_ptr : *this) {
initPhysicsBody(body_ptr);
}
}
virtual void insert(PhysicsBody* body_ptr) override
{
PhysicsEngineBase::insert(body_ptr);
initPhysicsBody(body_ptr);
}
}
virtual void insert(PhysicsBody* body_ptr) override
{
PhysicsEngineBase::insert(body_ptr);
virtual void update() override
{
PhysicsEngineBase::update();
initPhysicsBody(body_ptr);
}
virtual void update() override
{
PhysicsEngineBase::update();
for (PhysicsBody* body_ptr : *this) {
updatePhysics(*body_ptr);
for (PhysicsBody* body_ptr : *this) {
updatePhysics(*body_ptr);
}
}
}
virtual void reportState(StateReporter& reporter) override
{
for (PhysicsBody* body_ptr : *this) {
reporter.writeValue("Phys", debug_string_.str());
reporter.writeValue("Is Grounded", body_ptr->isGrounded());
reporter.writeValue("Force (world)", body_ptr->getWrench().force);
reporter.writeValue("Torque (body)", body_ptr->getWrench().torque);
virtual void reportState(StateReporter& reporter) override
{
for (PhysicsBody* body_ptr : *this) {
reporter.writeValue("Phys", debug_string_.str());
reporter.writeValue("Is Grounded", body_ptr->isGrounded());
reporter.writeValue("Force (world)", body_ptr->getWrench().force);
reporter.writeValue("Torque (body)", body_ptr->getWrench().torque);
}
//call base
UpdatableObject::reportState(reporter);
}
//call base
UpdatableObject::reportState(reporter);
}
//*** End: UpdatableState implementation ***//
//*** End: UpdatableState implementation ***//
// Set Wind, for API and Settings implementation
void setWind(const Vector3r& wind) override
{
wind_ = wind;
}
private:
void initPhysicsBody(PhysicsBody* body_ptr)
{
body_ptr->last_kinematics_time = clock()->nowNanos();
}
void updatePhysics(PhysicsBody& body)
{
TTimeDelta dt = clock()->updateSince(body.last_kinematics_time);
body.lock();
//get current kinematics state of the body - this state existed since last dt seconds
const Kinematics::State& current = body.getKinematics();
Kinematics::State next;
Wrench next_wrench;
//first compute the response as if there was no collision
//this is necessary to take in to account forces and torques generated by body
getNextKinematicsNoCollision(dt, body, current, next, next_wrench, wind_);
//if there is collision, see if we need collision response
const CollisionInfo collision_info = body.getCollisionInfo();
CollisionResponse& collision_response = body.getCollisionResponseInfo();
//if collision was already responded then do not respond to it until we get updated information
if (body.isGrounded() || (collision_info.has_collided && collision_response.collision_time_stamp != collision_info.time_stamp)) {
bool is_collision_response = getNextKinematicsOnCollision(dt, collision_info, body,
current, next, next_wrench, enable_ground_lock_);
updateCollisionResponseInfo(collision_info, next, is_collision_response, collision_response);
//throttledLogOutput("*** has collision", 0.1);
}
//else throttledLogOutput("*** no collision", 0.1);
//Utils::log(Utils::stringf("T-VEL %s %" PRIu64 ": ",
// VectorMath::toString(next.twist.linear).c_str(), clock()->getStepCount()));
body.setWrench(next_wrench);
body.updateKinematics(next);
body.unlock();
//TODO: this is now being done in PawnSimApi::update. We need to re-think this sequence
//with below commented out - Arducopter GPS may not work.
//body.getEnvironment().setPosition(next.pose.position);
//body.getEnvironment().update();
}
static void updateCollisionResponseInfo(const CollisionInfo& collision_info, const Kinematics::State& next,
bool is_collision_response, CollisionResponse& collision_response)
{
collision_response.collision_time_stamp = collision_info.time_stamp;
++collision_response.collision_count_raw;
//increment counter if we didn't collided with high velocity (like resting on ground)
if (is_collision_response && next.twist.linear.squaredNorm() > kRestingVelocityMax * kRestingVelocityMax)
++collision_response.collision_count_non_resting;
}
//return value indicates if collision response was generated
static bool getNextKinematicsOnCollision(TTimeDelta dt, const CollisionInfo& collision_info, PhysicsBody& body,
const Kinematics::State& current, Kinematics::State& next, Wrench& next_wrench, bool enable_ground_lock)
{
/************************* Collision response ************************/
const real_T dt_real = static_cast<real_T>(dt);
//are we going away from collision? if so then keep using computed next state
if (collision_info.normal.dot(next.twist.linear) >= 0.0f)
return false;
/********** Core collision response ***********/
//get avg current velocity
const Vector3r vcur_avg = current.twist.linear + current.accelerations.linear * dt_real;
//get average angular velocity
const Vector3r angular_avg = current.twist.angular + current.accelerations.angular * dt_real;
//contact point vector
Vector3r r = collision_info.impact_point - collision_info.position;
//see if impact is straight at body's surface (assuming its box)
const Vector3r normal_body = VectorMath::transformToBodyFrame(collision_info.normal, current.pose.orientation);
const bool is_ground_normal = Utils::isApproximatelyEqual(std::abs(normal_body.z()), 1.0f, kAxisTolerance);
bool ground_collision = false;
const float z_vel = vcur_avg.z();
const bool is_landing = z_vel > std::abs(vcur_avg.x()) && z_vel > std::abs(vcur_avg.y());
real_T restitution = body.getRestitution();
real_T friction = body.getFriction();
if (is_ground_normal && is_landing
// So normal_body is the collision normal translated into body coords, why does an x==1 or y==1
// mean we are coliding with the ground???
// || Utils::isApproximatelyEqual(std::abs(normal_body.x()), 1.0f, kAxisTolerance)
// || Utils::isApproximatelyEqual(std::abs(normal_body.y()), 1.0f, kAxisTolerance)
) {
// looks like we are coliding with the ground. We don't want the ground to be so bouncy
// so we reduce the coefficient of restitution. 0 means no bounce.
// TODO: it would be better if we did this based on the material we are landing on.
// e.g. grass should be inelastic, but a hard surface like the road should be more bouncy.
restitution = 0;
// crank up friction with the ground so it doesn't try and slide across the ground
// again, this should depend on the type of surface we are landing on.
friction = 1;
//we have collided with ground straight on, we will fix orientation later
ground_collision = is_ground_normal;
// Set Wind, for API and Settings implementation
void setWind(const Vector3r& wind) override
{
wind_ = wind;
}
//velocity at contact point
const Vector3r vcur_avg_body = VectorMath::transformToBodyFrame(vcur_avg, current.pose.orientation);
const Vector3r contact_vel_body = vcur_avg_body + angular_avg.cross(r);
private:
void initPhysicsBody(PhysicsBody* body_ptr)
{
body_ptr->last_kinematics_time = clock()->nowNanos();
}
/*
void updatePhysics(PhysicsBody& body)
{
TTimeDelta dt = clock()->updateSince(body.last_kinematics_time);
body.lock();
//get current kinematics state of the body - this state existed since last dt seconds
const Kinematics::State& current = body.getKinematics();
Kinematics::State next;
Wrench next_wrench;
//first compute the response as if there was no collision
//this is necessary to take in to account forces and torques generated by body
getNextKinematicsNoCollision(dt, body, current, next, next_wrench, wind_);
//if there is collision, see if we need collision response
const CollisionInfo collision_info = body.getCollisionInfo();
CollisionResponse& collision_response = body.getCollisionResponseInfo();
//if collision was already responded then do not respond to it until we get updated information
if (body.isGrounded() || (collision_info.has_collided && collision_response.collision_time_stamp != collision_info.time_stamp)) {
bool is_collision_response = getNextKinematicsOnCollision(dt, collision_info, body, current, next, next_wrench, enable_ground_lock_);
updateCollisionResponseInfo(collision_info, next, is_collision_response, collision_response);
//throttledLogOutput("*** has collision", 0.1);
}
//else throttledLogOutput("*** no collision", 0.1);
//Utils::log(Utils::stringf("T-VEL %s %" PRIu64 ": ",
// VectorMath::toString(next.twist.linear).c_str(), clock()->getStepCount()));
body.setWrench(next_wrench);
body.updateKinematics(next);
body.unlock();
//TODO: this is now being done in PawnSimApi::update. We need to re-think this sequence
//with below commented out - Arducopter GPS may not work.
//body.getEnvironment().setPosition(next.pose.position);
//body.getEnvironment().update();
}
static void updateCollisionResponseInfo(const CollisionInfo& collision_info, const Kinematics::State& next,
bool is_collision_response, CollisionResponse& collision_response)
{
collision_response.collision_time_stamp = collision_info.time_stamp;
++collision_response.collision_count_raw;
//increment counter if we didn't collided with high velocity (like resting on ground)
if (is_collision_response && next.twist.linear.squaredNorm() > kRestingVelocityMax * kRestingVelocityMax)
++collision_response.collision_count_non_resting;
}
//return value indicates if collision response was generated
static bool getNextKinematicsOnCollision(TTimeDelta dt, const CollisionInfo& collision_info, PhysicsBody& body,
const Kinematics::State& current, Kinematics::State& next, Wrench& next_wrench, bool enable_ground_lock)
{
/************************* Collision response ************************/
const real_T dt_real = static_cast<real_T>(dt);
//are we going away from collision? if so then keep using computed next state
if (collision_info.normal.dot(next.twist.linear) >= 0.0f)
return false;
/********** Core collision response ***********/
//get avg current velocity
const Vector3r vcur_avg = current.twist.linear + current.accelerations.linear * dt_real;
//get average angular velocity
const Vector3r angular_avg = current.twist.angular + current.accelerations.angular * dt_real;
//contact point vector
Vector3r r = collision_info.impact_point - collision_info.position;
//see if impact is straight at body's surface (assuming its box)
const Vector3r normal_body = VectorMath::transformToBodyFrame(collision_info.normal, current.pose.orientation);
const bool is_ground_normal = Utils::isApproximatelyEqual(std::abs(normal_body.z()), 1.0f, kAxisTolerance);
bool ground_collision = false;
const float z_vel = vcur_avg.z();
const bool is_landing = z_vel > std::abs(vcur_avg.x()) && z_vel > std::abs(vcur_avg.y());
real_T restitution = body.getRestitution();
real_T friction = body.getFriction();
if (is_ground_normal && is_landing
// So normal_body is the collision normal translated into body coords, why does an x==1 or y==1
// mean we are coliding with the ground???
// || Utils::isApproximatelyEqual(std::abs(normal_body.x()), 1.0f, kAxisTolerance)
// || Utils::isApproximatelyEqual(std::abs(normal_body.y()), 1.0f, kAxisTolerance)
) {
// looks like we are coliding with the ground. We don't want the ground to be so bouncy
// so we reduce the coefficient of restitution. 0 means no bounce.
// TODO: it would be better if we did this based on the material we are landing on.
// e.g. grass should be inelastic, but a hard surface like the road should be more bouncy.
restitution = 0;
// crank up friction with the ground so it doesn't try and slide across the ground
// again, this should depend on the type of surface we are landing on.
friction = 1;
//we have collided with ground straight on, we will fix orientation later
ground_collision = is_ground_normal;
}
//velocity at contact point
const Vector3r vcur_avg_body = VectorMath::transformToBodyFrame(vcur_avg, current.pose.orientation);
const Vector3r contact_vel_body = vcur_avg_body + angular_avg.cross(r);
/*
GafferOnGames - Collision response with columb friction
http://gafferongames.com/virtual-go/collision-response-and-coulomb-friction/
Assuming collision is with static fixed body,
@ -189,241 +188,240 @@ private:
http://chrishecker.com/images/e/e7/Gdmphys3.pdf
V(t+1) = V(t) + j*N / m
*/
const real_T impulse_mag_denom = 1.0f / body.getMass() +
(body.getInertiaInv() * r.cross(normal_body))
.cross(r)
.dot(normal_body);
const real_T impulse_mag = -contact_vel_body.dot(normal_body) * (1 + restitution) / impulse_mag_denom;
const real_T impulse_mag_denom = 1.0f / body.getMass() +
(body.getInertiaInv() * r.cross(normal_body))
.cross(r)
.dot(normal_body);
const real_T impulse_mag = -contact_vel_body.dot(normal_body) * (1 + restitution) / impulse_mag_denom;
next.twist.linear = vcur_avg + collision_info.normal * (impulse_mag / body.getMass());
next.twist.angular = angular_avg + r.cross(normal_body) * impulse_mag;
next.twist.linear = vcur_avg + collision_info.normal * (impulse_mag / body.getMass());
next.twist.angular = angular_avg + r.cross(normal_body) * impulse_mag;
//above would modify component in direction of normal
//we will use friction to modify component in direction of tangent
const Vector3r contact_tang_body = contact_vel_body - normal_body * normal_body.dot(contact_vel_body);
const Vector3r contact_tang_unit_body = contact_tang_body.normalized();
const real_T friction_mag_denom = 1.0f / body.getMass() +
(body.getInertiaInv() * r.cross(contact_tang_unit_body))
.cross(r)
.dot(contact_tang_unit_body);
const real_T friction_mag = -contact_tang_body.norm() * friction / friction_mag_denom;
//above would modify component in direction of normal
//we will use friction to modify component in direction of tangent
const Vector3r contact_tang_body = contact_vel_body - normal_body * normal_body.dot(contact_vel_body);
const Vector3r contact_tang_unit_body = contact_tang_body.normalized();
const real_T friction_mag_denom = 1.0f / body.getMass() +
(body.getInertiaInv() * r.cross(contact_tang_unit_body))
.cross(r)
.dot(contact_tang_unit_body);
const real_T friction_mag = -contact_tang_body.norm() * friction / friction_mag_denom;
const Vector3r contact_tang_unit = VectorMath::transformToWorldFrame(contact_tang_unit_body, current.pose.orientation);
next.twist.linear += contact_tang_unit * friction_mag;
next.twist.angular += r.cross(contact_tang_unit_body) * (friction_mag / body.getMass());
const Vector3r contact_tang_unit = VectorMath::transformToWorldFrame(contact_tang_unit_body, current.pose.orientation);
next.twist.linear += contact_tang_unit * friction_mag;
next.twist.angular += r.cross(contact_tang_unit_body) * (friction_mag / body.getMass());
//TODO: implement better rolling friction
next.twist.angular *= 0.9f;
//TODO: implement better rolling friction
next.twist.angular *= 0.9f;
// there is no acceleration during collision response, this is a hack, but without it the acceleration cancels
// the computed impulse response too much and stops the vehicle from bouncing off the collided object.
next.accelerations.linear = Vector3r::Zero();
next.accelerations.angular = Vector3r::Zero();
next.pose = current.pose;
if (enable_ground_lock && ground_collision) {
float pitch, roll, yaw;
VectorMath::toEulerianAngle(next.pose.orientation, pitch, roll, yaw);
pitch = roll = 0;
next.pose.orientation = VectorMath::toQuaternion(pitch, roll, yaw);
//there is a lot of random angular velocity when vehicle is on the ground
next.twist.angular = Vector3r::Zero();
// also eliminate any linear velocity due to twist - since we are sitting on the ground there shouldn't be any.
next.twist.linear = Vector3r::Zero();
next.pose.position = collision_info.position;
body.setGrounded(true);
// but we do want to "feel" the ground when we hit it (we should see a small z-acc bump)
// equal and opposite our downward velocity.
next.accelerations.linear = -0.5f * body.getMass() * vcur_avg;
//throttledLogOutput("*** Triggering ground lock", 0.1);
}
else {
//else keep the orientation
next.pose.position = collision_info.position + (collision_info.normal * collision_info.penetration_depth) + next.twist.linear * (dt_real * kCollisionResponseCycles);
}
next_wrench = Wrench::zero();
//Utils::log(Utils::stringf("*** C-VEL %s: ", VectorMath::toString(next.twist.linear).c_str()));
return true;
}
void throttledLogOutput(const std::string& msg, double seconds)
{
TTimeDelta dt = clock()->elapsedSince(last_message_time);
const real_T dt_real = static_cast<real_T>(dt);
if (dt_real > seconds) {
Utils::log(msg);
last_message_time = clock()->nowNanos();
}
}
static Wrench getDragWrench(const PhysicsBody& body, const Quaternionr& orientation,
const Vector3r& linear_vel, const Vector3r& angular_vel_body, const Vector3r& wind_world)
{
//add linear drag due to velocity we had since last dt seconds + wind
//drag vector magnitude is proportional to v^2, direction opposite of velocity
//total drag is b*v + c*v*v but we ignore the first term as b << c (pg 44, Classical Mechanics, John Taylor)
//To find the drag force, we find the magnitude in the body frame and unit vector direction in world frame
//http://physics.stackexchange.com/questions/304742/angular-drag-on-body
//similarly calculate angular drag
//note that angular velocity, acceleration, torque are already in body frame
Wrench wrench = Wrench::zero();
const real_T air_density = body.getEnvironment().getState().air_density;
// Use relative velocity of the body wrt wind
const Vector3r relative_vel = linear_vel - wind_world;
const Vector3r linear_vel_body = VectorMath::transformToBodyFrame(relative_vel, orientation);
for (uint vi = 0; vi < body.dragVertexCount(); ++vi) {
const auto& vertex = body.getDragVertex(vi);
const Vector3r vel_vertex = linear_vel_body + angular_vel_body.cross(vertex.getPosition());
const real_T vel_comp = vertex.getNormal().dot(vel_vertex);
//if vel_comp is -ve then we cull the face. If velocity too low then drag is not generated
if (vel_comp > kDragMinVelocity) {
const Vector3r drag_force = vertex.getNormal() * (- vertex.getDragFactor() * air_density * vel_comp * vel_comp);
const Vector3r drag_torque = vertex.getPosition().cross(drag_force);
wrench.force += drag_force;
wrench.torque += drag_torque;
}
}
//convert force to world frame, leave torque to local frame
wrench.force = VectorMath::transformToWorldFrame(wrench.force, orientation);
return wrench;
}
static Wrench getBodyWrench(const PhysicsBody& body, const Quaternionr& orientation)
{
//set wrench sum to zero
Wrench wrench = Wrench::zero();
//calculate total force on rigid body's center of gravity
for (uint i = 0; i < body.wrenchVertexCount(); ++i) {
//aggregate total
const PhysicsBodyVertex& vertex = body.getWrenchVertex(i);
const auto& vertex_wrench = vertex.getWrench();
wrench += vertex_wrench;
//add additional torque due to force applies farther than COG
// tau = r X F
wrench.torque += vertex.getPosition().cross(vertex_wrench.force);
}
//convert force to world frame, leave torque to local frame
wrench.force = VectorMath::transformToWorldFrame(wrench.force, orientation);
return wrench;
}
static void getNextKinematicsNoCollision(TTimeDelta dt, PhysicsBody& body, const Kinematics::State& current,
Kinematics::State& next, Wrench& next_wrench, const Vector3r& wind)
{
const real_T dt_real = static_cast<real_T>(dt);
Vector3r avg_linear = Vector3r::Zero();
Vector3r avg_angular = Vector3r::Zero();
/************************* Get force and torque acting on body ************************/
//set wrench sum to zero
const Wrench body_wrench = getBodyWrench(body, current.pose.orientation);
if (body.isGrounded()) {
// make it stick to the ground until the magnitude of net external force on body exceeds its weight.
float external_force_magnitude = body_wrench.force.squaredNorm();
Vector3r weight = body.getMass() * body.getEnvironment().getState().gravity;
float weight_magnitude = weight.squaredNorm();
if (external_force_magnitude >= weight_magnitude) {
//throttledLogOutput("*** Losing ground lock due to body_wrench " + VectorMath::toString(body_wrench.force), 0.1);
body.setGrounded(false);
}
next_wrench.force = Vector3r::Zero();
next_wrench.torque = Vector3r::Zero();
// there is no acceleration during collision response, this is a hack, but without it the acceleration cancels
// the computed impulse response too much and stops the vehicle from bouncing off the collided object.
next.accelerations.linear = Vector3r::Zero();
next.accelerations.angular = Vector3r::Zero();
next.pose = current.pose;
if (enable_ground_lock && ground_collision) {
float pitch, roll, yaw;
VectorMath::toEulerianAngle(next.pose.orientation, pitch, roll, yaw);
pitch = roll = 0;
next.pose.orientation = VectorMath::toQuaternion(pitch, roll, yaw);
//there is a lot of random angular velocity when vehicle is on the ground
next.twist.angular = Vector3r::Zero();
// also eliminate any linear velocity due to twist - since we are sitting on the ground there shouldn't be any.
next.twist.linear = Vector3r::Zero();
next.pose.position = collision_info.position;
body.setGrounded(true);
// but we do want to "feel" the ground when we hit it (we should see a small z-acc bump)
// equal and opposite our downward velocity.
next.accelerations.linear = -0.5f * body.getMass() * vcur_avg;
//throttledLogOutput("*** Triggering ground lock", 0.1);
}
else {
//else keep the orientation
next.pose.position = collision_info.position + (collision_info.normal * collision_info.penetration_depth) + next.twist.linear * (dt_real * kCollisionResponseCycles);
}
next_wrench = Wrench::zero();
//Utils::log(Utils::stringf("*** C-VEL %s: ", VectorMath::toString(next.twist.linear).c_str()));
return true;
}
else {
void throttledLogOutput(const std::string& msg, double seconds)
{
TTimeDelta dt = clock()->elapsedSince(last_message_time);
const real_T dt_real = static_cast<real_T>(dt);
if (dt_real > seconds) {
Utils::log(msg);
last_message_time = clock()->nowNanos();
}
}
static Wrench getDragWrench(const PhysicsBody& body, const Quaternionr& orientation,
const Vector3r& linear_vel, const Vector3r& angular_vel_body, const Vector3r& wind_world)
{
//add linear drag due to velocity we had since last dt seconds + wind
//drag vector magnitude is proportional to v^2, direction opposite of velocity
//total drag is b*v + c*v*v but we ignore the first term as b << c (pg 44, Classical Mechanics, John Taylor)
//To find the drag force, we find the magnitude in the body frame and unit vector direction in world frame
avg_linear = current.twist.linear + current.accelerations.linear * (0.5f * dt_real);
avg_angular = current.twist.angular + current.accelerations.angular * (0.5f * dt_real);
const Wrench drag_wrench = getDragWrench(body, current.pose.orientation, avg_linear, avg_angular, wind);
//http://physics.stackexchange.com/questions/304742/angular-drag-on-body
//similarly calculate angular drag
//note that angular velocity, acceleration, torque are already in body frame
next_wrench = body_wrench + drag_wrench;
Wrench wrench = Wrench::zero();
const real_T air_density = body.getEnvironment().getState().air_density;
//Utils::log(Utils::stringf("B-WRN %s: ", VectorMath::toString(body_wrench.force).c_str()));
//Utils::log(Utils::stringf("D-WRN %s: ", VectorMath::toString(drag_wrench.force).c_str()));
// Use relative velocity of the body wrt wind
const Vector3r relative_vel = linear_vel - wind_world;
const Vector3r linear_vel_body = VectorMath::transformToBodyFrame(relative_vel, orientation);
/************************* Update accelerations due to force and torque ************************/
//get new acceleration due to force - we'll use this acceleration in next time step
for (uint vi = 0; vi < body.dragVertexCount(); ++vi) {
const auto& vertex = body.getDragVertex(vi);
const Vector3r vel_vertex = linear_vel_body + angular_vel_body.cross(vertex.getPosition());
const real_T vel_comp = vertex.getNormal().dot(vel_vertex);
//if vel_comp is -ve then we cull the face. If velocity too low then drag is not generated
if (vel_comp > kDragMinVelocity) {
const Vector3r drag_force = vertex.getNormal() * (-vertex.getDragFactor() * air_density * vel_comp * vel_comp);
const Vector3r drag_torque = vertex.getPosition().cross(drag_force);
next.accelerations.linear = (next_wrench.force / body.getMass()) + body.getEnvironment().getState().gravity;
wrench.force += drag_force;
wrench.torque += drag_torque;
}
}
//convert force to world frame, leave torque to local frame
wrench.force = VectorMath::transformToWorldFrame(wrench.force, orientation);
return wrench;
}
static Wrench getBodyWrench(const PhysicsBody& body, const Quaternionr& orientation)
{
//set wrench sum to zero
Wrench wrench = Wrench::zero();
if (body.isGrounded()) {
// this stops vehicle from vibrating while it is on the ground doing nothing.
next.accelerations.angular = Vector3r::Zero();
next.twist.linear = Vector3r::Zero();
next.twist.angular = Vector3r::Zero();
} else {
//get new angular acceleration
//Euler's rotation equation: https://en.wikipedia.org/wiki/Euler's_equations_(body_dynamics)
//we will use torque to find out the angular acceleration
//angular momentum L = I * omega
const Vector3r angular_momentum = body.getInertia() * avg_angular;
const Vector3r angular_momentum_rate = next_wrench.torque - avg_angular.cross(angular_momentum);
//new angular acceleration - we'll use this acceleration in next time step
next.accelerations.angular = body.getInertiaInv() * angular_momentum_rate;
//calculate total force on rigid body's center of gravity
for (uint i = 0; i < body.wrenchVertexCount(); ++i) {
//aggregate total
const PhysicsBodyVertex& vertex = body.getWrenchVertex(i);
const auto& vertex_wrench = vertex.getWrench();
wrench += vertex_wrench;
/************************* Update pose and twist after dt ************************/
//Verlet integration: http://www.physics.udel.edu/~bnikolic/teaching/phys660/numerical_ode/node5.html
next.twist.linear = current.twist.linear + (current.accelerations.linear + next.accelerations.linear) * (0.5f * dt_real);
next.twist.angular = current.twist.angular + (current.accelerations.angular + next.accelerations.angular) * (0.5f * dt_real);
//add additional torque due to force applies farther than COG
// tau = r X F
wrench.torque += vertex.getPosition().cross(vertex_wrench.force);
}
//if controller has bug, velocities can increase idenfinitely
//so we need to clip this or everything will turn in to infinity/nans
//convert force to world frame, leave torque to local frame
wrench.force = VectorMath::transformToWorldFrame(wrench.force, orientation);
if (next.twist.linear.squaredNorm() > EarthUtils::SpeedOfLight * EarthUtils::SpeedOfLight) { //speed of light
next.twist.linear /= (next.twist.linear.norm() / EarthUtils::SpeedOfLight);
return wrench;
}
static void getNextKinematicsNoCollision(TTimeDelta dt, PhysicsBody& body, const Kinematics::State& current,
Kinematics::State& next, Wrench& next_wrench, const Vector3r& wind)
{
const real_T dt_real = static_cast<real_T>(dt);
Vector3r avg_linear = Vector3r::Zero();
Vector3r avg_angular = Vector3r::Zero();
/************************* Get force and torque acting on body ************************/
//set wrench sum to zero
const Wrench body_wrench = getBodyWrench(body, current.pose.orientation);
if (body.isGrounded()) {
// make it stick to the ground until the magnitude of net external force on body exceeds its weight.
float external_force_magnitude = body_wrench.force.squaredNorm();
Vector3r weight = body.getMass() * body.getEnvironment().getState().gravity;
float weight_magnitude = weight.squaredNorm();
if (external_force_magnitude >= weight_magnitude) {
//throttledLogOutput("*** Losing ground lock due to body_wrench " + VectorMath::toString(body_wrench.force), 0.1);
body.setGrounded(false);
}
next_wrench.force = Vector3r::Zero();
next_wrench.torque = Vector3r::Zero();
next.accelerations.linear = Vector3r::Zero();
}
//
//for disc of 1m radius which angular velocity translates to speed of light on tangent?
if (next.twist.angular.squaredNorm() > EarthUtils::SpeedOfLight * EarthUtils::SpeedOfLight) { //speed of light
next.twist.angular /= (next.twist.angular.norm() / EarthUtils::SpeedOfLight);
next.accelerations.angular = Vector3r::Zero();
else {
//add linear drag due to velocity we had since last dt seconds + wind
//drag vector magnitude is proportional to v^2, direction opposite of velocity
//total drag is b*v + c*v*v but we ignore the first term as b << c (pg 44, Classical Mechanics, John Taylor)
//To find the drag force, we find the magnitude in the body frame and unit vector direction in world frame
avg_linear = current.twist.linear + current.accelerations.linear * (0.5f * dt_real);
avg_angular = current.twist.angular + current.accelerations.angular * (0.5f * dt_real);
const Wrench drag_wrench = getDragWrench(body, current.pose.orientation, avg_linear, avg_angular, wind);
next_wrench = body_wrench + drag_wrench;
//Utils::log(Utils::stringf("B-WRN %s: ", VectorMath::toString(body_wrench.force).c_str()));
//Utils::log(Utils::stringf("D-WRN %s: ", VectorMath::toString(drag_wrench.force).c_str()));
/************************* Update accelerations due to force and torque ************************/
//get new acceleration due to force - we'll use this acceleration in next time step
next.accelerations.linear = (next_wrench.force / body.getMass()) + body.getEnvironment().getState().gravity;
}
if (body.isGrounded()) {
// this stops vehicle from vibrating while it is on the ground doing nothing.
next.accelerations.angular = Vector3r::Zero();
next.twist.linear = Vector3r::Zero();
next.twist.angular = Vector3r::Zero();
}
else {
//get new angular acceleration
//Euler's rotation equation: https://en.wikipedia.org/wiki/Euler's_equations_(body_dynamics)
//we will use torque to find out the angular acceleration
//angular momentum L = I * omega
const Vector3r angular_momentum = body.getInertia() * avg_angular;
const Vector3r angular_momentum_rate = next_wrench.torque - avg_angular.cross(angular_momentum);
//new angular acceleration - we'll use this acceleration in next time step
next.accelerations.angular = body.getInertiaInv() * angular_momentum_rate;
/************************* Update pose and twist after dt ************************/
//Verlet integration: http://www.physics.udel.edu/~bnikolic/teaching/phys660/numerical_ode/node5.html
next.twist.linear = current.twist.linear + (current.accelerations.linear + next.accelerations.linear) * (0.5f * dt_real);
next.twist.angular = current.twist.angular + (current.accelerations.angular + next.accelerations.angular) * (0.5f * dt_real);
//if controller has bug, velocities can increase idenfinitely
//so we need to clip this or everything will turn in to infinity/nans
if (next.twist.linear.squaredNorm() > EarthUtils::SpeedOfLight * EarthUtils::SpeedOfLight) { //speed of light
next.twist.linear /= (next.twist.linear.norm() / EarthUtils::SpeedOfLight);
next.accelerations.linear = Vector3r::Zero();
}
//
//for disc of 1m radius which angular velocity translates to speed of light on tangent?
if (next.twist.angular.squaredNorm() > EarthUtils::SpeedOfLight * EarthUtils::SpeedOfLight) { //speed of light
next.twist.angular /= (next.twist.angular.norm() / EarthUtils::SpeedOfLight);
next.accelerations.angular = Vector3r::Zero();
}
}
computeNextPose(dt, current.pose, avg_linear, avg_angular, next);
//Utils::log(Utils::stringf("N-VEL %s %f: ", VectorMath::toString(next.twist.linear).c_str(), dt));
//Utils::log(Utils::stringf("N-POS %s %f: ", VectorMath::toString(next.pose.position).c_str(), dt));
}
computeNextPose(dt, current.pose, avg_linear, avg_angular, next);
static void computeNextPose(TTimeDelta dt, const Pose& current_pose, const Vector3r& avg_linear, const Vector3r& avg_angular, Kinematics::State& next)
{
real_T dt_real = static_cast<real_T>(dt);
//Utils::log(Utils::stringf("N-VEL %s %f: ", VectorMath::toString(next.twist.linear).c_str(), dt));
//Utils::log(Utils::stringf("N-POS %s %f: ", VectorMath::toString(next.pose.position).c_str(), dt));
next.pose.position = current_pose.position + avg_linear * dt_real;
}
static void computeNextPose(TTimeDelta dt, const Pose& current_pose, const Vector3r& avg_linear, const Vector3r& avg_angular, Kinematics::State& next)
{
real_T dt_real = static_cast<real_T>(dt);
next.pose.position = current_pose.position + avg_linear * dt_real;
//use angular velocty in body frame to calculate angular displacement in last dt seconds
real_T angle_per_unit = avg_angular.norm();
if (Utils::isDefinitelyGreaterThan(angle_per_unit, 0.0f)) {
//convert change in angle to unit quaternion
AngleAxisr angle_dt_aa = AngleAxisr(angle_per_unit * dt_real, avg_angular / angle_per_unit);
Quaternionr angle_dt_q = Quaternionr(angle_dt_aa);
/*
//use angular velocty in body frame to calculate angular displacement in last dt seconds
real_T angle_per_unit = avg_angular.norm();
if (Utils::isDefinitelyGreaterThan(angle_per_unit, 0.0f)) {
//convert change in angle to unit quaternion
AngleAxisr angle_dt_aa = AngleAxisr(angle_per_unit * dt_real, avg_angular / angle_per_unit);
Quaternionr angle_dt_q = Quaternionr(angle_dt_aa);
/*
Add change in angle to previous orientation.
Proof that this is q0 * q1:
If rotated vector is qx*v*qx' then qx is attitude
@ -438,30 +436,30 @@ private:
q0(q1(v)q1')q0'
Thus new attitude is q0q1
*/
next.pose.orientation = current_pose.orientation * angle_dt_q;
if (VectorMath::hasNan(next.pose.orientation)) {
//Utils::DebugBreak();
Utils::log("orientation had NaN!", Utils::kLogLevelError);
next.pose.orientation = current_pose.orientation * angle_dt_q;
if (VectorMath::hasNan(next.pose.orientation)) {
//Utils::DebugBreak();
Utils::log("orientation had NaN!", Utils::kLogLevelError);
}
//re-normalize quaternion to avoid accumulating error
next.pose.orientation.normalize();
}
else //no change in angle, because angular velocity is zero (normalized vector is undefined)
next.pose.orientation = current_pose.orientation;
}
//re-normalize quaternion to avoid accumulating error
next.pose.orientation.normalize();
}
else //no change in angle, because angular velocity is zero (normalized vector is undefined)
next.pose.orientation = current_pose.orientation;
}
private:
static constexpr uint kCollisionResponseCycles = 1;
static constexpr float kAxisTolerance = 0.25f;
static constexpr float kRestingVelocityMax = 0.1f;
static constexpr float kDragMinVelocity = 0.1f;
private:
static constexpr uint kCollisionResponseCycles = 1;
static constexpr float kAxisTolerance = 0.25f;
static constexpr float kRestingVelocityMax = 0.1f;
static constexpr float kDragMinVelocity = 0.1f;
std::stringstream debug_string_;
bool enable_ground_lock_;
TTimePoint last_message_time;
Vector3r wind_;
};
}} //namespace
std::stringstream debug_string_;
bool enable_ground_lock_;
TTimePoint last_message_time;
Vector3r wind_;
};
}
} //namespace
#endif

Просмотреть файл

@ -8,98 +8,103 @@
#include "common/UpdatableObject.hpp"
#include "common/CommonStructs.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class Kinematics : public UpdatableObject {
public:
struct State {
Pose pose;
Twist twist;
Accelerations accelerations;
static State zero()
class Kinematics : public UpdatableObject
{
public:
struct State
{
State zero_state;
zero_state.pose.position = Vector3r::Zero();
zero_state.pose.orientation = Quaternionr::Identity();
zero_state.twist = Twist::zero();
zero_state.accelerations = Accelerations::zero();
Pose pose;
Twist twist;
Accelerations accelerations;
return zero_state;
static State zero()
{
State zero_state;
zero_state.pose.position = Vector3r::Zero();
zero_state.pose.orientation = Quaternionr::Identity();
zero_state.twist = Twist::zero();
zero_state.accelerations = Accelerations::zero();
return zero_state;
}
};
Kinematics(const State& initial = State::zero())
{
initialize(initial);
}
void initialize(const State& initial)
{
initial_ = initial;
}
virtual void resetImplementation() override
{
current_ = initial_;
}
virtual void update() override
{
UpdatableObject::update();
//nothing to do because next state should be updated
//by physics engine. The reason is that final state
//needs to take in to account state of other objects as well,
//for example, if collision occurs
}
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("Position", current_.pose.position);
reporter.writeValue("Orientation", current_.pose.orientation);
reporter.writeValue("Lin-Vel", current_.twist.linear);
reporter.writeValue("Lin-Accl", current_.accelerations.linear);
reporter.writeValue("Ang-Vel", current_.twist.angular);
reporter.writeValue("Ang-Accl", current_.accelerations.angular);
}
//*** End: UpdatableState implementation ***//
const Pose& getPose() const
{
return current_.pose;
}
void setPose(const Pose& pose)
{
current_.pose = pose;
}
const Twist& getTwist() const
{
return current_.twist;
}
void setTwist(const Twist& twist)
{
current_.twist = twist;
}
const State& getState() const
{
return current_;
}
void setState(const State& state)
{
current_ = state;
}
const State& getInitialState() const
{
return initial_;
}
private: //fields
State initial_;
State current_;
};
Kinematics(const State& initial = State::zero())
{
initialize(initial);
}
void initialize(const State& initial)
{
initial_ = initial;
}
virtual void resetImplementation() override
{
current_ = initial_;
}
virtual void update() override
{
UpdatableObject::update();
//nothing to do because next state should be updated
//by physics engine. The reason is that final state
//needs to take in to account state of other objects as well,
//for example, if collision occurs
}
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("Position", current_.pose.position);
reporter.writeValue("Orientation", current_.pose.orientation);
reporter.writeValue("Lin-Vel", current_.twist.linear);
reporter.writeValue("Lin-Accl", current_.accelerations.linear);
reporter.writeValue("Ang-Vel", current_.twist.angular);
reporter.writeValue("Ang-Accl", current_.accelerations.angular);
}
//*** End: UpdatableState implementation ***//
const Pose& getPose() const
{
return current_.pose;
}
void setPose(const Pose& pose)
{
current_.pose = pose;
}
const Twist& getTwist() const
{
return current_.twist;
}
void setTwist(const Twist& twist)
{
current_.twist = twist;
}
const State& getState() const
{
return current_;
}
void setState(const State& state)
{
current_ = state;
}
const State& getInitialState() const
{
return initial_;
}
private: //fields
State initial_;
State current_;
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -13,258 +13,257 @@
#include <unordered_set>
#include <exception>
namespace msr { namespace airlib {
class PhysicsBody : public UpdatableObject
namespace msr
{
namespace airlib
{
public: //interface
virtual real_T getRestitution() const = 0;
virtual real_T getFriction() const = 0;
//derived class may return covariant type
virtual uint wrenchVertexCount() const
class PhysicsBody : public UpdatableObject
{
return 0;
}
virtual PhysicsBodyVertex& getWrenchVertex(uint index)
{
unused(index);
throw std::out_of_range("no physics vertex are available");
}
virtual const PhysicsBodyVertex& getWrenchVertex(uint index) const
{
unused(index);
throw std::out_of_range("no physics vertex are available");
}
public: //interface
virtual real_T getRestitution() const = 0;
virtual real_T getFriction() const = 0;
virtual uint dragVertexCount() const
{
return 0;
}
virtual PhysicsBodyVertex& getDragVertex(uint index)
{
unused(index);
throw std::out_of_range("no physics vertex are available");
}
virtual const PhysicsBodyVertex& getDragVertex(uint index) const
{
unused(index);
throw std::out_of_range("no physics vertex are available");
}
virtual void setCollisionInfo(const CollisionInfo& collision_info)
{
collision_info_ = collision_info;
}
virtual void updateKinematics(const Kinematics::State& state)
{
if (VectorMath::hasNan(state.twist.linear)) {
//Utils::DebugBreak();
Utils::log("Linear velocity had NaN!", Utils::kLogLevelError);
//derived class may return covariant type
virtual uint wrenchVertexCount() const
{
return 0;
}
virtual PhysicsBodyVertex& getWrenchVertex(uint index)
{
unused(index);
throw std::out_of_range("no physics vertex are available");
}
virtual const PhysicsBodyVertex& getWrenchVertex(uint index) const
{
unused(index);
throw std::out_of_range("no physics vertex are available");
}
kinematics_->setState(state);
kinematics_->update();
}
/**
virtual uint dragVertexCount() const
{
return 0;
}
virtual PhysicsBodyVertex& getDragVertex(uint index)
{
unused(index);
throw std::out_of_range("no physics vertex are available");
}
virtual const PhysicsBodyVertex& getDragVertex(uint index) const
{
unused(index);
throw std::out_of_range("no physics vertex are available");
}
virtual void setCollisionInfo(const CollisionInfo& collision_info)
{
collision_info_ = collision_info;
}
virtual void updateKinematics(const Kinematics::State& state)
{
if (VectorMath::hasNan(state.twist.linear)) {
//Utils::DebugBreak();
Utils::log("Linear velocity had NaN!", Utils::kLogLevelError);
}
kinematics_->setState(state);
kinematics_->update();
}
/**
* Update kinematics without a state
*/
virtual void updateKinematics()
{
kinematics_->update();
}
public: //methods
//constructors
PhysicsBody()
{
//allow default constructor with later call for initialize
}
PhysicsBody(real_T mass, const Matrix3x3r& inertia, Kinematics* kinematics, Environment* environment)
{
initialize(mass, inertia, kinematics, environment);
}
void initialize(real_T mass, const Matrix3x3r& inertia, Kinematics* kinematics, Environment* environment)
{
mass_ = mass;
mass_inv_ = 1.0f / mass;
inertia_ = inertia;
inertia_inv_ = inertia_.inverse();
environment_ = environment;
environment_->setParent(this);
kinematics_ = kinematics;
kinematics_->setParent(this);
}
//enable physics body detection
virtual UpdatableObject* getPhysicsBody() override
{
return this;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
if (environment_)
environment_->reset();
wrench_ = Wrench::zero();
collision_info_ = CollisionInfo();
collision_response_ = CollisionResponse();
grounded_ = false;
//update individual vertices
for (uint vertex_index = 0; vertex_index < wrenchVertexCount(); ++vertex_index) {
getWrenchVertex(vertex_index).reset();
virtual void updateKinematics()
{
kinematics_->update();
}
for (uint vertex_index = 0; vertex_index < dragVertexCount(); ++vertex_index) {
getDragVertex(vertex_index).reset();
public: //methods
//constructors
PhysicsBody()
{
//allow default constructor with later call for initialize
}
}
virtual void update() override
{
UpdatableObject::update();
//update individual vertices - each vertex takes control signal as input and
//produces force and thrust as output
for (uint vertex_index = 0; vertex_index < wrenchVertexCount(); ++vertex_index) {
getWrenchVertex(vertex_index).update();
PhysicsBody(real_T mass, const Matrix3x3r& inertia, Kinematics* kinematics, Environment* environment)
{
initialize(mass, inertia, kinematics, environment);
}
for (uint vertex_index = 0; vertex_index < dragVertexCount(); ++vertex_index) {
getDragVertex(vertex_index).update();
void initialize(real_T mass, const Matrix3x3r& inertia, Kinematics* kinematics, Environment* environment)
{
mass_ = mass;
mass_inv_ = 1.0f / mass;
inertia_ = inertia;
inertia_inv_ = inertia_.inverse();
environment_ = environment;
environment_->setParent(this);
kinematics_ = kinematics;
kinematics_->setParent(this);
}
}
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
//enable physics body detection
virtual UpdatableObject* getPhysicsBody() override
{
return this;
}
reporter.writeHeading("Kinematics");
}
//*** End: UpdatableState implementation ***//
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
if (environment_)
environment_->reset();
wrench_ = Wrench::zero();
collision_info_ = CollisionInfo();
collision_response_ = CollisionResponse();
grounded_ = false;
//update individual vertices
for (uint vertex_index = 0; vertex_index < wrenchVertexCount(); ++vertex_index) {
getWrenchVertex(vertex_index).reset();
}
for (uint vertex_index = 0; vertex_index < dragVertexCount(); ++vertex_index) {
getDragVertex(vertex_index).reset();
}
}
//getters
real_T getMass() const
{
return mass_;
}
real_T getMassInv() const
{
return mass_inv_;
}
const Matrix3x3r& getInertia() const
{
return inertia_;
}
const Matrix3x3r& getInertiaInv() const
{
return inertia_inv_;
}
virtual void update() override
{
UpdatableObject::update();
const Pose& getPose() const
{
return kinematics_->getPose();
}
void setPose(const Pose& pose)
{
return kinematics_->setPose(pose);
}
const Twist& getTwist() const
{
return kinematics_->getTwist();
}
void setTwist(const Twist& twist)
{
return kinematics_->setTwist(twist);
}
//update individual vertices - each vertex takes control signal as input and
//produces force and thrust as output
for (uint vertex_index = 0; vertex_index < wrenchVertexCount(); ++vertex_index) {
getWrenchVertex(vertex_index).update();
}
for (uint vertex_index = 0; vertex_index < dragVertexCount(); ++vertex_index) {
getDragVertex(vertex_index).update();
}
}
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
const Kinematics::State& getKinematics() const
{
return kinematics_->getState();
}
reporter.writeHeading("Kinematics");
}
//*** End: UpdatableState implementation ***//
const Kinematics::State& getInitialKinematics() const
{
return kinematics_->getInitialState();
}
const Environment& getEnvironment() const
{
return *environment_;
}
Environment& getEnvironment()
{
return *environment_;
}
bool hasEnvironment() const
{
return environment_ != nullptr;
}
const Wrench& getWrench() const
{
return wrench_;
}
void setWrench(const Wrench& wrench)
{
wrench_ = wrench;
}
const CollisionInfo& getCollisionInfo() const
{
return collision_info_;
}
//getters
real_T getMass() const
{
return mass_;
}
real_T getMassInv() const
{
return mass_inv_;
}
const Matrix3x3r& getInertia() const
{
return inertia_;
}
const Matrix3x3r& getInertiaInv() const
{
return inertia_inv_;
}
const CollisionResponse& getCollisionResponseInfo() const
{
return collision_response_;
}
CollisionResponse& getCollisionResponseInfo()
{
return collision_response_;
}
const Pose& getPose() const
{
return kinematics_->getPose();
}
void setPose(const Pose& pose)
{
return kinematics_->setPose(pose);
}
const Twist& getTwist() const
{
return kinematics_->getTwist();
}
void setTwist(const Twist& twist)
{
return kinematics_->setTwist(twist);
}
bool isGrounded() const
{
return grounded_;
}
void setGrounded(bool grounded)
{
grounded_ = grounded;
}
const Kinematics::State& getKinematics() const
{
return kinematics_->getState();
}
void lock()
{
mutex_.lock();
}
const Kinematics::State& getInitialKinematics() const
{
return kinematics_->getInitialState();
}
const Environment& getEnvironment() const
{
return *environment_;
}
Environment& getEnvironment()
{
return *environment_;
}
bool hasEnvironment() const
{
return environment_ != nullptr;
}
const Wrench& getWrench() const
{
return wrench_;
}
void setWrench(const Wrench& wrench)
{
wrench_ = wrench;
}
const CollisionInfo& getCollisionInfo() const
{
return collision_info_;
}
void unlock()
{
mutex_.unlock();
}
const CollisionResponse& getCollisionResponseInfo() const
{
return collision_response_;
}
CollisionResponse& getCollisionResponseInfo()
{
return collision_response_;
}
public:
//for use in physics engine: //TODO: use getter/setter or friend method?
TTimePoint last_kinematics_time;
bool isGrounded() const
{
return grounded_;
}
void setGrounded(bool grounded)
{
grounded_ = grounded;
}
private:
real_T mass_, mass_inv_;
Matrix3x3r inertia_, inertia_inv_;
void lock()
{
mutex_.lock();
}
Kinematics* kinematics_ = nullptr;
Environment* environment_ = nullptr;
void unlock()
{
mutex_.unlock();
}
//force is in world frame but torque is not
Wrench wrench_;
public:
//for use in physics engine: //TODO: use getter/setter or friend method?
TTimePoint last_kinematics_time;
CollisionInfo collision_info_;
CollisionResponse collision_response_;
private:
real_T mass_, mass_inv_;
Matrix3x3r inertia_, inertia_inv_;
bool grounded_ = false;
std::mutex mutex_;
};
Kinematics* kinematics_ = nullptr;
Environment* environment_ = nullptr;
}} //namespace
//force is in world frame but torque is not
Wrench wrench_;
CollisionInfo collision_info_;
CollisionResponse collision_response_;
bool grounded_ = false;
std::mutex mutex_;
};
}
} //namespace
#endif

Просмотреть файл

@ -8,91 +8,93 @@
#include "common/Common.hpp"
#include "common/CommonStructs.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class PhysicsBodyVertex : public UpdatableObject {
protected:
virtual void setWrench(Wrench& wrench)
class PhysicsBodyVertex : public UpdatableObject
{
unused(wrench);
//derived class should override if this is force/torque
//generating vertex
}
public:
real_T getDragFactor() const
{
return drag_factor_;
}
void setDragFactor(real_T val)
{
drag_factor_ = val;
}
protected:
virtual void setWrench(Wrench& wrench)
{
unused(wrench);
//derived class should override if this is force/torque
//generating vertex
}
PhysicsBodyVertex()
{
//allow default constructor with later call for initialize
}
PhysicsBodyVertex(const Vector3r& position, const Vector3r& normal, real_T drag_factor = 0)
{
initialize(position, normal, drag_factor);
}
void initialize(const Vector3r& position, const Vector3r& normal, real_T drag_factor = 0)
{
initial_position_ = position;
initial_normal_ = normal;
drag_factor_ = drag_factor;
}
public:
real_T getDragFactor() const
{
return drag_factor_;
}
void setDragFactor(real_T val)
{
drag_factor_ = val;
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
position_ = initial_position_;
normal_ = initial_normal_;
PhysicsBodyVertex()
{
//allow default constructor with later call for initialize
}
PhysicsBodyVertex(const Vector3r& position, const Vector3r& normal, real_T drag_factor = 0)
{
initialize(position, normal, drag_factor);
}
void initialize(const Vector3r& position, const Vector3r& normal, real_T drag_factor = 0)
{
initial_position_ = position;
initial_normal_ = normal;
drag_factor_ = drag_factor;
}
current_wrench_ = Wrench::zero();
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
position_ = initial_position_;
normal_ = initial_normal_;
virtual void update() override
{
UpdatableObject::update();
current_wrench_ = Wrench::zero();
}
setWrench(current_wrench_);
}
//*** End: UpdatableState implementation ***//
virtual void update() override
{
UpdatableObject::update();
setWrench(current_wrench_);
}
//*** End: UpdatableState implementation ***//
//getters, setters
Vector3r getPosition() const
{
return position_;
}
void setPosition(const Vector3r& position)
{
position_ = position;
}
//getters, setters
Vector3r getPosition() const
{
return position_;
}
void setPosition(const Vector3r& position)
{
position_ = position;
}
Vector3r getNormal() const
{
return normal_;
}
void setNormal(const Vector3r& normal)
{
normal_ = normal;
}
Vector3r getNormal() const
{
return normal_;
}
void setNormal(const Vector3r& normal)
{
normal_ = normal;
}
Wrench getWrench() const
{
return current_wrench_;
}
Wrench getWrench() const
{
return current_wrench_;
}
private:
Vector3r initial_position_, position_;
Vector3r initial_normal_, normal_;
Wrench current_wrench_;
real_T drag_factor_;
};
}} //namespace
private:
Vector3r initial_position_, position_;
Vector3r initial_normal_, normal_;
Wrench current_wrench_;
real_T drag_factor_;
};
}
} //namespace
#endif

Просмотреть файл

@ -8,25 +8,27 @@
#include "common/Common.hpp"
#include "PhysicsBody.hpp"
namespace msr { namespace airlib {
class PhysicsEngineBase : public UpdatableContainer<PhysicsBody*>
namespace msr
{
public:
virtual void update() override
namespace airlib
{
class PhysicsEngineBase : public UpdatableContainer<PhysicsBody*>
{
UpdatableObject::update();
}
public:
virtual void update() override
{
UpdatableObject::update();
}
virtual void reportState(StateReporter& reporter) override
{
unused(reporter);
//default nothing to report for physics engine
}
virtual void reportState(StateReporter& reporter) override
{
unused(reporter);
//default nothing to report for physics engine
}
virtual void setWind(const Vector3r& wind) { unused(wind); };
};
}} //namespace
virtual void setWind(const Vector3r& wind) { unused(wind); };
};
}
} //namespace
#endif

Просмотреть файл

@ -11,129 +11,129 @@
#include "World.hpp"
#include "common/StateReporterWrapper.hpp"
namespace msr { namespace airlib {
class PhysicsWorld : UpdatableObject
namespace msr
{
namespace airlib
{
public:
PhysicsWorld(std::unique_ptr<PhysicsEngineBase> physics_engine, const std::vector<UpdatableObject*>& bodies,
uint64_t update_period_nanos = 3000000LL, bool state_reporter_enabled = false,
bool start_async_updator = true
)
: world_(std::move(physics_engine))
{
setName("PhysicsWorld");
enableStateReport(state_reporter_enabled);
update_period_nanos_ = update_period_nanos;
initializeWorld(bodies, start_async_updator);
}
void lock()
class PhysicsWorld : UpdatableObject
{
world_.lock();
}
void unlock()
{
world_.unlock();
}
void reset()
{
lock();
world_.reset();
unlock();
}
void addBody(UpdatableObject* body)
{
lock();
world_.insert(body);
unlock();
}
uint64_t getUpdatePeriodNanos() const
{
return update_period_nanos_;
}
void startAsyncUpdator()
{
world_.startAsyncUpdator(update_period_nanos_);
}
void stopAsyncUpdator()
{
world_.stopAsyncUpdator();
}
void enableStateReport(bool is_enabled)
{
reporter_.setEnable(is_enabled);
}
void updateStateReport()
{
if (reporter_.canReport()) {
reporter_.clearReport();
world_.reportState(*reporter_.getReporter());
public:
PhysicsWorld(std::unique_ptr<PhysicsEngineBase> physics_engine, const std::vector<UpdatableObject*>& bodies,
uint64_t update_period_nanos = 3000000LL, bool state_reporter_enabled = false,
bool start_async_updator = true)
: world_(std::move(physics_engine))
{
setName("PhysicsWorld");
enableStateReport(state_reporter_enabled);
update_period_nanos_ = update_period_nanos;
initializeWorld(bodies, start_async_updator);
}
}
std::string getDebugReport()
{
return reporter_.getOutput();
}
void lock()
{
world_.lock();
}
void pause(bool is_paused)
{
world_.pause(is_paused);
}
void unlock()
{
world_.unlock();
}
bool isPaused() const
{
return world_.isPaused();
}
void reset()
{
lock();
world_.reset();
unlock();
}
void continueForTime(double seconds)
{
world_.continueForTime(seconds);
}
void addBody(UpdatableObject* body)
{
lock();
world_.insert(body);
unlock();
}
void continueForFrames(uint32_t frames)
{
world_.continueForFrames(frames);
}
uint64_t getUpdatePeriodNanos() const
{
return update_period_nanos_;
}
void setFrameNumber(uint32_t frameNumber)
{
world_.setFrameNumber(frameNumber);
}
void resetImplementation() override {}
private:
void initializeWorld(const std::vector<UpdatableObject*>& bodies, bool start_async_updator)
{
reporter_.initialize(false);
world_.insert(&reporter_);
for(size_t bi = 0; bi < bodies.size(); bi++)
world_.insert(bodies.at(bi));
world_.reset();
if (start_async_updator)
void startAsyncUpdator()
{
world_.startAsyncUpdator(update_period_nanos_);
}
}
void stopAsyncUpdator()
{
world_.stopAsyncUpdator();
}
private:
std::vector<UpdatableObject*> bodies_;
StateReporterWrapper reporter_;
World world_;
uint64_t update_period_nanos_;
};
void enableStateReport(bool is_enabled)
{
reporter_.setEnable(is_enabled);
}
void updateStateReport()
{
if (reporter_.canReport()) {
reporter_.clearReport();
world_.reportState(*reporter_.getReporter());
}
}
}} //namespace
std::string getDebugReport()
{
return reporter_.getOutput();
}
void pause(bool is_paused)
{
world_.pause(is_paused);
}
bool isPaused() const
{
return world_.isPaused();
}
void continueForTime(double seconds)
{
world_.continueForTime(seconds);
}
void continueForFrames(uint32_t frames)
{
world_.continueForFrames(frames);
}
void setFrameNumber(uint32_t frameNumber)
{
world_.setFrameNumber(frameNumber);
}
void resetImplementation() override {}
private:
void initializeWorld(const std::vector<UpdatableObject*>& bodies, bool start_async_updator)
{
reporter_.initialize(false);
world_.insert(&reporter_);
for (size_t bi = 0; bi < bodies.size(); bi++)
world_.insert(bodies.at(bi));
world_.reset();
if (start_async_updator)
world_.startAsyncUpdator(update_period_nanos_);
}
private:
std::vector<UpdatableObject*> bodies_;
StateReporterWrapper reporter_;
World world_;
uint64_t update_period_nanos_;
};
}
} //namespace
#endif

Просмотреть файл

@ -12,158 +12,161 @@
#include "common/common_utils/ScheduledExecutor.hpp"
#include "common/ClockFactory.hpp"
namespace msr { namespace airlib {
class World : public UpdatableContainer<UpdatableObject*>
namespace msr
{
namespace airlib
{
public:
World(std::unique_ptr<PhysicsEngineBase> physics_engine)
: physics_engine_(std::move(physics_engine))
{
World::clear();
setName("World");
physics_engine_->setParent(this);
if (physics_engine)
physics_engine_->clear();
}
//override updatable interface so we can synchronize physics engine
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
class World : public UpdatableContainer<UpdatableObject*>
{
UpdatableContainer::resetImplementation();
if (physics_engine_)
physics_engine_->reset();
}
virtual void update() override
{
ClockFactory::get()->step();
//first update our objects
UpdatableContainer::update();
//now update kinematics state
if (physics_engine_)
physics_engine_->update();
}
virtual void reportState(StateReporter& reporter) override
{
reporter.writeValue("Sleep", 1.0f / executor_.getSleepTimeAvg());
if (physics_engine_)
physics_engine_->reportState(reporter);
//call base
UpdatableContainer::reportState(reporter);
}
//*** End: UpdatableState implementation ***//
//override membership modification methods so we can synchronize physics engine
virtual void clear() override
{
if (physics_engine_)
physics_engine_->clear();
UpdatableContainer::clear();
}
virtual void insert(UpdatableObject* member) override
{
if (physics_engine_ && member->getPhysicsBody() != nullptr)
physics_engine_->insert(static_cast<PhysicsBody*>(member->getPhysicsBody()));
UpdatableContainer::insert(member);
}
virtual void erase_remove(UpdatableObject* member) override
{
if (physics_engine_ && member->getPhysicsBody() != nullptr)
physics_engine_->erase_remove(static_cast<PhysicsBody*>(
member->getPhysicsBody()));
UpdatableContainer::erase_remove(member);
}
//async updater thread
void startAsyncUpdator(uint64_t period)
{
//TODO: probably we shouldn't be passing around fixed period
executor_.initialize(std::bind(&World::worldUpdatorAsync, this, std::placeholders::_1), period);
executor_.start();
}
void stopAsyncUpdator()
{
executor_.stop();
}
void lock()
{
executor_.lock();
}
void unlock()
{
executor_.unlock();
}
virtual ~World()
{
executor_.stop();
}
void pause(bool is_paused)
{
executor_.pause(is_paused);
}
bool isPaused() const
{
return executor_.isPaused();
}
void pauseForTime(double seconds)
{
executor_.pauseForTime(seconds);
}
void continueForTime(double seconds)
{
executor_.continueForTime(seconds);
}
void continueForFrames(uint32_t frames)
{
executor_.continueForFrames(frames);
}
void setFrameNumber(uint32_t frameNumber)
{
executor_.setFrameNumber(frameNumber);
}
private:
bool worldUpdatorAsync(uint64_t dt_nanos)
{
unused(dt_nanos);
try {
update();
}
catch(const std::exception& ex) {
//Utils::DebugBreak();
Utils::log(Utils::stringf("Exception occurred while updating world: %s", ex.what()), Utils::kLogLevelError);
}
catch(...) {
//Utils::DebugBreak();
Utils::log("Exception occurred while updating world", Utils::kLogLevelError);
public:
World(std::unique_ptr<PhysicsEngineBase> physics_engine)
: physics_engine_(std::move(physics_engine))
{
World::clear();
setName("World");
physics_engine_->setParent(this);
if (physics_engine)
physics_engine_->clear();
}
return true;
}
//override updatable interface so we can synchronize physics engine
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
UpdatableContainer::resetImplementation();
private:
std::unique_ptr<PhysicsEngineBase> physics_engine_ = nullptr;
common_utils::ScheduledExecutor executor_;
};
if (physics_engine_)
physics_engine_->reset();
}
}} //namespace
virtual void update() override
{
ClockFactory::get()->step();
//first update our objects
UpdatableContainer::update();
//now update kinematics state
if (physics_engine_)
physics_engine_->update();
}
virtual void reportState(StateReporter& reporter) override
{
reporter.writeValue("Sleep", 1.0f / executor_.getSleepTimeAvg());
if (physics_engine_)
physics_engine_->reportState(reporter);
//call base
UpdatableContainer::reportState(reporter);
}
//*** End: UpdatableState implementation ***//
//override membership modification methods so we can synchronize physics engine
virtual void clear() override
{
if (physics_engine_)
physics_engine_->clear();
UpdatableContainer::clear();
}
virtual void insert(UpdatableObject* member) override
{
if (physics_engine_ && member->getPhysicsBody() != nullptr)
physics_engine_->insert(static_cast<PhysicsBody*>(member->getPhysicsBody()));
UpdatableContainer::insert(member);
}
virtual void erase_remove(UpdatableObject* member) override
{
if (physics_engine_ && member->getPhysicsBody() != nullptr)
physics_engine_->erase_remove(static_cast<PhysicsBody*>(
member->getPhysicsBody()));
UpdatableContainer::erase_remove(member);
}
//async updater thread
void startAsyncUpdator(uint64_t period)
{
//TODO: probably we shouldn't be passing around fixed period
executor_.initialize(std::bind(&World::worldUpdatorAsync, this, std::placeholders::_1), period);
executor_.start();
}
void stopAsyncUpdator()
{
executor_.stop();
}
void lock()
{
executor_.lock();
}
void unlock()
{
executor_.unlock();
}
virtual ~World()
{
executor_.stop();
}
void pause(bool is_paused)
{
executor_.pause(is_paused);
}
bool isPaused() const
{
return executor_.isPaused();
}
void pauseForTime(double seconds)
{
executor_.pauseForTime(seconds);
}
void continueForTime(double seconds)
{
executor_.continueForTime(seconds);
}
void continueForFrames(uint32_t frames)
{
executor_.continueForFrames(frames);
}
void setFrameNumber(uint32_t frameNumber)
{
executor_.setFrameNumber(frameNumber);
}
private:
bool worldUpdatorAsync(uint64_t dt_nanos)
{
unused(dt_nanos);
try {
update();
}
catch (const std::exception& ex) {
//Utils::DebugBreak();
Utils::log(Utils::stringf("Exception occurred while updating world: %s", ex.what()), Utils::kLogLevelError);
}
catch (...) {
//Utils::DebugBreak();
Utils::log("Exception occurred while updating world", Utils::kLogLevelError);
}
return true;
}
private:
std::unique_ptr<PhysicsEngineBase> physics_engine_ = nullptr;
common_utils::ScheduledExecutor executor_;
};
}
} //namespace
#endif

Просмотреть файл

@ -6,65 +6,68 @@
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class CubeGeoFence : public IGeoFence {
private:
Vector3r point_min_, point_max_, point_center_;
float distance_accuracy_;
public:
CubeGeoFence(const Vector3r& point_min, const Vector3r& point_max, float distance_accuracy)
: point_min_(point_min), point_max_(point_max), distance_accuracy_(distance_accuracy)
class CubeGeoFence : public IGeoFence
{
calculateCenter();
private:
Vector3r point_min_, point_max_, point_center_;
float distance_accuracy_;
Utils::logMessage("CubeGeoFence: %s", toString().c_str());
}
public:
CubeGeoFence(const Vector3r& point_min, const Vector3r& point_max, float distance_accuracy)
: point_min_(point_min), point_max_(point_max), distance_accuracy_(distance_accuracy)
{
calculateCenter();
void setBoundry(const Vector3r& origin, float xy_length, float max_z, float min_z) override
{
point_min_ = Vector3r(-xy_length, -xy_length, 0) + origin;
point_min_[2] = max_z;
point_max_ = Vector3r(xy_length, xy_length, 0) + origin;
point_max_[2] = min_z;
calculateCenter();
Utils::logMessage("CubeGeoFence: %s", toString().c_str());
}
void checkFence(const Vector3r& cur_loc, const Vector3r& dest_loc,
bool& in_fence, bool& allow) override
{
in_fence = dest_loc[0] >= point_min_[0] && dest_loc[1] >= point_min_[1] && dest_loc[2] >= point_min_[2] &&
dest_loc[0] <= point_max_[0] && dest_loc[1] <= point_max_[1] && dest_loc[2] <= point_max_[2];
if (!in_fence) {
//are we better off with dest than cur location?
float dest_dist = (dest_loc - point_center_).norm();
float cur_dist = (cur_loc - point_center_).norm();
allow = cur_dist - dest_dist >= -distance_accuracy_;
Utils::logMessage("CubeGeoFence: %s", toString().c_str());
}
else
allow = true;
}
string toString() const override
{
return Utils::stringf("min=%s, max=%s", VectorMath::toString(point_min_).c_str(), VectorMath::toString(point_max_).c_str());
}
virtual ~CubeGeoFence() {};
void setBoundry(const Vector3r& origin, float xy_length, float max_z, float min_z) override
{
point_min_ = Vector3r(-xy_length, -xy_length, 0) + origin;
point_min_[2] = max_z;
private:
void calculateCenter()
{
point_center_ = (point_max_ + point_min_) / 2;
}
};
point_max_ = Vector3r(xy_length, xy_length, 0) + origin;
point_max_[2] = min_z;
calculateCenter();
}} //namespace
Utils::logMessage("CubeGeoFence: %s", toString().c_str());
}
void checkFence(const Vector3r& cur_loc, const Vector3r& dest_loc,
bool& in_fence, bool& allow) override
{
in_fence = dest_loc[0] >= point_min_[0] && dest_loc[1] >= point_min_[1] && dest_loc[2] >= point_min_[2] &&
dest_loc[0] <= point_max_[0] && dest_loc[1] <= point_max_[1] && dest_loc[2] <= point_max_[2];
if (!in_fence) {
//are we better off with dest than cur location?
float dest_dist = (dest_loc - point_center_).norm();
float cur_dist = (cur_loc - point_center_).norm();
allow = cur_dist - dest_dist >= -distance_accuracy_;
}
else
allow = true;
}
string toString() const override
{
return Utils::stringf("min=%s, max=%s", VectorMath::toString(point_min_).c_str(), VectorMath::toString(point_max_).c_str());
}
virtual ~CubeGeoFence(){};
private:
void calculateCenter()
{
point_center_ = (point_max_ + point_min_) / 2;
}
};
}
} //namespace
#endif

Просмотреть файл

@ -6,17 +6,21 @@
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class IGeoFence {
public:
virtual void setBoundry(const Vector3r& origin, float xy_length, float max_z, float min_z) = 0;
virtual void checkFence(const Vector3r& cur_loc, const Vector3r& dest_loc,
bool& in_fence, bool& allow) = 0;
virtual string toString() const = 0;
class IGeoFence
{
public:
virtual void setBoundry(const Vector3r& origin, float xy_length, float max_z, float min_z) = 0;
virtual void checkFence(const Vector3r& cur_loc, const Vector3r& dest_loc,
bool& in_fence, bool& allow) = 0;
virtual string toString() const = 0;
virtual ~IGeoFence() {};
};
}} //namespace
virtual ~IGeoFence(){};
};
}
} //namespace
#endif

Просмотреть файл

@ -7,9 +7,12 @@
#include <mutex>
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
/*
/*
ObstacleMap implements 2D map of obstacles in circular disk around the vehicle. The main
design criteria is to make insert/delete/queries very fast. This is typically
not possible in grid based approach because these operations may have large
@ -35,63 +38,68 @@ namespace msr { namespace airlib {
We fully expect one thread to continuously update the obstacles while another to query the map.
*/
class ObstacleMap {
private:
//stores distances for each tick segment
vector<float> distances_;
//what is the confidence in these values? This should typically be the standard deviation
vector<float> confidences_;
//number of ticks, this decides reolution
int ticks_;
//blind spots don't get updated so we get its value from neighbours
vector<bool> blindspots_;
public:
//this will be return result of the queries
struct ObstacleInfo {
int tick; //at what tick we found obstacle
float distance; //what is the distance from obstacle
float confidence;
class ObstacleMap
{
private:
//stores distances for each tick segment
vector<float> distances_;
//what is the confidence in these values? This should typically be the standard deviation
vector<float> confidences_;
//number of ticks, this decides reolution
int ticks_;
//blind spots don't get updated so we get its value from neighbours
vector<bool> blindspots_;
string toString() const
public:
//this will be return result of the queries
struct ObstacleInfo
{
return Utils::stringf("Obs: tick=%i, distance=%f, confidence=%f", tick, distance, confidence);
}
int tick; //at what tick we found obstacle
float distance; //what is the distance from obstacle
float confidence;
string toString() const
{
return Utils::stringf("Obs: tick=%i, distance=%f, confidence=%f", tick, distance, confidence);
}
};
//private version of hasObstacle doesn't do lock or check inputs
ObstacleInfo hasObstacle_(int from_tick, int to_tick) const;
private:
int wrap(int tick) const;
//currently we employ simple thread safe model: just serialize queries and updates
std::mutex mutex_;
public:
//if odd_blindspots = true then set all odd ticks as blind spots
ObstacleMap(int ticks, bool odd_blindspots = false);
//update the map for tick direction within +/-window ticks
void update(float distance, int tick, int window, float confidence);
void update(float distances[], float confidences[]);
void setBlindspot(int tick, bool blindspot);
//query if we have obstacle in segment that starts at from to segment that starts at to
ObstacleInfo hasObstacle(int from_tick, int to_tick);
//search entire map to find obstacle at minimum distance
ObstacleInfo getClosestObstacle();
//number of ticks the map was initialized with
int getTicks() const;
//convert angle (in body frame) in radians to tick number
int angleToTick(float angle_rad) const;
//convert tick to start of angle (in body frame) in radians
float tickToAngleStart(int tick) const;
//convert tick to end of angle (in body frame) in radians
float tickToAngleEnd(int tick) const;
//convert tick to mid of the cone in radians
float tickToAngleMid(int tick) const;
};
//private version of hasObstacle doesn't do lock or check inputs
ObstacleInfo hasObstacle_(int from_tick, int to_tick) const;
private:
int wrap(int tick) const;
//currently we employ simple thread safe model: just serialize queries and updates
std::mutex mutex_;
public:
//if odd_blindspots = true then set all odd ticks as blind spots
ObstacleMap(int ticks, bool odd_blindspots = false);
//update the map for tick direction within +/-window ticks
void update(float distance, int tick, int window, float confidence);
void update(float distances[], float confidences[]);
void setBlindspot(int tick, bool blindspot);
//query if we have obstacle in segment that starts at from to segment that starts at to
ObstacleInfo hasObstacle(int from_tick, int to_tick);
//search entire map to find obstacle at minimum distance
ObstacleInfo getClosestObstacle();
//number of ticks the map was initialized with
int getTicks() const;
//convert angle (in body frame) in radians to tick number
int angleToTick(float angle_rad) const;
//convert tick to start of angle (in body frame) in radians
float tickToAngleStart(int tick) const;
//convert tick to end of angle (in body frame) in radians
float tickToAngleEnd(int tick) const;
//convert tick to mid of the cone in radians
float tickToAngleMid(int tick) const;
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -14,89 +14,106 @@
#include "vehicles/multirotor/api/MultirotorCommon.hpp"
#include "common/common_utils/EnumFlags.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
//this class takes all inputs and outputs in NEU world coordinates in metric system
class SafetyEval {
public:
enum class SafetyViolationType_ :uint {
NoSafetyViolation = 0,
GeoFence = 1 << 0,
Obstacle = 1 << 1,
VelocityLimit = 1 << 2,
All = Utils::max<uint>()
};
//add bitwise operators for enum
typedef common_utils::EnumFlags<SafetyViolationType_> SafetyViolationType;
//to disable obstacle avoidance entirely, disable it in SafetyViolationType
enum class ObsAvoidanceStrategy : uint {
RaiseException = 0, //will return suggested velocity vector = 0
ClosestMove, //find closest obstacle free destination along desired destination
OppositeMove //find closest obstacle free destination along opposite of desired destination
};
//result of the safety evaluation
struct EvalResult {
//information in data structure may only be partially filled if is_safe = true
bool is_safe;
SafetyViolationType reason;
//obstacle info around cur and towards dest, if no obs found then cur might not be evaluated
ObstacleMap::ObstacleInfo cur_obs, dest_obs, suggested_obs;
//locations that were considered while evaluation
Vector3r cur_pos, dest_pos;
//transformed cur to destination vector in body frame
Vector3r cur_dest_body;
string message;
//suggested unit vector without obstacle, must be zero if no suggestions available
Vector3r suggested_vec;
//risk distances indicates how far we are in to risk zone, lower (<= 0) better than higher
//cur is for risk distance around current position
//dest if risk distance towards destination
float cur_risk_dist, dest_risk_dist;
//setup default result
EvalResult()
: is_safe(true), reason(SafetyViolationType_::NoSafetyViolation), suggested_vec(Vector3r::Zero()),
cur_risk_dist(Utils::nan<float>()), dest_risk_dist(Utils::nan<float>())
{}
string toString() const
//this class takes all inputs and outputs in NEU world coordinates in metric system
class SafetyEval
{
public:
enum class SafetyViolationType_ : uint
{
return Utils::stringf("SafetyEval: is_safe=%i, reason=%X, cur_risk_dist=%f, dest_risk_dist=%f, suggested_vec=%s,"
" cur=%s, dest=%s, cur_dest_body=%s, cur_obs=[%s], dest_obs=[%s], suggested_obs=[%s], message=%s",
is_safe, uint(reason), cur_risk_dist, dest_risk_dist, VectorMath::toString(suggested_vec).c_str(),
VectorMath::toString(cur_pos).c_str(), VectorMath::toString(dest_pos).c_str(), VectorMath::toString(cur_dest_body).c_str(),
cur_obs.toString().c_str(), dest_obs.toString().c_str(), suggested_obs.toString().c_str(), message.c_str());
}
NoSafetyViolation = 0,
GeoFence = 1 << 0,
Obstacle = 1 << 1,
VelocityLimit = 1 << 2,
All = Utils::max<uint>()
};
//add bitwise operators for enum
typedef common_utils::EnumFlags<SafetyViolationType_> SafetyViolationType;
//to disable obstacle avoidance entirely, disable it in SafetyViolationType
enum class ObsAvoidanceStrategy : uint
{
RaiseException = 0, //will return suggested velocity vector = 0
ClosestMove, //find closest obstacle free destination along desired destination
OppositeMove //find closest obstacle free destination along opposite of desired destination
};
//result of the safety evaluation
struct EvalResult
{
//information in data structure may only be partially filled if is_safe = true
bool is_safe;
SafetyViolationType reason;
//obstacle info around cur and towards dest, if no obs found then cur might not be evaluated
ObstacleMap::ObstacleInfo cur_obs, dest_obs, suggested_obs;
//locations that were considered while evaluation
Vector3r cur_pos, dest_pos;
//transformed cur to destination vector in body frame
Vector3r cur_dest_body;
string message;
//suggested unit vector without obstacle, must be zero if no suggestions available
Vector3r suggested_vec;
//risk distances indicates how far we are in to risk zone, lower (<= 0) better than higher
//cur is for risk distance around current position
//dest if risk distance towards destination
float cur_risk_dist, dest_risk_dist;
//setup default result
EvalResult()
: is_safe(true), reason(SafetyViolationType_::NoSafetyViolation), suggested_vec(Vector3r::Zero()), cur_risk_dist(Utils::nan<float>()), dest_risk_dist(Utils::nan<float>())
{
}
string toString() const
{
return Utils::stringf("SafetyEval: is_safe=%i, reason=%X, cur_risk_dist=%f, dest_risk_dist=%f, suggested_vec=%s,"
" cur=%s, dest=%s, cur_dest_body=%s, cur_obs=[%s], dest_obs=[%s], suggested_obs=[%s], message=%s",
is_safe,
uint(reason),
cur_risk_dist,
dest_risk_dist,
VectorMath::toString(suggested_vec).c_str(),
VectorMath::toString(cur_pos).c_str(),
VectorMath::toString(dest_pos).c_str(),
VectorMath::toString(cur_dest_body).c_str(),
cur_obs.toString().c_str(),
dest_obs.toString().c_str(),
suggested_obs.toString().c_str(),
message.c_str());
}
};
private:
MultirotorApiParams vehicle_params_;
shared_ptr<IGeoFence> fence_ptr_;
shared_ptr<ObstacleMap> obs_xy_ptr_;
SafetyViolationType enable_reasons_ = SafetyEval::SafetyViolationType_::GeoFence;
ObsAvoidanceStrategy obs_strategy_ = SafetyEval::ObsAvoidanceStrategy::RaiseException;
void checkFence(const Vector3r& cur_pos, const Vector3r& dest_pos, EvalResult& appendToResult);
void isSafeDestination(const Vector3r& dest, const Vector3r& cur_pos, const Quaternionr& quaternion, SafetyEval::EvalResult& result);
Vector3r getDestination(const Vector3r& cur_pos, const Vector3r& velocity) const;
bool isThisRiskDistLess(float this_risk_dist, float other_risk_dist) const;
void isCurrentSafer(SafetyEval::EvalResult& result);
void setSuggestedVelocity(SafetyEval::EvalResult& result, const Quaternionr& quaternion);
float adjustClearanceForPrStl(float base_clearance, float obs_confidence);
public:
SafetyEval(MultirotorApiParams vehicle_params, shared_ptr<IGeoFence> fence_ptr, shared_ptr<ObstacleMap> obs_xy);
EvalResult isSafeVelocity(const Vector3r& cur_pos, const Vector3r& velocity, const Quaternionr& quaternion);
EvalResult isSafeVelocityZ(const Vector3r& cur_pos, float vx, float vy, float z, const Quaternionr& quaternion);
EvalResult isSafeDestination(const Vector3r& dest, const Vector3r& cur_pos, const Quaternionr& quaternion);
EvalResult isSafePosition(const Vector3r& cur_pos, const Quaternionr& quaternion);
void setSafety(SafetyViolationType enable_reasons, float obs_clearance, SafetyEval::ObsAvoidanceStrategy obs_strategy,
const Vector3r& origin, float xy_length, float max_z, float min_z);
void setObsAvoidanceStrategy(SafetyEval::ObsAvoidanceStrategy obs_strategy);
SafetyEval::ObsAvoidanceStrategy getObsAvoidanceStrategy();
};
private:
MultirotorApiParams vehicle_params_;
shared_ptr<IGeoFence> fence_ptr_;
shared_ptr<ObstacleMap> obs_xy_ptr_;
SafetyViolationType enable_reasons_ = SafetyEval::SafetyViolationType_::GeoFence;
ObsAvoidanceStrategy obs_strategy_ = SafetyEval::ObsAvoidanceStrategy::RaiseException;
void checkFence(const Vector3r& cur_pos, const Vector3r& dest_pos, EvalResult& appendToResult);
void isSafeDestination(const Vector3r& dest,const Vector3r& cur_pos, const Quaternionr& quaternion, SafetyEval::EvalResult& result);
Vector3r getDestination(const Vector3r& cur_pos, const Vector3r& velocity) const;
bool isThisRiskDistLess(float this_risk_dist, float other_risk_dist) const;
void isCurrentSafer(SafetyEval::EvalResult& result);
void setSuggestedVelocity(SafetyEval::EvalResult& result, const Quaternionr& quaternion);
float adjustClearanceForPrStl(float base_clearance, float obs_confidence);
public:
SafetyEval(MultirotorApiParams vehicle_params, shared_ptr<IGeoFence> fence_ptr, shared_ptr<ObstacleMap> obs_xy);
EvalResult isSafeVelocity(const Vector3r& cur_pos, const Vector3r& velocity, const Quaternionr& quaternion);
EvalResult isSafeVelocityZ(const Vector3r& cur_pos, float vx, float vy, float z, const Quaternionr& quaternion);
EvalResult isSafeDestination(const Vector3r& dest,const Vector3r& cur_pos, const Quaternionr& quaternion);
EvalResult isSafePosition(const Vector3r& cur_pos, const Quaternionr& quaternion);
void setSafety(SafetyViolationType enable_reasons, float obs_clearance, SafetyEval::ObsAvoidanceStrategy obs_strategy,
const Vector3r& origin, float xy_length, float max_z, float min_z);
void setObsAvoidanceStrategy(SafetyEval::ObsAvoidanceStrategy obs_strategy);
SafetyEval::ObsAvoidanceStrategy getObsAvoidanceStrategy();
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -6,54 +6,57 @@
#include "common/Common.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class SphereGeoFence : public IGeoFence {
private:
Vector3r center_;
float radius_, distance_accuracy_, min_height_, max_height_;
public:
SphereGeoFence(const Vector3r& center, float radius, float max_height, float min_height, float distance_accuracy)
: center_(center), radius_(radius), distance_accuracy_(distance_accuracy), min_height_(min_height), max_height_(max_height)
class SphereGeoFence : public IGeoFence
{
Utils::logMessage("SphereGeoFence: %s", toString().c_str());
}
private:
Vector3r center_;
float radius_, distance_accuracy_, min_height_, max_height_;
void setBoundry(const Vector3r& origin, float xy_length, float max_z, float min_z) override
{
center_ = origin;
radius_ = xy_length;
max_height_ = min_z;
min_height_ = max_z;
Utils::logMessage("SphereGeoFence: %s", toString().c_str());
}
void checkFence(const Vector3r& cur_loc, const Vector3r& dest_loc,
bool& in_fence, bool& allow) override
{
Vector3r center_dest = dest_loc - center_;
Vector3r center_dest_xy(center_dest[0], center_dest[1], 0);
in_fence = center_dest_xy.norm() <= radius_ && dest_loc[2] >= min_height_ && dest_loc[2] <= max_height_;
if (!in_fence) {
float cur_center_norm = (cur_loc - center_).norm();
allow = cur_center_norm - center_dest.norm() >= -distance_accuracy;
public:
SphereGeoFence(const Vector3r& center, float radius, float max_height, float min_height, float distance_accuracy)
: center_(center), radius_(radius), distance_accuracy_(distance_accuracy), min_height_(min_height), max_height_(max_height)
{
Utils::logMessage("SphereGeoFence: %s", toString().c_str());
}
else
allow = true;
}
string toString() const override
{
return Utils::stringf("CubeGeoFence: radius=%f, min_height=%f, max_height=%f, center=%s", radius_, min_height_, max_height_, Vector3r::toString(center_).c_str());
}
void setBoundry(const Vector3r& origin, float xy_length, float max_z, float min_z) override
{
center_ = origin;
radius_ = xy_length;
max_height_ = min_z;
min_height_ = max_z;
virtual ~SphereGeoFence() {};
};
Utils::logMessage("SphereGeoFence: %s", toString().c_str());
}
}} //namespace
void checkFence(const Vector3r& cur_loc, const Vector3r& dest_loc,
bool& in_fence, bool& allow) override
{
Vector3r center_dest = dest_loc - center_;
Vector3r center_dest_xy(center_dest[0], center_dest[1], 0);
in_fence = center_dest_xy.norm() <= radius_ && dest_loc[2] >= min_height_ && dest_loc[2] <= max_height_;
if (!in_fence) {
float cur_center_norm = (cur_loc - center_).norm();
allow = cur_center_norm - center_dest.norm() >= -distance_accuracy;
}
else
allow = true;
}
string toString() const override
{
return Utils::stringf("CubeGeoFence: radius=%f, min_height=%f, max_height=%f, center=%s", radius_, min_height_, max_height_, Vector3r::toString(center_).c_str());
}
virtual ~SphereGeoFence(){};
};
}
} //namespace
#endif

Просмотреть файл

@ -10,61 +10,65 @@
#include "physics/Environment.hpp"
#include "physics/Kinematics.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
/*
/*
Derived classes should not do any work in constructor which requires ground truth.
After construction of the derived class an initialize(...) must be made which would
set the sensor in good-to-use state by call to reset.
*/
class SensorBase : public UpdatableObject
{
public:
enum class SensorType : uint {
Barometer = 1,
Imu = 2,
Gps = 3,
Magnetometer = 4,
Distance = 5,
Lidar = 6
class SensorBase : public UpdatableObject
{
public:
enum class SensorType : uint
{
Barometer = 1,
Imu = 2,
Gps = 3,
Magnetometer = 4,
Distance = 5,
Lidar = 6
};
SensorBase(const std::string& sensor_name = "")
: name_(sensor_name)
{
}
protected:
struct GroundTruth
{
const Kinematics::State* kinematics;
const Environment* environment;
};
public:
virtual void initialize(const Kinematics::State* kinematics, const Environment* environment)
{
ground_truth_.kinematics = kinematics;
ground_truth_.environment = environment;
}
const GroundTruth& getGroundTruth() const
{
return ground_truth_;
}
const std::string& getName() const
{
return name_;
}
virtual ~SensorBase() = default;
private:
//ground truth can be shared between many sensors
GroundTruth ground_truth_ = { nullptr, nullptr };
std::string name_ = "";
};
SensorBase(const std::string& sensor_name = "")
: name_(sensor_name)
{}
protected:
struct GroundTruth {
const Kinematics::State* kinematics;
const Environment* environment;
};
public:
virtual void initialize(const Kinematics::State* kinematics, const Environment* environment)
{
ground_truth_.kinematics = kinematics;
ground_truth_.environment = environment;
}
const GroundTruth& getGroundTruth() const
{
return ground_truth_;
}
const std::string& getName() const
{
return name_;
}
virtual ~SensorBase() = default;
private:
//ground truth can be shared between many sensors
GroundTruth ground_truth_ = { nullptr, nullptr };
std::string name_ = "";
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -9,93 +9,97 @@
#include "common/UpdatableContainer.hpp"
#include "common/Common.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class SensorCollection : public UpdatableObject {
public: //types
typedef SensorBase* SensorBasePtr;
public:
void insert(SensorBasePtr sensor, SensorBase::SensorType type)
class SensorCollection : public UpdatableObject
{
auto type_int = static_cast<uint>(type);
const auto& it = sensors_.find(type_int);
if (it == sensors_.end()) {
const auto& pair = sensors_.emplace(type_int, unique_ptr<SensorBaseContainer>(new SensorBaseContainer()));
pair.first->second->insert(sensor);
}
else {
it->second->insert(sensor);
}
}
public: //types
typedef SensorBase* SensorBasePtr;
const SensorBase* getByType(SensorBase::SensorType type, uint index = 0) const
{
auto type_int = static_cast<uint>(type);
const auto& it = sensors_.find(type_int);
if (it == sensors_.end()) {
return nullptr;
}
else {
return it->second->at(index);
}
}
uint size(SensorBase::SensorType type) const
{
auto type_int = static_cast<uint>(type);
const auto& it = sensors_.find(type_int);
if (it == sensors_.end()) {
return 0;
}
else {
return it->second->size();
}
}
void initialize(const Kinematics::State* kinematics, const Environment* environment)
{
for (auto& pair : sensors_) {
for (auto& sensor : *pair.second) {
sensor->initialize(kinematics, environment);
public:
void insert(SensorBasePtr sensor, SensorBase::SensorType type)
{
auto type_int = static_cast<uint>(type);
const auto& it = sensors_.find(type_int);
if (it == sensors_.end()) {
const auto& pair = sensors_.emplace(type_int, unique_ptr<SensorBaseContainer>(new SensorBaseContainer()));
pair.first->second->insert(sensor);
}
else {
it->second->insert(sensor);
}
}
}
void clear()
{
sensors_.clear();
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
for (auto& pair : sensors_) {
pair.second->reset();
const SensorBase* getByType(SensorBase::SensorType type, uint index = 0) const
{
auto type_int = static_cast<uint>(type);
const auto& it = sensors_.find(type_int);
if (it == sensors_.end()) {
return nullptr;
}
else {
return it->second->at(index);
}
}
}
virtual void update() override
{
UpdatableObject::update();
for (auto& pair : sensors_) {
pair.second->update();
uint size(SensorBase::SensorType type) const
{
auto type_int = static_cast<uint>(type);
const auto& it = sensors_.find(type_int);
if (it == sensors_.end()) {
return 0;
}
else {
return it->second->size();
}
}
}
virtual void reportState(StateReporter& reporter) override
{
for (auto& pair : sensors_) {
pair.second->reportState(reporter);
void initialize(const Kinematics::State* kinematics, const Environment* environment)
{
for (auto& pair : sensors_) {
for (auto& sensor : *pair.second) {
sensor->initialize(kinematics, environment);
}
}
}
}
//*** End: UpdatableState implementation ***//
private:
typedef UpdatableContainer<SensorBasePtr> SensorBaseContainer;
unordered_map<uint, unique_ptr<SensorBaseContainer>> sensors_;
};
void clear()
{
sensors_.clear();
}
}} //namespace
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
for (auto& pair : sensors_) {
pair.second->reset();
}
}
virtual void update() override
{
UpdatableObject::update();
for (auto& pair : sensors_) {
pair.second->update();
}
}
virtual void reportState(StateReporter& reporter) override
{
for (auto& pair : sensors_) {
pair.second->reportState(reporter);
}
}
//*** End: UpdatableState implementation ***//
private:
typedef UpdatableContainer<SensorBasePtr> SensorBaseContainer;
unordered_map<uint, unique_ptr<SensorBaseContainer>> sensors_;
};
}
} //namespace
#endif

Просмотреть файл

@ -1,7 +1,6 @@
#ifndef msr_airlib_SensorFactoryBase_hpp
#define msr_airlib_SensorFactoryBase_hpp
#include "SensorBase.hpp"
#include "SensorCollection.hpp"
#include <memory>
@ -12,55 +11,55 @@
#include "sensors/gps/GpsSimple.hpp"
#include "sensors/barometer/BarometerSimple.hpp"
namespace msr { namespace airlib {
class SensorFactory
namespace msr
{
namespace airlib
{
public:
// creates one sensor from settings
virtual std::shared_ptr<SensorBase> createSensorFromSettings(
const AirSimSettings::SensorSetting* sensor_setting) const
class SensorFactory
{
switch (sensor_setting->sensor_type) {
case SensorBase::SensorType::Imu:
return std::shared_ptr<ImuSimple>(new ImuSimple(*static_cast<const AirSimSettings::ImuSetting*>(sensor_setting)));
case SensorBase::SensorType::Magnetometer:
return std::shared_ptr<MagnetometerSimple>(new MagnetometerSimple(*static_cast<const AirSimSettings::MagnetometerSetting*>(sensor_setting)));
case SensorBase::SensorType::Gps:
return std::shared_ptr<GpsSimple>(new GpsSimple(*static_cast<const AirSimSettings::GpsSetting*>(sensor_setting)));
case SensorBase::SensorType::Barometer:
return std::shared_ptr<BarometerSimple>(new BarometerSimple(*static_cast<const AirSimSettings::BarometerSetting*>(sensor_setting)));
default:
throw new std::invalid_argument("Unexpected sensor type");
}
}
// creates sensor-collection
virtual void createSensorsFromSettings(
const std::map<std::string, std::shared_ptr<AirSimSettings::SensorSetting>>& sensors_settings,
SensorCollection& sensors,
vector<shared_ptr<SensorBase>>& sensor_storage) const
{
for (const auto& sensor_setting_pair : sensors_settings) {
const AirSimSettings::SensorSetting* sensor_setting = sensor_setting_pair.second.get();
// ignore sensors that are marked "disabled" in settings
if (sensor_setting == nullptr || !sensor_setting->enabled)
continue;
std::shared_ptr<SensorBase> sensor = createSensorFromSettings(sensor_setting);
if (sensor) {
sensor_storage.push_back(sensor);
sensors.insert(sensor.get(), sensor_setting->sensor_type);
public:
// creates one sensor from settings
virtual std::shared_ptr<SensorBase> createSensorFromSettings(
const AirSimSettings::SensorSetting* sensor_setting) const
{
switch (sensor_setting->sensor_type) {
case SensorBase::SensorType::Imu:
return std::shared_ptr<ImuSimple>(new ImuSimple(*static_cast<const AirSimSettings::ImuSetting*>(sensor_setting)));
case SensorBase::SensorType::Magnetometer:
return std::shared_ptr<MagnetometerSimple>(new MagnetometerSimple(*static_cast<const AirSimSettings::MagnetometerSetting*>(sensor_setting)));
case SensorBase::SensorType::Gps:
return std::shared_ptr<GpsSimple>(new GpsSimple(*static_cast<const AirSimSettings::GpsSetting*>(sensor_setting)));
case SensorBase::SensorType::Barometer:
return std::shared_ptr<BarometerSimple>(new BarometerSimple(*static_cast<const AirSimSettings::BarometerSetting*>(sensor_setting)));
default:
throw new std::invalid_argument("Unexpected sensor type");
}
}
}
virtual ~SensorFactory() = default;
};
// creates sensor-collection
virtual void createSensorsFromSettings(
const std::map<std::string, std::shared_ptr<AirSimSettings::SensorSetting>>& sensors_settings,
SensorCollection& sensors,
vector<shared_ptr<SensorBase>>& sensor_storage) const
{
for (const auto& sensor_setting_pair : sensors_settings) {
const AirSimSettings::SensorSetting* sensor_setting = sensor_setting_pair.second.get();
// ignore sensors that are marked "disabled" in settings
if (sensor_setting == nullptr || !sensor_setting->enabled)
continue;
}} //namespace
std::shared_ptr<SensorBase> sensor = createSensorFromSettings(sensor_setting);
if (sensor) {
sensor_storage.push_back(sensor);
sensors.insert(sensor.get(), sensor_setting->sensor_type);
}
}
}
virtual ~SensorFactory() = default;
};
}
} //namespace
#endif

Просмотреть файл

@ -4,53 +4,54 @@
#ifndef msr_airlib_BarometerBase_hpp
#define msr_airlib_BarometerBase_hpp
#include "sensors/SensorBase.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class BarometerBase : public SensorBase
{
public:
BarometerBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{
}
class BarometerBase : public SensorBase {
public:
BarometerBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{}
public: //types
struct Output
{ //same fields as ROS message
TTimePoint time_stamp;
real_T altitude; //meters
real_T pressure; //Pascal
real_T qnh;
};
public: //types
struct Output { //same fields as ROS message
TTimePoint time_stamp;
real_T altitude; //meters
real_T pressure; //Pascal
real_T qnh;
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("Baro-Alt", output_.altitude);
reporter.writeValue("Baro-Prs", output_.pressure);
}
const Output& getOutput() const
{
return output_;
}
protected:
void setOutput(const Output& output)
{
output_ = output;
}
private:
Output output_;
};
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("Baro-Alt", output_.altitude);
reporter.writeValue("Baro-Prs", output_.pressure);
}
const Output& getOutput() const
{
return output_;
}
protected:
void setOutput(const Output& output)
{
output_ = output;
}
private:
Output output_;
};
}} //namespace
#endif
}
} //namespace
#endif

Просмотреть файл

@ -13,100 +13,102 @@
#include "common/DelayLine.hpp"
#include "common/FrequencyLimiter.hpp"
namespace msr { namespace airlib {
class BarometerSimple : public BarometerBase
namespace msr
{
public:
BarometerSimple(const AirSimSettings::BarometerSetting& setting = AirSimSettings::BarometerSetting())
: BarometerBase(setting.sensor_name)
namespace airlib
{
class BarometerSimple : public BarometerBase
{
// initialize params
params_.initializeFromSettings(setting);
public:
BarometerSimple(const AirSimSettings::BarometerSetting& setting = AirSimSettings::BarometerSetting())
: BarometerBase(setting.sensor_name)
{
// initialize params
params_.initializeFromSettings(setting);
//GM process that would do random walk for pressure factor
pressure_factor_.initialize(params_.pressure_factor_tau, params_.pressure_factor_sigma, 0);
//GM process that would do random walk for pressure factor
pressure_factor_.initialize(params_.pressure_factor_tau, params_.pressure_factor_sigma, 0);
uncorrelated_noise_ = RandomGeneratorGausianR(0.0f, params_.uncorrelated_noise_sigma);
//correlated_noise_.initialize(params_.correlated_noise_tau, params_.correlated_noise_sigma, 0.0f);
uncorrelated_noise_ = RandomGeneratorGausianR(0.0f, params_.uncorrelated_noise_sigma);
//correlated_noise_.initialize(params_.correlated_noise_tau, params_.correlated_noise_sigma, 0.0f);
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
delay_line_.initialize(params_.update_latency);
}
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
delay_line_.initialize(params_.update_latency);
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
pressure_factor_.reset();
//correlated_noise_.reset();
uncorrelated_noise_.reset();
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
pressure_factor_.reset();
//correlated_noise_.reset();
uncorrelated_noise_.reset();
freq_limiter_.reset();
delay_line_.reset();
freq_limiter_.reset();
delay_line_.reset();
delay_line_.push_back(getOutputInternal());
}
virtual void update() override
{
BarometerBase::update();
freq_limiter_.update();
if (freq_limiter_.isWaitComplete()) {
delay_line_.push_back(getOutputInternal());
}
delay_line_.update();
virtual void update() override
{
BarometerBase::update();
if (freq_limiter_.isWaitComplete())
setOutput(delay_line_.getOutput());
}
//*** End: UpdatableState implementation ***//
freq_limiter_.update();
virtual ~BarometerSimple() = default;
if (freq_limiter_.isWaitComplete()) {
delay_line_.push_back(getOutputInternal());
}
private: //methods
Output getOutputInternal()
{
Output output;
const GroundTruth& ground_truth = getGroundTruth();
delay_line_.update();
auto altitude = ground_truth.environment->getState().geo_point.altitude;
auto pressure = EarthUtils::getStandardPressure(altitude);
if (freq_limiter_.isWaitComplete())
setOutput(delay_line_.getOutput());
}
//*** End: UpdatableState implementation ***//
//add drift in pressure, about 10m change per hour using default settings.
pressure_factor_.update();
pressure += pressure * pressure_factor_.getOutput();
virtual ~BarometerSimple() = default;
//add noise in pressure (about 0.2m sigma)
pressure += uncorrelated_noise_.next();
private: //methods
Output getOutputInternal()
{
Output output;
const GroundTruth& ground_truth = getGroundTruth();
output.pressure = pressure - EarthUtils::SeaLevelPressure + params_.qnh*100.0f;
auto altitude = ground_truth.environment->getState().geo_point.altitude;
auto pressure = EarthUtils::getStandardPressure(altitude);
//apply altimeter formula
//https://en.wikipedia.org/wiki/Pressure_altitude
//TODO: use same formula as in driver code?
output.altitude = (1 - pow(pressure / EarthUtils::SeaLevelPressure, 0.190284f)) * 145366.45f * 0.3048f;
output.qnh = params_.qnh;
//add drift in pressure, about 10m change per hour using default settings.
pressure_factor_.update();
pressure += pressure * pressure_factor_.getOutput();
output.time_stamp = clock()->nowNanos();
//add noise in pressure (about 0.2m sigma)
pressure += uncorrelated_noise_.next();
return output;
}
private:
BarometerSimpleParams params_;
output.pressure = pressure - EarthUtils::SeaLevelPressure + params_.qnh * 100.0f;
GaussianMarkov pressure_factor_;
//GaussianMarkov correlated_noise_;
RandomGeneratorGausianR uncorrelated_noise_;
//apply altimeter formula
//https://en.wikipedia.org/wiki/Pressure_altitude
//TODO: use same formula as in driver code?
output.altitude = (1 - pow(pressure / EarthUtils::SeaLevelPressure, 0.190284f)) * 145366.45f * 0.3048f;
output.qnh = params_.qnh;
FrequencyLimiter freq_limiter_;
DelayLine<Output> delay_line_;
};
output.time_stamp = clock()->nowNanos();
}} //namespace
#endif
return output;
}
private:
BarometerSimpleParams params_;
GaussianMarkov pressure_factor_;
//GaussianMarkov correlated_noise_;
RandomGeneratorGausianR uncorrelated_noise_;
FrequencyLimiter freq_limiter_;
DelayLine<Output> delay_line_;
};
}
} //namespace
#endif

Просмотреть файл

@ -7,26 +7,27 @@
#include "common/Common.hpp"
#include "common/AirSimSettings.hpp"
namespace msr { namespace airlib {
struct BarometerSimpleParams
namespace msr
{
namespace airlib
{
//user specified sea level pressure is specified in hPa units
real_T qnh = EarthUtils::SeaLevelPressure / 100.0f; // hPa
//sea level min,avh,max = 950,1013,1050 ie approx 3.65% variation
//regular pressure changes in quiet conditions are taken as 1/20th of this
//Mariner's Pressure Atlas, David Burch, 2014
//GM process may generate ~70% of sigma in tau interval
//This means below config may produce ~10m variance per hour
struct BarometerSimpleParams
{
//user specified sea level pressure is specified in hPa units
real_T qnh = EarthUtils::SeaLevelPressure / 100.0f; // hPa
//https://www.starpath.com/ebooksamples/9780914025382_sample.pdf
real_T pressure_factor_sigma = 0.0365f / 20;
real_T pressure_factor_tau = 3600;
//sea level min,avh,max = 950,1013,1050 ie approx 3.65% variation
//regular pressure changes in quiet conditions are taken as 1/20th of this
//Mariner's Pressure Atlas, David Burch, 2014
//GM process may generate ~70% of sigma in tau interval
//This means below config may produce ~10m variance per hour
/*
//https://www.starpath.com/ebooksamples/9780914025382_sample.pdf
real_T pressure_factor_sigma = 0.0365f / 20;
real_T pressure_factor_tau = 3600;
/*
Ref: A Stochastic Approach to Noise Modeling for Barometric Altimeters
Angelo Maria Sabatini* and Vincenzo Genovese
Sample values are from Table 1
@ -38,29 +39,28 @@ struct BarometerSimpleParams
real_T uncorrelated_noise_sigma = 0.24f;
*/
//Experiments for MEAS MS56112 sensor shows 0.021mbar, datasheet has resoultion of 0.027mbar @ 1024
//http://www.te.com/commerce/DocumentDelivery/DDEController?Action=srchrtrv&DocNm=MS5611-01BA03&DocType=Data+Sheet&DocLang=English
real_T uncorrelated_noise_sigma = 0.027f * 100;
//jMavSim uses below
//real_T uncorrelated_noise_sigma = 0.1f;
//Experiments for MEAS MS56112 sensor shows 0.021mbar, datasheet has resoultion of 0.027mbar @ 1024
//http://www.te.com/commerce/DocumentDelivery/DDEController?Action=srchrtrv&DocNm=MS5611-01BA03&DocType=Data+Sheet&DocLang=English
real_T uncorrelated_noise_sigma = 0.027f * 100;
//jMavSim uses below
//real_T uncorrelated_noise_sigma = 0.1f;
//see PX4 param reference for EKF: https://dev.px4.io/en/advanced/parameter_reference.html
real_T update_latency = 0.0f; //sec
real_T update_frequency = 50; //Hz
real_T startup_delay = 0; //sec
//see PX4 param reference for EKF: https://dev.px4.io/en/advanced/parameter_reference.html
real_T update_latency = 0.0f; //sec
real_T update_frequency = 50; //Hz
real_T startup_delay = 0; //sec
void initializeFromSettings(const AirSimSettings::BarometerSetting& settings)
{
const auto& json = settings.settings;
pressure_factor_sigma = json.getFloat("PressureFactorSigma", pressure_factor_sigma);
pressure_factor_tau = json.getFloat("PressureFactorTau", pressure_factor_tau);
uncorrelated_noise_sigma = json.getFloat("UncorrelatedNoiseSigma", uncorrelated_noise_sigma);
update_latency = json.getFloat("UpdateLatency", update_latency);
update_frequency = json.getFloat("UpdateFrequency", update_frequency);
startup_delay = json.getFloat("StartupDelay", startup_delay);
}
};
}} //namespace
void initializeFromSettings(const AirSimSettings::BarometerSetting& settings)
{
const auto& json = settings.settings;
pressure_factor_sigma = json.getFloat("PressureFactorSigma", pressure_factor_sigma);
pressure_factor_tau = json.getFloat("PressureFactorTau", pressure_factor_tau);
uncorrelated_noise_sigma = json.getFloat("UncorrelatedNoiseSigma", uncorrelated_noise_sigma);
update_latency = json.getFloat("UpdateLatency", update_latency);
update_frequency = json.getFloat("UpdateFrequency", update_frequency);
startup_delay = json.getFloat("StartupDelay", startup_delay);
}
};
}
} //namespace
#endif

Просмотреть файл

@ -4,43 +4,44 @@
#ifndef msr_airlib_DistanceBase_hpp
#define msr_airlib_DistanceBase_hpp
#include "sensors/SensorBase.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class DistanceBase : public SensorBase {
public:
DistanceBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{}
public:
virtual void reportState(StateReporter& reporter) override
class DistanceBase : public SensorBase
{
//call base
UpdatableObject::reportState(reporter);
public:
DistanceBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{
}
reporter.writeValue("Dist-Curr", output_.distance);
}
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
const DistanceSensorData& getOutput() const
{
return output_;
}
reporter.writeValue("Dist-Curr", output_.distance);
}
protected:
void setOutput(const DistanceSensorData& output)
{
output_ = output;
}
const DistanceSensorData& getOutput() const
{
return output_;
}
protected:
void setOutput(const DistanceSensorData& output)
{
output_ = output;
}
private:
DistanceSensorData output_;
};
}} //namespace
private:
DistanceSensorData output_;
};
}
} //namespace
#endif

Просмотреть файл

@ -12,97 +12,99 @@
#include "common/DelayLine.hpp"
#include "common/FrequencyLimiter.hpp"
namespace msr { namespace airlib {
class DistanceSimple : public DistanceBase
namespace msr
{
public:
DistanceSimple(const AirSimSettings::DistanceSetting& setting = AirSimSettings::DistanceSetting())
: DistanceBase(setting.sensor_name)
namespace airlib
{
class DistanceSimple : public DistanceBase
{
// initialize params
params_.initializeFromSettings(setting);
public:
DistanceSimple(const AirSimSettings::DistanceSetting& setting = AirSimSettings::DistanceSetting())
: DistanceBase(setting.sensor_name)
{
// initialize params
params_.initializeFromSettings(setting);
uncorrelated_noise_ = RandomGeneratorGausianR(0.0f, params_.uncorrelated_noise_sigma);
//correlated_noise_.initialize(params_.correlated_noise_tau, params_.correlated_noise_sigma, 0.0f);
uncorrelated_noise_ = RandomGeneratorGausianR(0.0f, params_.uncorrelated_noise_sigma);
//correlated_noise_.initialize(params_.correlated_noise_tau, params_.correlated_noise_sigma, 0.0f);
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
delay_line_.initialize(params_.update_latency);
}
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
delay_line_.initialize(params_.update_latency);
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
//correlated_noise_.reset();
uncorrelated_noise_.reset();
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
//correlated_noise_.reset();
uncorrelated_noise_.reset();
freq_limiter_.reset();
delay_line_.reset();
freq_limiter_.reset();
delay_line_.reset();
delay_line_.push_back(getOutputInternal());
}
virtual void update() override
{
DistanceBase::update();
freq_limiter_.update();
if (freq_limiter_.isWaitComplete()) {
delay_line_.push_back(getOutputInternal());
}
delay_line_.update();
virtual void update() override
{
DistanceBase::update();
if (freq_limiter_.isWaitComplete())
setOutput(delay_line_.getOutput());
}
//*** End: UpdatableState implementation ***//
freq_limiter_.update();
virtual ~DistanceSimple() = default;
if (freq_limiter_.isWaitComplete()) {
delay_line_.push_back(getOutputInternal());
}
const DistanceSimpleParams& getParams() const
{
return params_;
}
delay_line_.update();
protected:
virtual real_T getRayLength(const Pose& pose) = 0;
if (freq_limiter_.isWaitComplete())
setOutput(delay_line_.getOutput());
}
//*** End: UpdatableState implementation ***//
private: //methods
DistanceSensorData getOutputInternal()
{
DistanceSensorData output;
const GroundTruth& ground_truth = getGroundTruth();
virtual ~DistanceSimple() = default;
//order of Pose addition is important here because it also adds quaternions which is not commutative!
auto distance = getRayLength(params_.relative_pose + ground_truth.kinematics->pose);
const DistanceSimpleParams& getParams() const
{
return params_;
}
//add noise in distance (about 0.2m sigma)
distance += uncorrelated_noise_.next();
protected:
virtual real_T getRayLength(const Pose& pose) = 0;
output.distance = distance;
output.min_distance = params_.min_distance;
output.max_distance = params_.max_distance;
output.relative_pose = params_.relative_pose;
output.time_stamp = clock()->nowNanos();
private: //methods
DistanceSensorData getOutputInternal()
{
DistanceSensorData output;
const GroundTruth& ground_truth = getGroundTruth();
return output;
}
//order of Pose addition is important here because it also adds quaternions which is not commutative!
auto distance = getRayLength(params_.relative_pose + ground_truth.kinematics->pose);
private:
DistanceSimpleParams params_;
//add noise in distance (about 0.2m sigma)
distance += uncorrelated_noise_.next();
//GaussianMarkov correlated_noise_;
RandomGeneratorGausianR uncorrelated_noise_;
output.distance = distance;
output.min_distance = params_.min_distance;
output.max_distance = params_.max_distance;
output.relative_pose = params_.relative_pose;
output.time_stamp = clock()->nowNanos();
FrequencyLimiter freq_limiter_;
DelayLine<DistanceSensorData> delay_line_;
return output;
}
//start time
};
private:
DistanceSimpleParams params_;
}} //namespace
//GaussianMarkov correlated_noise_;
RandomGeneratorGausianR uncorrelated_noise_;
FrequencyLimiter freq_limiter_;
DelayLine<DistanceSensorData> delay_line_;
//start time
};
}
} //namespace
#endif

Просмотреть файл

@ -7,24 +7,25 @@
#include "common/Common.hpp"
#include "common/AirSimSettings.hpp"
namespace msr { namespace airlib {
struct DistanceSimpleParams
namespace msr
{
namespace airlib
{
real_T min_distance = 20.0f / 100; //m
real_T max_distance = 4000.0f / 100; //m
Pose relative_pose {
Vector3r(0,0,-1), // position - a little above vehicle (especially for cars) or Vector3r::Zero()
Quaternionr::Identity() // orientation - by default Quaternionr(1, 0, 0, 0)
};
struct DistanceSimpleParams
{
real_T min_distance = 20.0f / 100; //m
real_T max_distance = 4000.0f / 100; //m
bool draw_debug_points = false;
bool external_controller = true;
Pose relative_pose{
Vector3r(0, 0, -1), // position - a little above vehicle (especially for cars) or Vector3r::Zero()
Quaternionr::Identity() // orientation - by default Quaternionr(1, 0, 0, 0)
};
/*
bool draw_debug_points = false;
bool external_controller = true;
/*
Ref: A Stochastic Approach to Noise Modeling for Barometric Altimeters
Angelo Maria Sabatini* and Vincenzo Genovese
Sample values are from Table 1
@ -36,52 +37,51 @@ struct DistanceSimpleParams
real_T uncorrelated_noise_sigma = 0.24f;
*/
//TODO: update sigma based on documentation, maybe as a function increasing with measured distance
real_T uncorrelated_noise_sigma = 0.002f * 100;
//jMavSim uses below
//real_T uncorrelated_noise_sigma = 0.1f;
//TODO: update sigma based on documentation, maybe as a function increasing with measured distance
real_T uncorrelated_noise_sigma = 0.002f * 100;
//jMavSim uses below
//real_T uncorrelated_noise_sigma = 0.1f;
//see PX4 param reference for EKF: https://dev.px4.io/en/advanced/parameter_reference.html
real_T update_latency = 0.0f; //sec
real_T update_frequency = 50; //Hz
real_T startup_delay = 0; //sec
//see PX4 param reference for EKF: https://dev.px4.io/en/advanced/parameter_reference.html
real_T update_latency = 0.0f; //sec
real_T update_frequency = 50; //Hz
real_T startup_delay = 0; //sec
void initializeFromSettings(const AirSimSettings::DistanceSetting& settings)
{
const auto& settings_json = settings.settings;
min_distance = settings_json.getFloat("MinDistance", min_distance);
max_distance = settings_json.getFloat("MaxDistance", max_distance);
draw_debug_points = settings_json.getBool("DrawDebugPoints", draw_debug_points);
external_controller = settings_json.getBool("ExternalController", external_controller);
void initializeFromSettings(const AirSimSettings::DistanceSetting& settings)
{
const auto& settings_json = settings.settings;
min_distance = settings_json.getFloat("MinDistance", min_distance);
max_distance = settings_json.getFloat("MaxDistance", max_distance);
draw_debug_points = settings_json.getBool("DrawDebugPoints", draw_debug_points);
external_controller = settings_json.getBool("ExternalController", external_controller);
auto position = AirSimSettings::createVectorSetting(settings_json, VectorMath::nanVector());
auto rotation = AirSimSettings::createRotationSetting(settings_json, AirSimSettings::Rotation::nanRotation());
auto position = AirSimSettings::createVectorSetting(settings_json, VectorMath::nanVector());
auto rotation = AirSimSettings::createRotationSetting(settings_json, AirSimSettings::Rotation::nanRotation());
std::string simmode_name = AirSimSettings::singleton().simmode_name;
std::string simmode_name = AirSimSettings::singleton().simmode_name;
relative_pose.position = position;
if (std::isnan(relative_pose.position.x()))
relative_pose.position.x() = 0;
if (std::isnan(relative_pose.position.y()))
relative_pose.position.y() = 0;
if (std::isnan(relative_pose.position.z())) {
if (simmode_name == AirSimSettings::kSimModeTypeMultirotor)
relative_pose.position.z() = 0;
else
relative_pose.position.z() = -1; // a little bit above for cars
relative_pose.position = position;
if (std::isnan(relative_pose.position.x()))
relative_pose.position.x() = 0;
if (std::isnan(relative_pose.position.y()))
relative_pose.position.y() = 0;
if (std::isnan(relative_pose.position.z())) {
if (simmode_name == AirSimSettings::kSimModeTypeMultirotor)
relative_pose.position.z() = 0;
else
relative_pose.position.z() = -1; // a little bit above for cars
}
float pitch, roll, yaw;
pitch = !std::isnan(rotation.pitch) ? rotation.pitch : 0;
roll = !std::isnan(rotation.roll) ? rotation.roll : 0;
yaw = !std::isnan(rotation.yaw) ? rotation.yaw : 0;
relative_pose.orientation = VectorMath::toQuaternion(
Utils::degreesToRadians(pitch), //pitch - rotation around Y axis
Utils::degreesToRadians(roll), //roll - rotation around X axis
Utils::degreesToRadians(yaw)); //yaw - rotation around Z axis
}
float pitch, roll, yaw;
pitch = !std::isnan(rotation.pitch) ? rotation.pitch : 0;
roll = !std::isnan(rotation.roll) ? rotation.roll : 0;
yaw = !std::isnan(rotation.yaw) ? rotation.yaw : 0;
relative_pose.orientation = VectorMath::toQuaternion(
Utils::degreesToRadians(pitch), //pitch - rotation around Y axis
Utils::degreesToRadians(roll), //roll - rotation around X axis
Utils::degreesToRadians(yaw)); //yaw - rotation around Z axis
}
};
}} //namespace
};
}
} //namespace
#endif

Просмотреть файл

@ -4,126 +4,137 @@
#ifndef msr_airlib_GpsBase_hpp
#define msr_airlib_GpsBase_hpp
#include "sensors/SensorBase.hpp"
#include "common/CommonStructs.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class GpsBase : public SensorBase {
public:
GpsBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{}
public: //types
//TODO: cleanup GPS structures that are not needed
struct GpsPoint {
public:
double latitude, longitude;
float height, altitude;
int health;
GpsPoint()
{}
GpsPoint(double latitude_val, double longitude_val, float altitude_val, int health_val = -1, float height_val = std::numeric_limits<float>::quiet_NaN())
class GpsBase : public SensorBase
{
public:
GpsBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{
latitude = latitude_val; longitude = longitude_val;
height = height_val, altitude = altitude_val;
health = health_val;
}
string to_string()
public: //types
//TODO: cleanup GPS structures that are not needed
struct GpsPoint
{
return Utils::stringf("latitude=%f, longitude=%f, altitude=%f, height=%f, health=%d", latitude, longitude, altitude, height, health);
public:
double latitude, longitude;
float height, altitude;
int health;
GpsPoint()
{
}
GpsPoint(double latitude_val, double longitude_val, float altitude_val, int health_val = -1, float height_val = std::numeric_limits<float>::quiet_NaN())
{
latitude = latitude_val;
longitude = longitude_val;
height = height_val, altitude = altitude_val;
health = health_val;
}
string to_string()
{
return Utils::stringf("latitude=%f, longitude=%f, altitude=%f, height=%f, health=%d", latitude, longitude, altitude, height, health);
}
};
enum NavSatStatusType : char
{
STATUS_NO_FIX = 80, //unable to fix position
STATUS_FIX = 0, //unaugmented fix
STATUS_SBAS_FIX = 1, //with satellite-based augmentation
STATUS_GBAS_FIX = 2 //with ground-based augmentation
};
enum NavSatStatusServiceType : unsigned short int
{
SERVICE_GPS = 1,
SERVICE_GLONASS = 2,
SERVICE_COMPASS = 4, //includes BeiDou.
SERVICE_GALILEO = 8
};
struct NavSatStatus
{
NavSatStatusType status;
NavSatStatusServiceType service;
};
enum PositionCovarianceType : unsigned char
{
COVARIANCE_TYPE_UNKNOWN = 0,
COVARIANCE_TYPE_APPROXIMATED = 1,
COVARIANCE_TYPE_DIAGONAL_KNOWN = 2,
COVARIANCE_TYPE_KNOWN = 3
};
enum GnssFixType : unsigned char
{
GNSS_FIX_NO_FIX = 0,
GNSS_FIX_TIME_ONLY = 1,
GNSS_FIX_2D_FIX = 2,
GNSS_FIX_3D_FIX = 3
};
struct GnssReport
{
GeoPoint geo_point;
real_T eph, epv; //GPS HDOP/VDOP horizontal/vertical dilution of position (unitless), 0-100%
Vector3r velocity;
GnssFixType fix_type;
uint64_t time_utc = 0;
};
struct NavSatFix
{
GeoPoint geo_point;
double position_covariance[9] = {};
NavSatStatus status;
PositionCovarianceType position_covariance_type;
};
struct Output
{ //same as ROS message
TTimePoint time_stamp;
GnssReport gnss;
bool is_valid = false;
};
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("GPS-Loc", output_.gnss.geo_point);
reporter.writeValue("GPS-Vel", output_.gnss.velocity);
reporter.writeValue("GPS-Eph", output_.gnss.eph);
reporter.writeValue("GPS-Epv", output_.gnss.epv);
}
const Output& getOutput() const
{
return output_;
}
protected:
void setOutput(const Output& output)
{
output_ = output;
}
private:
Output output_;
};
enum NavSatStatusType : char {
STATUS_NO_FIX = 80, //unable to fix position
STATUS_FIX = 0, //unaugmented fix
STATUS_SBAS_FIX = 1, //with satellite-based augmentation
STATUS_GBAS_FIX = 2 //with ground-based augmentation
};
enum NavSatStatusServiceType : unsigned short int {
SERVICE_GPS = 1,
SERVICE_GLONASS = 2,
SERVICE_COMPASS = 4, //includes BeiDou.
SERVICE_GALILEO = 8
};
struct NavSatStatus {
NavSatStatusType status;
NavSatStatusServiceType service;
};
enum PositionCovarianceType : unsigned char {
COVARIANCE_TYPE_UNKNOWN = 0,
COVARIANCE_TYPE_APPROXIMATED = 1,
COVARIANCE_TYPE_DIAGONAL_KNOWN = 2,
COVARIANCE_TYPE_KNOWN = 3
};
enum GnssFixType : unsigned char {
GNSS_FIX_NO_FIX = 0,
GNSS_FIX_TIME_ONLY = 1,
GNSS_FIX_2D_FIX = 2,
GNSS_FIX_3D_FIX = 3
};
struct GnssReport {
GeoPoint geo_point;
real_T eph, epv; //GPS HDOP/VDOP horizontal/vertical dilution of position (unitless), 0-100%
Vector3r velocity;
GnssFixType fix_type;
uint64_t time_utc = 0;
};
struct NavSatFix {
GeoPoint geo_point;
double position_covariance[9] = {};
NavSatStatus status;
PositionCovarianceType position_covariance_type;
};
struct Output { //same as ROS message
TTimePoint time_stamp;
GnssReport gnss;
bool is_valid = false;
};
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("GPS-Loc", output_.gnss.geo_point);
reporter.writeValue("GPS-Vel", output_.gnss.velocity);
reporter.writeValue("GPS-Eph", output_.gnss.eph);
reporter.writeValue("GPS-Epv", output_.gnss.epv);
}
const Output& getOutput() const
{
return output_;
}
protected:
void setOutput(const Output& output)
{
output_ = output;
}
private:
Output output_;
};
}} //namespace
#endif
}
} //namespace
#endif

Просмотреть файл

@ -12,94 +12,96 @@
#include "common/FrequencyLimiter.hpp"
#include "common/DelayLine.hpp"
namespace msr { namespace airlib {
class GpsSimple : public GpsBase
namespace msr
{
public: //methods
GpsSimple(const AirSimSettings::GpsSetting& setting = AirSimSettings::GpsSetting())
: GpsBase(setting.sensor_name)
namespace airlib
{
class GpsSimple : public GpsBase
{
// initialize params
params_.initializeFromSettings(setting);
public: //methods
GpsSimple(const AirSimSettings::GpsSetting& setting = AirSimSettings::GpsSetting())
: GpsBase(setting.sensor_name)
{
// initialize params
params_.initializeFromSettings(setting);
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
delay_line_.initialize(params_.update_latency);
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
delay_line_.initialize(params_.update_latency);
//initialize filters
eph_filter.initialize(params_.eph_time_constant, params_.eph_final, params_.eph_initial); //starting dilution set to 100 which we will reduce over time to targeted 0.3f, with 45% accuracy within 100 updates, each update occurring at 0.2s interval
epv_filter.initialize(params_.epv_time_constant, params_.epv_final, params_.epv_initial);
}
//initialize filters
eph_filter.initialize(params_.eph_time_constant, params_.eph_final, params_.eph_initial); //starting dilution set to 100 which we will reduce over time to targeted 0.3f, with 45% accuracy within 100 updates, each update occurring at 0.2s interval
epv_filter.initialize(params_.epv_time_constant, params_.epv_final, params_.epv_initial);
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
freq_limiter_.reset();
delay_line_.reset();
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
freq_limiter_.reset();
delay_line_.reset();
eph_filter.reset();
epv_filter.reset();
eph_filter.reset();
epv_filter.reset();
addOutputToDelayLine(eph_filter.getOutput(), epv_filter.getOutput());
}
virtual void update() override
{
GpsBase::update();
freq_limiter_.update();
eph_filter.update();
epv_filter.update();
if (freq_limiter_.isWaitComplete()) { //update output
addOutputToDelayLine(eph_filter.getOutput(), epv_filter.getOutput());
}
delay_line_.update();
virtual void update() override
{
GpsBase::update();
if (freq_limiter_.isWaitComplete())
setOutput(delay_line_.getOutput());
}
freq_limiter_.update();
eph_filter.update();
epv_filter.update();
//*** End: UpdatableState implementation ***//
if (freq_limiter_.isWaitComplete()) { //update output
addOutputToDelayLine(eph_filter.getOutput(), epv_filter.getOutput());
}
virtual ~GpsSimple() = default;
private:
void addOutputToDelayLine(real_T eph, real_T epv)
{
Output output;
const GroundTruth& ground_truth = getGroundTruth();
delay_line_.update();
//GNSS
output.gnss.time_utc = static_cast<uint64_t>(clock()->nowNanos() / 1.0E3);
output.gnss.geo_point = ground_truth.environment->getState().geo_point;
output.gnss.eph = eph;
output.gnss.epv = epv;
output.gnss.velocity = ground_truth.kinematics->twist.linear;
output.is_valid = true;
if (freq_limiter_.isWaitComplete())
setOutput(delay_line_.getOutput());
}
output.gnss.fix_type =
output.gnss.eph <= params_.eph_min_3d ? GnssFixType::GNSS_FIX_3D_FIX
: output.gnss.eph <= params_.eph_min_2d ? GnssFixType::GNSS_FIX_2D_FIX
: GnssFixType::GNSS_FIX_NO_FIX;
//*** End: UpdatableState implementation ***//
output.time_stamp = clock()->nowNanos();
virtual ~GpsSimple() = default;
delay_line_.push_back(output);
}
private:
void addOutputToDelayLine(real_T eph, real_T epv)
{
Output output;
const GroundTruth& ground_truth = getGroundTruth();
//GNSS
output.gnss.time_utc = static_cast<uint64_t>(clock()->nowNanos() / 1.0E3);
output.gnss.geo_point = ground_truth.environment->getState().geo_point;
output.gnss.eph = eph;
output.gnss.epv = epv;
output.gnss.velocity = ground_truth.kinematics->twist.linear;
output.is_valid = true;
private:
typedef std::normal_distribution<> NormalDistribution;
output.gnss.fix_type =
output.gnss.eph <= params_.eph_min_3d ? GnssFixType::GNSS_FIX_3D_FIX
: output.gnss.eph <= params_.eph_min_2d ? GnssFixType::GNSS_FIX_2D_FIX
: GnssFixType::GNSS_FIX_NO_FIX;
GpsSimpleParams params_;
output.time_stamp = clock()->nowNanos();
FirstOrderFilter<real_T> eph_filter, epv_filter;
FrequencyLimiter freq_limiter_;
DelayLine<Output> delay_line_;
};
delay_line_.push_back(output);
}
}} //namespace
private:
typedef std::normal_distribution<> NormalDistribution;
GpsSimpleParams params_;
FirstOrderFilter<real_T> eph_filter, epv_filter;
FrequencyLimiter freq_limiter_;
DelayLine<Output> delay_line_;
};
}
} //namespace
#endif

Просмотреть файл

@ -6,36 +6,38 @@
#include "common/Common.hpp"
namespace msr { namespace airlib {
struct GpsSimpleParams
namespace msr
{
namespace airlib
{
real_T eph_time_constant = 0.9f, epv_time_constant = 0.9f;
real_T eph_initial = 100.0f, epv_initial = 100.0f; //initially fully diluted positions
real_T eph_final = 0.1f, epv_final = 0.1f; // PX4 won't converge GPS sensor fusion until we get to 10% accuracty.
real_T eph_min_3d = 3.0f, eph_min_2d = 4.0f;
real_T update_latency = 0.2f; //sec
real_T update_frequency = 50; //Hz
real_T startup_delay = 1; //sec
void initializeFromSettings(const AirSimSettings::GpsSetting& settings)
struct GpsSimpleParams
{
const auto& json = settings.settings;
eph_time_constant = json.getFloat("EPH_TimeConstant", eph_time_constant);
epv_time_constant = json.getFloat("EPV_TimeConstant", epv_time_constant);
eph_initial = json.getFloat("EphInitial", eph_initial);
epv_initial = json.getFloat("EpvInitial", epv_initial);
eph_final = json.getFloat("EphFinal", eph_final);
epv_final = json.getFloat("EpvFinal", epv_final);
eph_min_3d = json.getFloat("EphMin3d", eph_min_3d);
eph_min_2d = json.getFloat("EphMin2d", eph_min_2d);
update_latency = json.getFloat("UpdateLatency", update_latency);
update_frequency = json.getFloat("UpdateFrequency", update_frequency);
startup_delay = json.getFloat("StartupDelay", startup_delay);
}
};
real_T eph_time_constant = 0.9f, epv_time_constant = 0.9f;
real_T eph_initial = 100.0f, epv_initial = 100.0f; //initially fully diluted positions
real_T eph_final = 0.1f, epv_final = 0.1f; // PX4 won't converge GPS sensor fusion until we get to 10% accuracty.
real_T eph_min_3d = 3.0f, eph_min_2d = 4.0f;
}} //namespace
real_T update_latency = 0.2f; //sec
real_T update_frequency = 50; //Hz
real_T startup_delay = 1; //sec
void initializeFromSettings(const AirSimSettings::GpsSetting& settings)
{
const auto& json = settings.settings;
eph_time_constant = json.getFloat("EPH_TimeConstant", eph_time_constant);
epv_time_constant = json.getFloat("EPV_TimeConstant", epv_time_constant);
eph_initial = json.getFloat("EphInitial", eph_initial);
epv_initial = json.getFloat("EpvInitial", epv_initial);
eph_final = json.getFloat("EphFinal", eph_final);
epv_final = json.getFloat("EpvFinal", epv_final);
eph_min_3d = json.getFloat("EphMin3d", eph_min_3d);
eph_min_2d = json.getFloat("EphMin2d", eph_min_2d);
update_latency = json.getFloat("UpdateLatency", update_latency);
update_frequency = json.getFloat("UpdateFrequency", update_frequency);
startup_delay = json.getFloat("StartupDelay", startup_delay);
}
};
}
} //namespace
#endif

Просмотреть файл

@ -4,54 +4,55 @@
#ifndef msr_airlib_ImuBase_hpp
#define msr_airlib_ImuBase_hpp
#include "sensors/SensorBase.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class ImuBase : public SensorBase
{
public:
ImuBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{
}
class ImuBase : public SensorBase {
public:
ImuBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{}
public: //types
struct Output
{ //structure is same as ROS IMU message
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
TTimePoint time_stamp;
Quaternionr orientation;
Vector3r angular_velocity;
Vector3r linear_acceleration;
};
public: //types
struct Output { //structure is same as ROS IMU message
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
TTimePoint time_stamp;
Quaternionr orientation;
Vector3r angular_velocity;
Vector3r linear_acceleration;
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("IMU-Ang", output_.angular_velocity);
reporter.writeValue("IMU-Lin", output_.linear_acceleration);
}
const Output& getOutput() const
{
return output_;
}
protected:
void setOutput(const Output& output)
{
output_ = output;
}
private:
Output output_;
};
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("IMU-Ang", output_.angular_velocity);
reporter.writeValue("IMU-Lin", output_.linear_acceleration);
}
const Output& getOutput() const
{
return output_;
}
protected:
void setOutput(const Output& output)
{
output_ = output;
}
private:
Output output_;
};
}} //namespace
#endif
}
} //namespace
#endif

Просмотреть файл

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef msr_airlib_SimpleImu_hpp
#define msr_airlib_SimpleImu_hpp
@ -9,108 +8,111 @@
#include "ImuSimpleParams.hpp"
#include "ImuBase.hpp"
namespace msr { namespace airlib {
class ImuSimple : public ImuBase
namespace msr
{
public:
//constructors
ImuSimple(const AirSimSettings::ImuSetting& setting = AirSimSettings::ImuSetting())
: ImuBase(setting.sensor_name)
namespace airlib
{
class ImuSimple : public ImuBase
{
// initialize params
params_.initializeFromSettings(setting);
public:
//constructors
ImuSimple(const AirSimSettings::ImuSetting& setting = AirSimSettings::ImuSetting())
: ImuBase(setting.sensor_name)
{
// initialize params
params_.initializeFromSettings(setting);
gyro_bias_stability_norm = params_.gyro.bias_stability / sqrt(params_.gyro.tau);
accel_bias_stability_norm = params_.accel.bias_stability / sqrt(params_.accel.tau);
}
gyro_bias_stability_norm = params_.gyro.bias_stability / sqrt(params_.gyro.tau);
accel_bias_stability_norm = params_.accel.bias_stability / sqrt(params_.accel.tau);
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
last_time_ = clock()->nowNanos();
state_.gyroscope_bias = params_.gyro.turn_on_bias;
state_.accelerometer_bias = params_.accel.turn_on_bias;
gauss_dist.reset();
updateOutput();
}
state_.gyroscope_bias = params_.gyro.turn_on_bias;
state_.accelerometer_bias = params_.accel.turn_on_bias;
gauss_dist.reset();
updateOutput();
}
virtual void update() override
{
ImuBase::update();
virtual void update() override
{
ImuBase::update();
updateOutput();
}
//*** End: UpdatableState implementation ***//
updateOutput();
}
//*** End: UpdatableState implementation ***//
virtual ~ImuSimple() = default;
virtual ~ImuSimple() = default;
private: //methods
void updateOutput()
{
Output output;
const GroundTruth& ground_truth = getGroundTruth();
private: //methods
void updateOutput()
{
Output output;
const GroundTruth& ground_truth = getGroundTruth();
output.angular_velocity = ground_truth.kinematics->twist.angular;
output.linear_acceleration = ground_truth.kinematics->accelerations.linear - ground_truth.environment->getState().gravity;
output.orientation = ground_truth.kinematics->pose.orientation;
output.angular_velocity = ground_truth.kinematics->twist.angular;
output.linear_acceleration = ground_truth.kinematics->accelerations.linear - ground_truth.environment->getState().gravity;
output.orientation = ground_truth.kinematics->pose.orientation;
//acceleration is in world frame so transform to body frame
output.linear_acceleration = VectorMath::transformToBodyFrame(output.linear_acceleration,
ground_truth.kinematics->pose.orientation, true);
//acceleration is in world frame so transform to body frame
output.linear_acceleration = VectorMath::transformToBodyFrame(output.linear_acceleration,
ground_truth.kinematics->pose.orientation,
true);
//add noise
addNoise(output.linear_acceleration, output.angular_velocity);
// TODO: Add noise in orientation?
//add noise
addNoise(output.linear_acceleration, output.angular_velocity);
// TODO: Add noise in orientation?
output.time_stamp = clock()->nowNanos();
output.time_stamp = clock()->nowNanos();
setOutput(output);
}
setOutput(output);
}
void addNoise(Vector3r& linear_acceleration, Vector3r& angular_velocity)
{
TTimeDelta dt = clock()->updateSince(last_time_);
void addNoise(Vector3r& linear_acceleration, Vector3r& angular_velocity)
{
TTimeDelta dt = clock()->updateSince(last_time_);
//ref: An introduction to inertial navigation, Oliver J. Woodman, Sec 3.2, pp 10-12
//https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-696.pdf
//ref: An introduction to inertial navigation, Oliver J. Woodman, Sec 3.2, pp 10-12
//https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-696.pdf
real_T sqrt_dt = static_cast<real_T>(sqrt(std::max<TTimeDelta>(dt, params_.min_sample_time)));
real_T sqrt_dt = static_cast<real_T>(sqrt(std::max<TTimeDelta>(dt, params_.min_sample_time)));
// Gyrosocpe
//convert arw to stddev
real_T gyro_sigma_arw = params_.gyro.arw / sqrt_dt;
angular_velocity += gauss_dist.next() * gyro_sigma_arw + state_.gyroscope_bias;
//update bias random walk
real_T gyro_sigma_bias = gyro_bias_stability_norm * sqrt_dt;
state_.gyroscope_bias += gauss_dist.next() * gyro_sigma_bias;
// Gyrosocpe
//convert arw to stddev
real_T gyro_sigma_arw = params_.gyro.arw / sqrt_dt;
angular_velocity += gauss_dist.next() * gyro_sigma_arw + state_.gyroscope_bias;
//update bias random walk
real_T gyro_sigma_bias = gyro_bias_stability_norm * sqrt_dt;
state_.gyroscope_bias += gauss_dist.next() * gyro_sigma_bias;
//accelerometer
//convert vrw to stddev
real_T accel_sigma_vrw = params_.accel.vrw / sqrt_dt;
linear_acceleration += gauss_dist.next() * accel_sigma_vrw + state_.accelerometer_bias;
//update bias random walk
real_T accel_sigma_bias = accel_bias_stability_norm * sqrt_dt;
state_.accelerometer_bias += gauss_dist.next() * accel_sigma_bias;
}
//accelerometer
//convert vrw to stddev
real_T accel_sigma_vrw = params_.accel.vrw / sqrt_dt;
linear_acceleration += gauss_dist.next() * accel_sigma_vrw + state_.accelerometer_bias;
//update bias random walk
real_T accel_sigma_bias = accel_bias_stability_norm * sqrt_dt;
state_.accelerometer_bias += gauss_dist.next() * accel_sigma_bias;
}
private: //fields
ImuSimpleParams params_;
RandomVectorGaussianR gauss_dist = RandomVectorGaussianR(0, 1);
private: //fields
ImuSimpleParams params_;
RandomVectorGaussianR gauss_dist = RandomVectorGaussianR(0, 1);
//cached calculated values
real_T gyro_bias_stability_norm, accel_bias_stability_norm;
//cached calculated values
real_T gyro_bias_stability_norm, accel_bias_stability_norm;
struct State
{
Vector3r gyroscope_bias;
Vector3r accelerometer_bias;
} state_;
struct State {
Vector3r gyroscope_bias;
Vector3r accelerometer_bias;
} state_;
TTimePoint last_time_;
};
}} //namespace
TTimePoint last_time_;
};
}
} //namespace
#endif

Просмотреть файл

@ -9,15 +9,16 @@
#include "common/AirSimSettings.hpp"
#include <cmath>
namespace msr { namespace airlib {
// A description of the parameters:
// https://github.com/ethz-asl/kalibr/wiki/IMU-Noise-Model-and-Intrinsics
struct ImuSimpleParams
namespace msr
{
/* ref: Parameter values are for MPU 6000 IMU from InvenSense
namespace airlib
{
// A description of the parameters:
// https://github.com/ethz-asl/kalibr/wiki/IMU-Noise-Model-and-Intrinsics
struct ImuSimpleParams
{
/* ref: Parameter values are for MPU 6000 IMU from InvenSense
Design and Characterization of a Low Cost MEMS IMU Cluster for Precision Navigation
Daniel R. Greenheck, 2009, sec 2.2, pp 17
http://epublications.marquette.edu/cgi/viewcontent.cgi?article=1326&context=theses_open
@ -25,52 +26,51 @@ struct ImuSimpleParams
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf
For Allan Variance/Deviation plots see http://www.invensense.com/wp-content/uploads/2015/02/MPU-3300-Datasheet.pdf
*/
struct Gyroscope
{
//angular random walk (ARW)
real_T arw = 0.30f / sqrt(3600.0f) * M_PIf / 180; //deg/sqrt(hour) converted to rad/sqrt(sec)
//Bias Stability (tau = 500s)
real_T tau = 500;
real_T bias_stability = 4.6f / 3600 * M_PIf / 180; //deg/hr converted to rad/sec
Vector3r turn_on_bias = Vector3r::Zero(); //assume calibration is done
} gyro;
struct Gyroscope
{
//angular random walk (ARW)
real_T arw = 0.30f / sqrt(3600.0f) * M_PIf / 180; //deg/sqrt(hour) converted to rad/sqrt(sec)
//Bias Stability (tau = 500s)
real_T tau = 500;
real_T bias_stability = 4.6f / 3600 * M_PIf / 180; //deg/hr converted to rad/sec
Vector3r turn_on_bias = Vector3r::Zero(); //assume calibration is done
} gyro;
struct Accelerometer
{
//velocity random walk (ARW)
real_T vrw = 0.24f * EarthUtils::Gravity / 1.0E3f; //mg converted to m/s^2
//Bias Stability (tau = 800s)
real_T tau = 800;
real_T bias_stability = 36.0f * 1E-6f * EarthUtils::Gravity; //ug converted to m/s^2
Vector3r turn_on_bias = Vector3r::Zero(); //assume calibration is done
} accel;
struct Accelerometer
{
//velocity random walk (ARW)
real_T vrw = 0.24f * EarthUtils::Gravity / 1.0E3f; //mg converted to m/s^2
//Bias Stability (tau = 800s)
real_T tau = 800;
real_T bias_stability = 36.0f * 1E-6f * EarthUtils::Gravity; //ug converted to m/s^2
Vector3r turn_on_bias = Vector3r::Zero(); //assume calibration is done
} accel;
real_T min_sample_time = 1 / 1000.0f; //internal IMU frequency
real_T min_sample_time = 1 / 1000.0f; //internal IMU frequency
void initializeFromSettings(const AirSimSettings::ImuSetting& settings)
{
const auto& json = settings.settings;
float arw = json.getFloat("AngularRandomWalk", Utils::nan<float>());
if (!std::isnan(arw)) {
gyro.arw = arw / sqrt(3600.0f) * M_PIf / 180; // //deg/sqrt(hour) converted to rad/sqrt(sec)
void initializeFromSettings(const AirSimSettings::ImuSetting& settings)
{
const auto& json = settings.settings;
float arw = json.getFloat("AngularRandomWalk", Utils::nan<float>());
if (!std::isnan(arw)) {
gyro.arw = arw / sqrt(3600.0f) * M_PIf / 180; // //deg/sqrt(hour) converted to rad/sqrt(sec)
}
gyro.tau = json.getFloat("GyroBiasStabilityTau", gyro.tau);
float bias_stability = json.getFloat("GyroBiasStability", Utils::nan<float>());
if (!std::isnan(bias_stability)) {
gyro.bias_stability = bias_stability / 3600 * M_PIf / 180; //deg/hr converted to rad/sec
}
auto vrw = json.getFloat("VelocityRandomWalk", Utils::nan<float>());
if (!std::isnan(vrw)) {
accel.vrw = vrw * EarthUtils::Gravity / 1.0E3f; //mg converted to m/s^2
}
accel.tau = json.getFloat("AccelBiasStabilityTau", accel.tau);
bias_stability = json.getFloat("AccelBiasStability", Utils::nan<float>());
if (!std::isnan(bias_stability)) {
accel.bias_stability = bias_stability * 1E-6f * EarthUtils::Gravity; //ug converted to m/s^2
}
}
gyro.tau = json.getFloat("GyroBiasStabilityTau", gyro.tau);
float bias_stability = json.getFloat("GyroBiasStability", Utils::nan<float>());
if (!std::isnan(bias_stability)) {
gyro.bias_stability = bias_stability / 3600 * M_PIf / 180; //deg/hr converted to rad/sec
}
auto vrw = json.getFloat("VelocityRandomWalk", Utils::nan<float>());
if (!std::isnan(vrw)) {
accel.vrw = vrw * EarthUtils::Gravity / 1.0E3f; //mg converted to m/s^2
}
accel.tau = json.getFloat("AccelBiasStabilityTau", accel.tau);
bias_stability = json.getFloat("AccelBiasStability", Utils::nan<float>());
if (!std::isnan(bias_stability)) {
accel.bias_stability = bias_stability * 1E-6f * EarthUtils::Gravity; //ug converted to m/s^2
}
}
};
}} //namespace
};
}
} //namespace
#endif

Просмотреть файл

@ -6,38 +6,43 @@
#include "sensors/SensorBase.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class LidarBase : public SensorBase {
public:
LidarBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{}
public:
virtual void reportState(StateReporter& reporter) override
class LidarBase : public SensorBase
{
//call base
UpdatableObject::reportState(reporter);
public:
LidarBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{
}
reporter.writeValue("Lidar-Timestamp", output_.time_stamp);
reporter.writeValue("Lidar-NumPoints", static_cast<int>(output_.point_cloud.size() / 3));
}
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
const LidarData& getOutput() const
{
return output_;
}
reporter.writeValue("Lidar-Timestamp", output_.time_stamp);
reporter.writeValue("Lidar-NumPoints", static_cast<int>(output_.point_cloud.size() / 3));
}
protected:
void setOutput(const LidarData& output)
{
output_ = output;
}
const LidarData& getOutput() const
{
return output_;
}
private:
LidarData output_;
};
protected:
void setOutput(const LidarData& output)
{
output_ = output;
}
}} //namespace
private:
LidarData output_;
};
}
} //namespace
#endif

Просмотреть файл

@ -11,109 +11,110 @@
#include "common/DelayLine.hpp"
#include "common/FrequencyLimiter.hpp"
namespace msr { namespace airlib {
class LidarSimple : public LidarBase
namespace msr
{
public:
LidarSimple(const AirSimSettings::LidarSetting& setting = AirSimSettings::LidarSetting())
: LidarBase(setting.sensor_name)
namespace airlib
{
class LidarSimple : public LidarBase
{
// initialize params
params_.initializeFromSettings(setting);
public:
LidarSimple(const AirSimSettings::LidarSetting& setting = AirSimSettings::LidarSetting())
: LidarBase(setting.sensor_name)
{
// initialize params
params_.initializeFromSettings(setting);
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
}
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
}
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
freq_limiter_.reset();
last_time_ = clock()->nowNanos();
//*** Start: UpdatableState implementation ***//
virtual void resetImplementation() override
{
freq_limiter_.reset();
last_time_ = clock()->nowNanos();
updateOutput();
}
virtual void update() override
{
LidarBase::update();
freq_limiter_.update();
if (freq_limiter_.isWaitComplete()) {
updateOutput();
}
}
virtual void reportState(StateReporter& reporter) override
{
//call base
LidarBase::reportState(reporter);
virtual void update() override
{
LidarBase::update();
reporter.writeValue("Lidar-NumChannels", params_.number_of_channels);
reporter.writeValue("Lidar-Range", params_.range);
reporter.writeValue("Lidar-FOV-Upper", params_.vertical_FOV_upper);
reporter.writeValue("Lidar-FOV-Lower", params_.vertical_FOV_lower);
}
//*** End: UpdatableState implementation ***//
freq_limiter_.update();
virtual ~LidarSimple() = default;
if (freq_limiter_.isWaitComplete()) {
updateOutput();
}
}
const LidarSimpleParams& getParams() const
{
return params_;
}
virtual void reportState(StateReporter& reporter) override
{
//call base
LidarBase::reportState(reporter);
protected:
virtual void getPointCloud(const Pose& lidar_pose, const Pose& vehicle_pose,
TTimeDelta delta_time, vector<real_T>& point_cloud, vector<int>& segmentation_cloud) = 0;
reporter.writeValue("Lidar-NumChannels", params_.number_of_channels);
reporter.writeValue("Lidar-Range", params_.range);
reporter.writeValue("Lidar-FOV-Upper", params_.vertical_FOV_upper);
reporter.writeValue("Lidar-FOV-Lower", params_.vertical_FOV_lower);
}
//*** End: UpdatableState implementation ***//
private: //methods
void updateOutput()
{
TTimeDelta delta_time = clock()->updateSince(last_time_);
virtual ~LidarSimple() = default;
point_cloud_.clear();
const LidarSimpleParams& getParams() const
{
return params_;
}
const GroundTruth& ground_truth = getGroundTruth();
protected:
virtual void getPointCloud(const Pose& lidar_pose, const Pose& vehicle_pose,
TTimeDelta delta_time, vector<real_T>& point_cloud, vector<int>& segmentation_cloud) = 0;
// calculate the pose before obtaining the point-cloud. Before/after is a bit arbitrary
// decision here. If the pose can change while obtaining the point-cloud (could happen for drones)
// then the pose won't be very accurate either way.
//
// TODO: Seems like pose is in vehicle inertial-frame (NOT in Global NED frame).
// That could be a bit unintuitive but seems consistent with the position/orientation returned as part of
// ImageResponse for cameras and pose returned by getCameraInfo API.
// Do we need to convert pose to Global NED frame before returning to clients?
Pose lidar_pose = params_.relative_pose + ground_truth.kinematics->pose;
getPointCloud(params_.relative_pose, // relative lidar pose
ground_truth.kinematics->pose, // relative vehicle pose
delta_time,
point_cloud_,
segmentation_cloud_
);
private: //methods
void updateOutput()
{
TTimeDelta delta_time = clock()->updateSince(last_time_);
LidarData output;
output.point_cloud = point_cloud_;
output.time_stamp = clock()->nowNanos();
output.pose = lidar_pose;
output.segmentation = segmentation_cloud_;
point_cloud_.clear();
last_time_ = output.time_stamp;
const GroundTruth& ground_truth = getGroundTruth();
setOutput(output);
}
// calculate the pose before obtaining the point-cloud. Before/after is a bit arbitrary
// decision here. If the pose can change while obtaining the point-cloud (could happen for drones)
// then the pose won't be very accurate either way.
//
// TODO: Seems like pose is in vehicle inertial-frame (NOT in Global NED frame).
// That could be a bit unintuitive but seems consistent with the position/orientation returned as part of
// ImageResponse for cameras and pose returned by getCameraInfo API.
// Do we need to convert pose to Global NED frame before returning to clients?
Pose lidar_pose = params_.relative_pose + ground_truth.kinematics->pose;
getPointCloud(params_.relative_pose, // relative lidar pose
ground_truth.kinematics->pose, // relative vehicle pose
delta_time,
point_cloud_,
segmentation_cloud_);
private:
LidarSimpleParams params_;
vector<real_T> point_cloud_;
vector<int> segmentation_cloud_;
LidarData output;
output.point_cloud = point_cloud_;
output.time_stamp = clock()->nowNanos();
output.pose = lidar_pose;
output.segmentation = segmentation_cloud_;
FrequencyLimiter freq_limiter_;
TTimePoint last_time_;
};
last_time_ = output.time_stamp;
}} //namespace
setOutput(output);
}
private:
LidarSimpleParams params_;
vector<real_T> point_cloud_;
vector<int> segmentation_cloud_;
FrequencyLimiter freq_limiter_;
TTimePoint last_time_;
};
}
} //namespace
#endif

Просмотреть файл

@ -7,100 +7,101 @@
#include "common/Common.hpp"
#include "common/AirSimSettings.hpp"
namespace msr { namespace airlib {
struct LidarSimpleParams
namespace msr
{
namespace airlib
{
// Velodyne VLP-16 Puck config
// https://velodynelidar.com/vlp-16.html
// default settings
// TODO: enable reading of these params from AirSim settings
uint number_of_channels = 16;
real_T range = 10000.0f / 100; // meters
uint points_per_second = 100000;
uint horizontal_rotation_frequency = 10; // rotations/sec
real_T horizontal_FOV_start = 0;
real_T horizontal_FOV_end = 359;
real_T vertical_FOV_upper = -15; // drones -15, car +10
real_T vertical_FOV_lower = -45; // drones -45, car -10
Pose relative_pose {
Vector3r(0,0,-1), // position - a little above vehicle (especially for cars) or Vector3r::Zero()
Quaternionr::Identity() // orientation - by default Quaternionr(1, 0, 0, 0)
};
bool draw_debug_points = false;
std::string data_frame = AirSimSettings::kVehicleInertialFrame;
bool external_controller = true;
real_T update_frequency = 10; // Hz
real_T startup_delay = 0; // sec
void initializeFromSettings(const AirSimSettings::LidarSetting& settings)
struct LidarSimpleParams
{
std::string simmode_name = AirSimSettings::singleton().simmode_name;
const auto& settings_json = settings.settings;
number_of_channels = settings_json.getInt("NumberOfChannels", number_of_channels);
range = settings_json.getFloat("Range", range);
points_per_second = settings_json.getInt("PointsPerSecond", points_per_second);
horizontal_rotation_frequency = settings_json.getInt("RotationsPerSecond", horizontal_rotation_frequency);
draw_debug_points = settings_json.getBool("DrawDebugPoints", draw_debug_points);
data_frame = settings_json.getString("DataFrame", data_frame);
external_controller = settings_json.getBool("ExternalController", external_controller);
// Velodyne VLP-16 Puck config
// https://velodynelidar.com/vlp-16.html
vertical_FOV_upper = settings_json.getFloat("VerticalFOVUpper", Utils::nan<float>());
// default settings
// TODO: enable reading of these params from AirSim settings
// By default, for multirotors the lidars FOV point downwards;
// for cars, the lidars FOV is more forward facing.
if (std::isnan(vertical_FOV_upper)) {
if (simmode_name == AirSimSettings::kSimModeTypeMultirotor)
vertical_FOV_upper = -15;
else
vertical_FOV_upper = +10;
uint number_of_channels = 16;
real_T range = 10000.0f / 100; // meters
uint points_per_second = 100000;
uint horizontal_rotation_frequency = 10; // rotations/sec
real_T horizontal_FOV_start = 0;
real_T horizontal_FOV_end = 359;
real_T vertical_FOV_upper = -15; // drones -15, car +10
real_T vertical_FOV_lower = -45; // drones -45, car -10
Pose relative_pose{
Vector3r(0, 0, -1), // position - a little above vehicle (especially for cars) or Vector3r::Zero()
Quaternionr::Identity() // orientation - by default Quaternionr(1, 0, 0, 0)
};
bool draw_debug_points = false;
std::string data_frame = AirSimSettings::kVehicleInertialFrame;
bool external_controller = true;
real_T update_frequency = 10; // Hz
real_T startup_delay = 0; // sec
void initializeFromSettings(const AirSimSettings::LidarSetting& settings)
{
std::string simmode_name = AirSimSettings::singleton().simmode_name;
const auto& settings_json = settings.settings;
number_of_channels = settings_json.getInt("NumberOfChannels", number_of_channels);
range = settings_json.getFloat("Range", range);
points_per_second = settings_json.getInt("PointsPerSecond", points_per_second);
horizontal_rotation_frequency = settings_json.getInt("RotationsPerSecond", horizontal_rotation_frequency);
draw_debug_points = settings_json.getBool("DrawDebugPoints", draw_debug_points);
data_frame = settings_json.getString("DataFrame", data_frame);
external_controller = settings_json.getBool("ExternalController", external_controller);
vertical_FOV_upper = settings_json.getFloat("VerticalFOVUpper", Utils::nan<float>());
// By default, for multirotors the lidars FOV point downwards;
// for cars, the lidars FOV is more forward facing.
if (std::isnan(vertical_FOV_upper)) {
if (simmode_name == AirSimSettings::kSimModeTypeMultirotor)
vertical_FOV_upper = -15;
else
vertical_FOV_upper = +10;
}
vertical_FOV_lower = settings_json.getFloat("VerticalFOVLower", Utils::nan<float>());
if (std::isnan(vertical_FOV_lower)) {
if (simmode_name == AirSimSettings::kSimModeTypeMultirotor)
vertical_FOV_lower = -45;
else
vertical_FOV_lower = -10;
}
horizontal_FOV_start = settings_json.getFloat("HorizontalFOVStart", horizontal_FOV_start);
horizontal_FOV_end = settings_json.getFloat("HorizontalFOVEnd", horizontal_FOV_end);
relative_pose.position = AirSimSettings::createVectorSetting(settings_json, VectorMath::nanVector());
auto rotation = AirSimSettings::createRotationSetting(settings_json, AirSimSettings::Rotation::nanRotation());
if (std::isnan(relative_pose.position.x()))
relative_pose.position.x() = 0;
if (std::isnan(relative_pose.position.y()))
relative_pose.position.y() = 0;
if (std::isnan(relative_pose.position.z())) {
if (simmode_name == AirSimSettings::kSimModeTypeMultirotor)
relative_pose.position.z() = 0;
else
relative_pose.position.z() = -1; // a little bit above for cars
}
float pitch, roll, yaw;
pitch = !std::isnan(rotation.pitch) ? rotation.pitch : 0;
roll = !std::isnan(rotation.roll) ? rotation.roll : 0;
yaw = !std::isnan(rotation.yaw) ? rotation.yaw : 0;
relative_pose.orientation = VectorMath::toQuaternion(
Utils::degreesToRadians(pitch), // pitch - rotation around Y axis
Utils::degreesToRadians(roll), // roll - rotation around X axis
Utils::degreesToRadians(yaw)); // yaw - rotation around Z axis
}
vertical_FOV_lower = settings_json.getFloat("VerticalFOVLower", Utils::nan<float>());
if (std::isnan(vertical_FOV_lower)) {
if (simmode_name == AirSimSettings::kSimModeTypeMultirotor)
vertical_FOV_lower = -45;
else
vertical_FOV_lower = -10;
}
horizontal_FOV_start = settings_json.getFloat("HorizontalFOVStart", horizontal_FOV_start);
horizontal_FOV_end = settings_json.getFloat("HorizontalFOVEnd", horizontal_FOV_end);
relative_pose.position = AirSimSettings::createVectorSetting(settings_json, VectorMath::nanVector());
auto rotation = AirSimSettings::createRotationSetting(settings_json, AirSimSettings::Rotation::nanRotation());
if (std::isnan(relative_pose.position.x()))
relative_pose.position.x() = 0;
if (std::isnan(relative_pose.position.y()))
relative_pose.position.y() = 0;
if (std::isnan(relative_pose.position.z())) {
if (simmode_name == AirSimSettings::kSimModeTypeMultirotor)
relative_pose.position.z() = 0;
else
relative_pose.position.z() = -1; // a little bit above for cars
}
float pitch, roll, yaw;
pitch = !std::isnan(rotation.pitch) ? rotation.pitch : 0;
roll = !std::isnan(rotation.roll) ? rotation.roll : 0;
yaw = !std::isnan(rotation.yaw) ? rotation.yaw : 0;
relative_pose.orientation = VectorMath::toQuaternion(
Utils::degreesToRadians(pitch), // pitch - rotation around Y axis
Utils::degreesToRadians(roll), // roll - rotation around X axis
Utils::degreesToRadians(yaw)); // yaw - rotation around Z axis
}
};
}} //namespace
};
}
} //namespace
#endif

Просмотреть файл

@ -4,50 +4,52 @@
#ifndef msr_airlib_MagnetometerBase_hpp
#define msr_airlib_MagnetometerBase_hpp
#include "sensors/SensorBase.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class MagnetometerBase : public SensorBase
{
public:
MagnetometerBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{
}
class MagnetometerBase : public SensorBase {
public:
MagnetometerBase(const std::string& sensor_name = "")
: SensorBase(sensor_name)
{}
public: //types
struct Output
{ //same fields as ROS message
TTimePoint time_stamp;
Vector3r magnetic_field_body; //in Gauss
vector<real_T> magnetic_field_covariance; //9 elements 3x3 matrix
};
public: //types
struct Output { //same fields as ROS message
TTimePoint time_stamp;
Vector3r magnetic_field_body; //in Gauss
vector<real_T> magnetic_field_covariance; //9 elements 3x3 matrix
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("Mag-Vec", output_.magnetic_field_body);
}
const Output& getOutput() const
{
return output_;
}
protected:
void setOutput(const Output& output)
{
output_ = output;
}
private:
Output output_;
};
public:
virtual void reportState(StateReporter& reporter) override
{
//call base
UpdatableObject::reportState(reporter);
reporter.writeValue("Mag-Vec", output_.magnetic_field_body);
}
const Output& getOutput() const
{
return output_;
}
protected:
void setOutput(const Output& output)
{
output_ = output;
}
private:
Output output_;
};
}} //namespace
#endif
}
} //namespace
#endif

Просмотреть файл

@ -12,104 +12,106 @@
#include "common/FrequencyLimiter.hpp"
#include "common/DelayLine.hpp"
namespace msr { namespace airlib {
class MagnetometerSimple : public MagnetometerBase
namespace msr
{
public:
MagnetometerSimple(const AirSimSettings::MagnetometerSetting& setting = AirSimSettings::MagnetometerSetting())
: MagnetometerBase(setting.sensor_name)
namespace airlib
{
class MagnetometerSimple : public MagnetometerBase
{
// initialize params
params_.initializeFromSettings(setting);
public:
MagnetometerSimple(const AirSimSettings::MagnetometerSetting& setting = AirSimSettings::MagnetometerSetting())
: MagnetometerBase(setting.sensor_name)
{
// initialize params
params_.initializeFromSettings(setting);
noise_vec_ = RandomVectorGaussianR(Vector3r::Zero(), params_.noise_sigma);
bias_vec_ = RandomVectorR(-params_.noise_bias, params_.noise_bias).next();
noise_vec_ = RandomVectorGaussianR(Vector3r::Zero(), params_.noise_sigma);
bias_vec_ = RandomVectorR(-params_.noise_bias, params_.noise_bias).next();
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
delay_line_.initialize(params_.update_latency);
}
//initialize frequency limiter
freq_limiter_.initialize(params_.update_frequency, params_.startup_delay);
delay_line_.initialize(params_.update_latency);
}
//*** Start: UpdatableObject implementation ***//
virtual void resetImplementation() override
{
//Ground truth is reset before sensors are reset
updateReference(getGroundTruth());
noise_vec_.reset();
//*** Start: UpdatableObject implementation ***//
virtual void resetImplementation() override
{
//Ground truth is reset before sensors are reset
updateReference(getGroundTruth());
noise_vec_.reset();
freq_limiter_.reset();
delay_line_.reset();
freq_limiter_.reset();
delay_line_.reset();
delay_line_.push_back(getOutputInternal());
}
virtual void update() override
{
MagnetometerBase::update();
freq_limiter_.update();
if (freq_limiter_.isWaitComplete()) {
delay_line_.push_back(getOutputInternal());
}
delay_line_.update();
virtual void update() override
{
MagnetometerBase::update();
if (freq_limiter_.isWaitComplete())
setOutput(delay_line_.getOutput());
}
//*** End: UpdatableObject implementation ***//
freq_limiter_.update();
virtual ~MagnetometerSimple() = default;
if (freq_limiter_.isWaitComplete()) {
delay_line_.push_back(getOutputInternal());
}
private: //methods
void updateReference(const GroundTruth& ground_truth)
{
switch (params_.ref_source) {
case MagnetometerSimpleParams::ReferenceSource::ReferenceSource_Constant:
// Constant magnetic field for Seattle
magnetic_field_true_ = Vector3r(0.34252f, 0.09805f, 0.93438f);
break;
case MagnetometerSimpleParams::ReferenceSource::ReferenceSource_DipoleModel:
magnetic_field_true_ = EarthUtils::getMagField(ground_truth.environment->getState().geo_point) * 1E4f; //Tesla to Gauss
break;
default:
throw std::invalid_argument("magnetic reference source type is not recognized");
delay_line_.update();
if (freq_limiter_.isWaitComplete())
setOutput(delay_line_.getOutput());
}
}
Output getOutputInternal()
{
Output output;
const GroundTruth& ground_truth = getGroundTruth();
//*** End: UpdatableObject implementation ***//
if (params_.dynamic_reference_source)
updateReference(ground_truth);
virtual ~MagnetometerSimple() = default;
// Calculate the magnetic field noise.
output.magnetic_field_body = VectorMath::transformToBodyFrame(magnetic_field_true_,
ground_truth.kinematics->pose.orientation, true) * params_.scale_factor
+ noise_vec_.next()
+ bias_vec_;
private: //methods
void updateReference(const GroundTruth& ground_truth)
{
switch (params_.ref_source) {
case MagnetometerSimpleParams::ReferenceSource::ReferenceSource_Constant:
// Constant magnetic field for Seattle
magnetic_field_true_ = Vector3r(0.34252f, 0.09805f, 0.93438f);
break;
case MagnetometerSimpleParams::ReferenceSource::ReferenceSource_DipoleModel:
magnetic_field_true_ = EarthUtils::getMagField(ground_truth.environment->getState().geo_point) * 1E4f; //Tesla to Gauss
break;
default:
throw std::invalid_argument("magnetic reference source type is not recognized");
}
}
Output getOutputInternal()
{
Output output;
const GroundTruth& ground_truth = getGroundTruth();
// todo output.magnetic_field_covariance ?
output.time_stamp = clock()->nowNanos();
if (params_.dynamic_reference_source)
updateReference(ground_truth);
return output;
}
// Calculate the magnetic field noise.
output.magnetic_field_body = VectorMath::transformToBodyFrame(magnetic_field_true_,
ground_truth.kinematics->pose.orientation,
true) *
params_.scale_factor +
noise_vec_.next() + bias_vec_;
private:
RandomVectorGaussianR noise_vec_;
Vector3r bias_vec_;
// todo output.magnetic_field_covariance ?
output.time_stamp = clock()->nowNanos();
Vector3r magnetic_field_true_;
MagnetometerSimpleParams params_;
return output;
}
private:
RandomVectorGaussianR noise_vec_;
Vector3r bias_vec_;
FrequencyLimiter freq_limiter_;
DelayLine<Output> delay_line_;
};
Vector3r magnetic_field_true_;
MagnetometerSimpleParams params_;
}} //namespace
#endif
FrequencyLimiter freq_limiter_;
DelayLine<Output> delay_line_;
};
}
} //namespace
#endif

Просмотреть файл

@ -6,47 +6,48 @@
#include "common/Common.hpp"
namespace msr { namespace airlib {
struct MagnetometerSimpleParams
namespace msr
{
namespace airlib
{
enum ReferenceSource {
ReferenceSource_Constant,
ReferenceSource_DipoleModel
};
Vector3r noise_sigma = Vector3r(0.005f, 0.005f, 0.005f); //5 mgauss as per specs sheet (RMS is same as stddev) https://goo.gl/UOz6FT
real_T scale_factor = 1.0f;
Vector3r noise_bias = Vector3r(0.0f, 0.0f, 0.0f); //no offset as per specsheet (zero gauss level) https://goo.gl/UOz6FT
float ref_update_frequency = 0.2f; //Hz
//use dipole model if there is enough compute power available
bool dynamic_reference_source = true;
ReferenceSource ref_source = ReferenceSource::ReferenceSource_DipoleModel;
//bool dynamic_reference_source = false;
//ReferenceSource ref_source = ReferenceSource::ReferenceSource_Constant;
//see PX4 param reference for EKF: https://dev.px4.io/en/advanced/parameter_reference.html
real_T update_latency = 0.0f; //sec: from PX4 doc
real_T update_frequency = 50; //Hz
real_T startup_delay = 0; //sec
void initializeFromSettings(const AirSimSettings::MagnetometerSetting& settings)
struct MagnetometerSimpleParams
{
const auto& json = settings.settings;
float noise = json.getFloat("NoiseSigma", noise_sigma.x());
noise_sigma = Vector3r(noise, noise, noise);
scale_factor = json.getFloat("ScaleFactor", scale_factor);
float bias = json.getFloat("NoiseBias", noise_bias.x());
noise_bias = Vector3r(bias, bias, bias);
update_latency = json.getFloat("UpdateLatency", update_latency);
update_frequency = json.getFloat("UpdateFrequency", update_frequency);
startup_delay = json.getFloat("StartupDelay", startup_delay);
}
};
enum ReferenceSource
{
ReferenceSource_Constant,
ReferenceSource_DipoleModel
};
Vector3r noise_sigma = Vector3r(0.005f, 0.005f, 0.005f); //5 mgauss as per specs sheet (RMS is same as stddev) https://goo.gl/UOz6FT
real_T scale_factor = 1.0f;
Vector3r noise_bias = Vector3r(0.0f, 0.0f, 0.0f); //no offset as per specsheet (zero gauss level) https://goo.gl/UOz6FT
float ref_update_frequency = 0.2f; //Hz
}} //namespace
//use dipole model if there is enough compute power available
bool dynamic_reference_source = true;
ReferenceSource ref_source = ReferenceSource::ReferenceSource_DipoleModel;
//bool dynamic_reference_source = false;
//ReferenceSource ref_source = ReferenceSource::ReferenceSource_Constant;
//see PX4 param reference for EKF: https://dev.px4.io/en/advanced/parameter_reference.html
real_T update_latency = 0.0f; //sec: from PX4 doc
real_T update_frequency = 50; //Hz
real_T startup_delay = 0; //sec
void initializeFromSettings(const AirSimSettings::MagnetometerSetting& settings)
{
const auto& json = settings.settings;
float noise = json.getFloat("NoiseSigma", noise_sigma.x());
noise_sigma = Vector3r(noise, noise, noise);
scale_factor = json.getFloat("ScaleFactor", scale_factor);
float bias = json.getFloat("NoiseBias", noise_bias.x());
noise_bias = Vector3r(bias, bias, bias);
update_latency = json.getFloat("UpdateLatency", update_latency);
update_frequency = json.getFloat("UpdateFrequency", update_frequency);
startup_delay = json.getFloat("StartupDelay", startup_delay);
}
};
}
} //namespace
#endif

Просмотреть файл

@ -7,31 +7,33 @@
#include "vehicles/car/firmwares/physxcar/PhysXCarApi.hpp"
#include "vehicles/car/firmwares/ardurover/ArduRoverApi.hpp"
namespace msr { namespace airlib {
namespace msr
{
namespace airlib
{
class CarApiFactory {
public:
static std::unique_ptr<CarApiBase> createApi(const AirSimSettings::VehicleSetting* vehicle_setting,
std::shared_ptr<SensorFactory> sensor_factory,
const Kinematics::State& state, const Environment& environment,
const msr::airlib::GeoPoint& home_geopoint)
class CarApiFactory
{
if (vehicle_setting->vehicle_type == AirSimSettings::kVehicleTypeArduRover) {
return std::unique_ptr<CarApiBase>(new ArduRoverApi(vehicle_setting, sensor_factory,
state, environment, home_geopoint));
}
else if (vehicle_setting->vehicle_type == "" || //default config
vehicle_setting->vehicle_type == AirSimSettings::kVehicleTypePhysXCar) {
return std::unique_ptr<CarApiBase>(new PhysXCarApi(vehicle_setting, sensor_factory,
state, environment, home_geopoint));
}
else
throw std::runtime_error(Utils::stringf(
public:
static std::unique_ptr<CarApiBase> createApi(const AirSimSettings::VehicleSetting* vehicle_setting,
std::shared_ptr<SensorFactory> sensor_factory,
const Kinematics::State& state, const Environment& environment,
const msr::airlib::GeoPoint& home_geopoint)
{
if (vehicle_setting->vehicle_type == AirSimSettings::kVehicleTypeArduRover) {
return std::unique_ptr<CarApiBase>(new ArduRoverApi(vehicle_setting, sensor_factory, state, environment, home_geopoint));
}
else if (vehicle_setting->vehicle_type == "" || //default config
vehicle_setting->vehicle_type == AirSimSettings::kVehicleTypePhysXCar) {
return std::unique_ptr<CarApiBase>(new PhysXCarApi(vehicle_setting, sensor_factory, state, environment, home_geopoint));
}
else
throw std::runtime_error(Utils::stringf(
"Cannot create vehicle config because vehicle name '%s' is not recognized",
vehicle_setting->vehicle_name.c_str()));
}
};
}} // namespace
}
};
}
} // namespace
#endif

Просмотреть файл

@ -12,150 +12,151 @@
#include "sensors/SensorCollection.hpp"
#include "sensors/SensorFactory.hpp"
namespace msr { namespace airlib {
class CarApiBase : public VehicleApiBase
namespace msr
{
namespace airlib
{
public:
struct CarControls {
float throttle = 0; /* 1 to -1 */
float steering = 0; /* 1 to -1 */
float brake = 0; /* 1 to -1 */
bool handbrake = false;
bool is_manual_gear = false;
int manual_gear = 0;
bool gear_immediate = true;
CarControls()
class CarApiBase : public VehicleApiBase
{
public:
struct CarControls
{
}
CarControls(float throttle_val, float steering_val, float brake_val, bool handbrake_val,
bool is_manual_gear_val, int manual_gear_val, bool gear_immediate_val)
: throttle(throttle_val), steering(steering_val), brake(brake_val), handbrake(handbrake_val),
is_manual_gear(is_manual_gear_val), manual_gear(manual_gear_val), gear_immediate(gear_immediate_val)
{
}
void set_throttle(float throttle_val, bool forward)
{
if (forward) {
is_manual_gear = false;
manual_gear = 0;
throttle = std::abs(throttle_val);
float throttle = 0; /* 1 to -1 */
float steering = 0; /* 1 to -1 */
float brake = 0; /* 1 to -1 */
bool handbrake = false;
bool is_manual_gear = false;
int manual_gear = 0;
bool gear_immediate = true;
CarControls()
{
}
else {
is_manual_gear = false;
manual_gear = -1;
throttle = - std::abs(throttle_val);
CarControls(float throttle_val, float steering_val, float brake_val, bool handbrake_val,
bool is_manual_gear_val, int manual_gear_val, bool gear_immediate_val)
: throttle(throttle_val), steering(steering_val), brake(brake_val), handbrake(handbrake_val), is_manual_gear(is_manual_gear_val), manual_gear(manual_gear_val), gear_immediate(gear_immediate_val)
{
}
void set_throttle(float throttle_val, bool forward)
{
if (forward) {
is_manual_gear = false;
manual_gear = 0;
throttle = std::abs(throttle_val);
}
else {
is_manual_gear = false;
manual_gear = -1;
throttle = -std::abs(throttle_val);
}
}
};
struct CarState
{
float speed;
int gear;
float rpm;
float maxrpm;
bool handbrake;
Kinematics::State kinematics_estimated;
uint64_t timestamp;
CarState()
{
}
CarState(float speed_val, int gear_val, float rpm_val, float maxrpm_val, bool handbrake_val,
const Kinematics::State& kinematics_estimated_val, uint64_t timestamp_val)
: speed(speed_val), gear(gear_val), rpm(rpm_val), maxrpm(maxrpm_val), handbrake(handbrake_val), kinematics_estimated(kinematics_estimated_val), timestamp(timestamp_val)
{
}
//shortcuts
const Vector3r& getPosition() const
{
return kinematics_estimated.pose.position;
}
const Quaternionr& getOrientation() const
{
return kinematics_estimated.pose.orientation;
}
};
public:
// TODO: Temporary constructor for the Unity implementation which does not use the new Sensor Configuration Settings implementation.
//CarApiBase() {}
CarApiBase(const AirSimSettings::VehicleSetting* vehicle_setting,
std::shared_ptr<SensorFactory> sensor_factory,
const Kinematics::State& state, const Environment& environment)
{
initialize(vehicle_setting, sensor_factory, state, environment);
}
virtual void update() override
{
VehicleApiBase::update();
getSensors().update();
}
void reportState(StateReporter& reporter) override
{
getSensors().reportState(reporter);
}
// sensor helpers
virtual const SensorCollection& getSensors() const override
{
return sensors_;
}
SensorCollection& getSensors()
{
return sensors_;
}
void initialize(const AirSimSettings::VehicleSetting* vehicle_setting,
std::shared_ptr<SensorFactory> sensor_factory,
const Kinematics::State& state, const Environment& environment)
{
sensor_factory_ = sensor_factory;
sensor_storage_.clear();
sensors_.clear();
addSensorsFromSettings(vehicle_setting);
getSensors().initialize(&state, &environment);
}
void addSensorsFromSettings(const AirSimSettings::VehicleSetting* vehicle_setting)
{
const auto& sensor_settings = vehicle_setting->sensors;
sensor_factory_->createSensorsFromSettings(sensor_settings, sensors_, sensor_storage_);
}
virtual void setCarControls(const CarControls& controls) = 0;
virtual void updateCarState(const CarState& state) = 0;
virtual const CarState& getCarState() const = 0;
virtual const CarControls& getCarControls() const = 0;
virtual ~CarApiBase() = default;
std::shared_ptr<const SensorFactory> sensor_factory_;
SensorCollection sensors_; //maintains sensor type indexed collection of sensors
vector<shared_ptr<SensorBase>> sensor_storage_; //RAII for created sensors
protected:
virtual void resetImplementation() override
{
//reset sensors last after their ground truth has been reset
getSensors().reset();
}
};
struct CarState {
float speed;
int gear;
float rpm;
float maxrpm;
bool handbrake;
Kinematics::State kinematics_estimated;
uint64_t timestamp;
CarState()
{
}
CarState(float speed_val, int gear_val, float rpm_val, float maxrpm_val, bool handbrake_val,
const Kinematics::State& kinematics_estimated_val, uint64_t timestamp_val)
: speed(speed_val), gear(gear_val), rpm(rpm_val), maxrpm(maxrpm_val), handbrake(handbrake_val),
kinematics_estimated(kinematics_estimated_val), timestamp(timestamp_val)
{
}
//shortcuts
const Vector3r& getPosition() const
{
return kinematics_estimated.pose.position;
}
const Quaternionr& getOrientation() const
{
return kinematics_estimated.pose.orientation;
}
};
public:
// TODO: Temporary constructor for the Unity implementation which does not use the new Sensor Configuration Settings implementation.
//CarApiBase() {}
CarApiBase(const AirSimSettings::VehicleSetting* vehicle_setting,
std::shared_ptr<SensorFactory> sensor_factory,
const Kinematics::State& state, const Environment& environment)
{
initialize(vehicle_setting, sensor_factory, state, environment);
}
virtual void update() override
{
VehicleApiBase::update();
getSensors().update();
}
void reportState(StateReporter& reporter) override
{
getSensors().reportState(reporter);
}
// sensor helpers
virtual const SensorCollection& getSensors() const override
{
return sensors_;
}
SensorCollection& getSensors()
{
return sensors_;
}
void initialize(const AirSimSettings::VehicleSetting* vehicle_setting,
std::shared_ptr<SensorFactory> sensor_factory,
const Kinematics::State& state, const Environment& environment)
{
sensor_factory_ = sensor_factory;
sensor_storage_.clear();
sensors_.clear();
addSensorsFromSettings(vehicle_setting);
getSensors().initialize(&state, &environment);
}
void addSensorsFromSettings(const AirSimSettings::VehicleSetting* vehicle_setting)
{
const auto& sensor_settings = vehicle_setting->sensors;
sensor_factory_->createSensorsFromSettings(sensor_settings, sensors_, sensor_storage_);
}
virtual void setCarControls(const CarControls& controls) = 0;
virtual void updateCarState(const CarState& state) = 0;
virtual const CarState& getCarState() const = 0;
virtual const CarControls& getCarControls() const = 0;
virtual ~CarApiBase() = default;
std::shared_ptr<const SensorFactory> sensor_factory_;
SensorCollection sensors_; //maintains sensor type indexed collection of sensors
vector<shared_ptr<SensorBase>> sensor_storage_; //RAII for created sensors
protected:
virtual void resetImplementation() override
{
//reset sensors last after their ground truth has been reset
getSensors().reset();
}
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -14,74 +14,80 @@
#include "rpc/msgpack.hpp"
#include "common/common_utils/WindowsApisCommonPost.hpp"
namespace msr { namespace airlib_rpclib {
namespace msr
{
namespace airlib_rpclib
{
class CarRpcLibAdaptors : public RpcLibAdaptorsBase {
public:
struct CarControls {
float throttle = 0;
float steering = 0;
float brake = 0;
bool handbrake = false;
bool is_manual_gear = false;
int manual_gear = 0;
bool gear_immediate = true;
MSGPACK_DEFINE_MAP(throttle, steering, brake, handbrake, is_manual_gear, manual_gear, gear_immediate);
CarControls()
{}
CarControls(const msr::airlib::CarApiBase::CarControls& s)
class CarRpcLibAdaptors : public RpcLibAdaptorsBase
{
public:
struct CarControls
{
throttle = s.throttle;
steering = s.steering;
brake = s.brake;
handbrake = s.handbrake;
is_manual_gear = s.is_manual_gear;
manual_gear = s.manual_gear;
gear_immediate = s.gear_immediate;
}
msr::airlib::CarApiBase::CarControls to() const
float throttle = 0;
float steering = 0;
float brake = 0;
bool handbrake = false;
bool is_manual_gear = false;
int manual_gear = 0;
bool gear_immediate = true;
MSGPACK_DEFINE_MAP(throttle, steering, brake, handbrake, is_manual_gear, manual_gear, gear_immediate);
CarControls()
{
}
CarControls(const msr::airlib::CarApiBase::CarControls& s)
{
throttle = s.throttle;
steering = s.steering;
brake = s.brake;
handbrake = s.handbrake;
is_manual_gear = s.is_manual_gear;
manual_gear = s.manual_gear;
gear_immediate = s.gear_immediate;
}
msr::airlib::CarApiBase::CarControls to() const
{
return msr::airlib::CarApiBase::CarControls(throttle, steering, brake, handbrake, is_manual_gear, manual_gear, gear_immediate);
}
};
struct CarState
{
return msr::airlib::CarApiBase::CarControls(throttle, steering, brake, handbrake,
is_manual_gear, manual_gear, gear_immediate);
}
float speed;
int gear;
float rpm;
float maxrpm;
bool handbrake;
KinematicsState kinematics_estimated;
uint64_t timestamp;
MSGPACK_DEFINE_MAP(speed, gear, rpm, maxrpm, handbrake, kinematics_estimated, timestamp);
CarState()
{
}
CarState(const msr::airlib::CarApiBase::CarState& s)
{
speed = s.speed;
gear = s.gear;
rpm = s.rpm;
maxrpm = s.maxrpm;
handbrake = s.handbrake;
timestamp = s.timestamp;
kinematics_estimated = s.kinematics_estimated;
}
msr::airlib::CarApiBase::CarState to() const
{
return msr::airlib::CarApiBase::CarState(
speed, gear, rpm, maxrpm, handbrake, kinematics_estimated.to(), timestamp);
}
};
};
struct CarState {
float speed;
int gear;
float rpm;
float maxrpm;
bool handbrake;
KinematicsState kinematics_estimated;
uint64_t timestamp;
MSGPACK_DEFINE_MAP(speed, gear, rpm, maxrpm, handbrake, kinematics_estimated, timestamp);
CarState()
{}
CarState(const msr::airlib::CarApiBase::CarState& s)
{
speed = s.speed;
gear = s.gear;
rpm = s.rpm;
maxrpm = s.maxrpm;
handbrake = s.handbrake;
timestamp = s.timestamp;
kinematics_estimated = s.kinematics_estimated;
}
msr::airlib::CarApiBase::CarState to() const
{
return msr::airlib::CarApiBase::CarState(
speed, gear, rpm, maxrpm, handbrake, kinematics_estimated.to(), timestamp);
}
};
};
}} //namespace
}
} //namespace
#endif

Просмотреть файл

@ -11,18 +11,21 @@
#include "api/RpcLibClientBase.hpp"
#include "common/ImageCaptureBase.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class CarRpcLibClient : public RpcLibClientBase
{
public:
CarRpcLibClient(const string& ip_address = "localhost", uint16_t port = RpcLibPort, float timeout_sec = 60);
class CarRpcLibClient : public RpcLibClientBase {
public:
CarRpcLibClient(const string& ip_address = "localhost", uint16_t port = RpcLibPort, float timeout_sec = 60);
void setCarControls(const CarApiBase::CarControls& controls, const std::string& vehicle_name = "");
CarApiBase::CarState getCarState(const std::string& vehicle_name = "");
CarApiBase::CarControls getCarControls(const std::string& vehicle_name = "");
virtual ~CarRpcLibClient(); //required for pimpl
};
}} //namespace
void setCarControls(const CarApiBase::CarControls& controls, const std::string& vehicle_name = "");
CarApiBase::CarState getCarState(const std::string& vehicle_name = "");
CarApiBase::CarControls getCarControls(const std::string& vehicle_name = "");
virtual ~CarRpcLibClient(); //required for pimpl
};
}
} //namespace
#endif

Просмотреть файл

@ -11,22 +11,25 @@
#include "api/RpcLibServerBase.hpp"
#include "vehicles/car/api/CarApiBase.hpp"
namespace msr
{
namespace airlib
{
namespace msr { namespace airlib {
class CarRpcLibServer : public RpcLibServerBase {
public:
CarRpcLibServer(ApiProvider* api_provider, string server_address, uint16_t port = RpcLibPort);
virtual ~CarRpcLibServer();
protected:
virtual CarApiBase* getVehicleApi(const std::string& vehicle_name) override
class CarRpcLibServer : public RpcLibServerBase
{
return static_cast<CarApiBase*>(RpcLibServerBase::getVehicleApi(vehicle_name));
}
};
public:
CarRpcLibServer(ApiProvider* api_provider, string server_address, uint16_t port = RpcLibPort);
virtual ~CarRpcLibServer();
protected:
virtual CarApiBase* getVehicleApi(const std::string& vehicle_name) override
{
return static_cast<CarApiBase*>(RpcLibServerBase::getVehicleApi(vehicle_name));
}
};
#endif
}} //namespace
}
} //namespace
#endif

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше