From f9678954aad84dbac621a4719fdbe70fe8deb75d Mon Sep 17 00:00:00 2001 From: Rajat Singhal Date: Tue, 21 Jul 2020 00:19:40 +0530 Subject: [PATCH 1/4] Add Wind force calculation to PhysicsEngine Use velocity wrt wind to calculate drag forces --- AirLib/include/physics/FastPhysicsEngine.hpp | 29 ++++++++++++++------ AirLib/include/physics/PhysicsEngineBase.hpp | 2 ++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/AirLib/include/physics/FastPhysicsEngine.hpp b/AirLib/include/physics/FastPhysicsEngine.hpp index 52e6bea053..e94277ac3e 100644 --- a/AirLib/include/physics/FastPhysicsEngine.hpp +++ b/AirLib/include/physics/FastPhysicsEngine.hpp @@ -18,8 +18,8 @@ namespace msr { namespace airlib { class FastPhysicsEngine : public PhysicsEngineBase { public: - FastPhysicsEngine(bool enable_ground_lock = true) - : enable_ground_lock_(enable_ground_lock) + FastPhysicsEngine(bool enable_ground_lock = true, Vector3r wind = Vector3r::Zero()) + : enable_ground_lock_(enable_ground_lock), wind_(wind) { } @@ -59,6 +59,12 @@ class FastPhysicsEngine : public PhysicsEngineBase { } //*** End: UpdatableState implementation ***// + // Set Wind, for API and Settings implementation + void setWind(const Vector3r& wind) override + { + wind_ = wind; + } + private: void initPhysicsBody(PhysicsBody* body_ptr) { @@ -76,7 +82,7 @@ class FastPhysicsEngine : public PhysicsEngineBase { //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); + getNextKinematicsNoCollision(dt, body, current, next, next_wrench, wind_); //if there is collision, see if we need collision response const CollisionInfo collision_info = body.getCollisionInfo(); @@ -255,9 +261,9 @@ class FastPhysicsEngine : public PhysicsEngineBase { } static Wrench getDragWrench(const PhysicsBody& body, const Quaternionr& orientation, - const Vector3r& linear_vel, const Vector3r& angular_vel_body) + 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 + //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 @@ -268,9 +274,13 @@ class FastPhysicsEngine : public PhysicsEngineBase { 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 = VectorMath::transformToBodyFrame(linear_vel, orientation) + angular_vel_body.cross(vertex.getPosition()); + 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) { @@ -312,7 +322,7 @@ class FastPhysicsEngine : public PhysicsEngineBase { } static void getNextKinematicsNoCollision(TTimeDelta dt, PhysicsBody& body, const Kinematics::State& current, - Kinematics::State& next, Wrench& next_wrench) + Kinematics::State& next, Wrench& next_wrench, const Vector3r& wind) { const real_T dt_real = static_cast(dt); @@ -338,13 +348,13 @@ class FastPhysicsEngine : public PhysicsEngineBase { next.accelerations.linear = Vector3r::Zero(); } else { - //add linear drag due to velocity we had since last dt seconds + //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); + const Wrench drag_wrench = getDragWrench(body, current.pose.orientation, avg_linear, avg_angular, wind); next_wrench = body_wrench + drag_wrench; @@ -449,6 +459,7 @@ class FastPhysicsEngine : public PhysicsEngineBase { std::stringstream debug_string_; bool enable_ground_lock_; TTimePoint last_message_time; + Vector3r wind_; }; }} //namespace diff --git a/AirLib/include/physics/PhysicsEngineBase.hpp b/AirLib/include/physics/PhysicsEngineBase.hpp index b151a8d6e3..2dff630ab4 100644 --- a/AirLib/include/physics/PhysicsEngineBase.hpp +++ b/AirLib/include/physics/PhysicsEngineBase.hpp @@ -44,6 +44,8 @@ class PhysicsEngineBase : public UpdatableObject { virtual void erase_remove(TUpdatableObjectPtr obj) { members_.erase(std::remove(members_.begin(), members_.end(), obj), members_.end()); } + virtual void setWind(const Vector3r& wind) {}; + private: MembersContainer members_; }; From 9be1fbf142261aa08b5ceecdb357f0a5173bb329 Mon Sep 17 00:00:00 2001 From: Rajat Singhal Date: Tue, 21 Jul 2020 00:20:49 +0530 Subject: [PATCH 2/4] Add Settings field for Wind, simSetWind API --- AirLib/include/api/RpcLibClientBase.hpp | 2 ++ AirLib/include/api/WorldSimApiBase.hpp | 2 ++ AirLib/include/common/AirSimSettings.hpp | 9 +++++++++ AirLib/src/api/RpcLibClientBase.cpp | 6 ++++++ AirLib/src/api/RpcLibServerBase.cpp | 4 ++++ PythonClient/airsim/client.py | 9 +++++++++ Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp | 7 +++++++ Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.h | 2 ++ .../Plugins/AirSim/Source/SimMode/SimModeWorldBase.cpp | 7 +++++++ Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.h | 2 ++ Unreal/Plugins/AirSim/Source/WorldSimApi.cpp | 6 ++++++ Unreal/Plugins/AirSim/Source/WorldSimApi.h | 2 ++ 12 files changed, 58 insertions(+) diff --git a/AirLib/include/api/RpcLibClientBase.hpp b/AirLib/include/api/RpcLibClientBase.hpp index 7f98072743..bb26a9f5c3 100644 --- a/AirLib/include/api/RpcLibClientBase.hpp +++ b/AirLib/include/api/RpcLibClientBase.hpp @@ -114,6 +114,8 @@ class RpcLibClientBase { void stopRecording(); bool isRecording(); + void simSetWind(const Vector3r& wind) const; + protected: void* getClient(); const void* getClient() const; diff --git a/AirLib/include/api/WorldSimApiBase.hpp b/AirLib/include/api/WorldSimApiBase.hpp index 8607c44ba1..9fae01d74c 100644 --- a/AirLib/include/api/WorldSimApiBase.hpp +++ b/AirLib/include/api/WorldSimApiBase.hpp @@ -70,6 +70,8 @@ class WorldSimApiBase { virtual void startRecording() = 0; virtual void stopRecording() = 0; virtual bool isRecording() const = 0; + + virtual void setWind(const Vector3r& wind) const = 0; }; diff --git a/AirLib/include/common/AirSimSettings.hpp b/AirLib/include/common/AirSimSettings.hpp index 348f235c8d..d992ecbce2 100644 --- a/AirLib/include/common/AirSimSettings.hpp +++ b/AirLib/include/common/AirSimSettings.hpp @@ -362,6 +362,7 @@ struct AirSimSettings { float speed_unit_factor = 1.0f; std::string speed_unit_label = "m\\s"; std::map> sensor_defaults; + Vector3r wind = Vector3r::Zero(); public: //methods static AirSimSettings& singleton() @@ -1064,6 +1065,14 @@ struct AirSimSettings { tod_setting.move_sun = tod_settings_json.getBool("MoveSun", tod_setting.move_sun); } } + + { + // Wind Settings + Settings child_json; + if (settings_json.getChild("Wind", child_json)) { + wind = createVectorSetting(child_json, wind); + } + } } static void loadDefaultCameraSetting(const Settings& settings_json, CameraSetting& camera_defaults) diff --git a/AirLib/src/api/RpcLibClientBase.cpp b/AirLib/src/api/RpcLibClientBase.cpp index be9c01fe80..4b0104a62d 100644 --- a/AirLib/src/api/RpcLibClientBase.cpp +++ b/AirLib/src/api/RpcLibClientBase.cpp @@ -432,6 +432,12 @@ bool RpcLibClientBase::isRecording() return pimpl_->client.call("isRecording").as(); } +void RpcLibClientBase::simSetWind(const Vector3r& wind) const +{ + RpcLibAdapatorsBase::Vector3r conv_wind(wind); + pimpl_->client.call("simSetWind", conv_wind); +} + void* RpcLibClientBase::getClient() { return &pimpl_->client; diff --git a/AirLib/src/api/RpcLibServerBase.cpp b/AirLib/src/api/RpcLibServerBase.cpp index 3123e95f18..daf8120a5d 100644 --- a/AirLib/src/api/RpcLibServerBase.cpp +++ b/AirLib/src/api/RpcLibServerBase.cpp @@ -366,6 +366,10 @@ RpcLibServerBase::RpcLibServerBase(ApiProvider* api_provider, const std::string& return getWorldSimApi()->isRecording(); }); + pimpl_->server.bind("simSetWind", [&](const RpcLibAdapatorsBase::Vector3r& wind) -> void { + getWorldSimApi()->setWind(wind.to()); + }); + //if we don't suppress then server will bomb out for exceptions raised by any method pimpl_->server.suppress_exceptions(true); } diff --git a/PythonClient/airsim/client.py b/PythonClient/airsim/client.py index a6553093bd..c2a97ed7c8 100644 --- a/PythonClient/airsim/client.py +++ b/PythonClient/airsim/client.py @@ -750,6 +750,15 @@ def isRecording(self): """ return self.client.call('isRecording') + def simSetWind(self, wind): + """ + Set simulated wind, in World frame, NED direction, m/s + + Args: + wind (Vector3r): Wind, in World frame, NED direction, in m/s + """ + self.client.call('simSetWind', wind) + # ----------------------------------- Multirotor APIs --------------------------------------------- class MultirotorClient(VehicleClient, object): def __init__(self, ip = "", port = 41451, timeout_value = 3600): diff --git a/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp b/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp index 74f923c658..beb2028f24 100644 --- a/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp +++ b/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp @@ -263,6 +263,13 @@ void ASimModeBase::continueForTime(double seconds) throw std::domain_error("continueForTime is not implemented by SimMode"); } +void ASimModeBase::setWind(const msr::airlib::Vector3r& wind) const +{ + // should be overridden by derived class + unused(wind); + throw std::domain_error("setWind not implemented by SimMode"); +} + std::unique_ptr ASimModeBase::createApiServer() const { //this will be the case when compilation with RPCLIB is disabled or simmode doesn't support APIs diff --git a/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.h b/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.h index 1b0b678ffe..2a420fdc90 100644 --- a/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.h +++ b/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.h @@ -62,6 +62,8 @@ class AIRSIM_API ASimModeBase : public AActor virtual void pause(bool is_paused); virtual void continueForTime(double seconds); + virtual void setWind(const msr::airlib::Vector3r& wind) const; + 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); diff --git a/Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.cpp b/Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.cpp index d3c96e5df7..4d66b012b1 100644 --- a/Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.cpp +++ b/Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.cpp @@ -62,6 +62,8 @@ std::unique_ptr ASimModeWorldBase::createP else { physics_engine.reset(new msr::airlib::FastPhysicsEngine()); } + + physics_engine->setWind(getSettings().wind); } else { physics_engine.reset(); @@ -98,6 +100,11 @@ void ASimModeWorldBase::continueForTime(double seconds) UGameplayStatics::SetGamePaused(this->GetWorld(), true); } +void ASimModeWorldBase::setWind(const msr::airlib::Vector3r& wind) const +{ + physics_engine_->setWind(wind); +} + void ASimModeWorldBase::updateDebugReport(msr::airlib::StateReporterWrapper& debug_reporter) { unused(debug_reporter); diff --git a/Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.h b/Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.h index cc1c622ce2..7bce788aea 100644 --- a/Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.h +++ b/Unreal/Plugins/AirSim/Source/SimMode/SimModeWorldBase.h @@ -31,6 +31,8 @@ class AIRSIM_API ASimModeWorldBase : public ASimModeBase virtual void pause(bool is_paused) override; virtual void continueForTime(double seconds) override; + virtual void setWind(const msr::airlib::Vector3r& wind) const override; + protected: void startAsyncUpdator(); void stopAsyncUpdator(); diff --git a/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp b/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp index 4a60712435..80594f8bce 100644 --- a/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp +++ b/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp @@ -410,3 +410,9 @@ bool WorldSimApi::isRecording() const { return simmode_->isRecording(); } + + +void WorldSimApi::setWind(const Vector3r& wind) const +{ + simmode_->setWind(wind); +} diff --git a/Unreal/Plugins/AirSim/Source/WorldSimApi.h b/Unreal/Plugins/AirSim/Source/WorldSimApi.h index a3aef5861c..6fd6e724b7 100644 --- a/Unreal/Plugins/AirSim/Source/WorldSimApi.h +++ b/Unreal/Plugins/AirSim/Source/WorldSimApi.h @@ -63,6 +63,8 @@ class WorldSimApi : public msr::airlib::WorldSimApiBase { virtual void stopRecording() override; virtual bool isRecording() const override; + virtual void setWind(const Vector3r& wind) const override; + private: AActor* createNewActor(const FActorSpawnParameters& spawn_params, const FTransform& actor_transform, const Vector3r& scale, UStaticMesh* static_mesh); void spawnPlayer(); From 0c4761e0ae6de9281cb383ae7ba50b363d7d78e8 Mon Sep 17 00:00:00 2001 From: Rajat Singhal Date: Tue, 21 Jul 2020 11:49:15 +0530 Subject: [PATCH 3/4] Add documentation, example script for setWind API --- PythonClient/multirotor/set_wind.py | 35 +++++++++++++++++++++++++++++ docs/apis.md | 14 ++++++++++++ docs/settings.md | 5 +++++ 3 files changed, 54 insertions(+) create mode 100644 PythonClient/multirotor/set_wind.py diff --git a/PythonClient/multirotor/set_wind.py b/PythonClient/multirotor/set_wind.py new file mode 100644 index 0000000000..2fcc7bec72 --- /dev/null +++ b/PythonClient/multirotor/set_wind.py @@ -0,0 +1,35 @@ +import setup_path +import airsim +import time + +client = airsim.MultirotorClient() +client.confirmConnection() +client.enableApiControl(True) + +client.armDisarm(True) + +print("Setting wind to 10m/s in forward direction") # NED +wind = airsim.Vector3r(10, 0, 0) +client.simSetWind(wind) + +# Takeoff or hover +landed = client.getMultirotorState().landed_state +if landed == airsim.LandedState.Landed: + print("taking off...") + client.takeoffAsync().join() +else: + print("already flying...") + client.hoverAsync().join() + +time.sleep(5) + +print("Setting wind to 15m/s towards right") # NED +wind = airsim.Vector3r(0, 15, 0) +client.simSetWind(wind) + +time.sleep(5) + +# Set wind to 0 +print("Resetting wind to 0") +wind = airsim.Vector3r(0, 0, 0) +client.simSetWind(wind) diff --git a/docs/apis.md b/docs/apis.md index a8807f74b4..f8482efcf0 100644 --- a/docs/apis.md +++ b/docs/apis.md @@ -193,6 +193,20 @@ This API works alongwith toggling Recording using R button, therefore if it's en Note that this will only save the data as specfied in the settings. For full freedom in storing data such as certain sensor information, or in a different format or layout, use the other APIs to fetch the data and save as desired. +### Wind API + +Wind can be changed during simulation using `simSetWind()`. Wind is specified in World frame, NED direction and m/s values + +E.g. To set 20m/s wind in North (forward) direction - + +```python +# Set wind to (20,0,0) in NED (forward direction) +wind = airsim.Vector3r(20, 0, 0) +client.simSetWind(wind) +``` + +Also see example script in [set_wind.py](https://github.com/Microsoft/AirSim/blob/master/PythonClient/multirotor/set_wind.py) + ### Lidar APIs AirSim offers API to retrieve point cloud data from Lidar sensors on vehicles. You can set the number of channels, points per second, horizontal and vertical FOV, etc parameters in [settings.json](settings.md). diff --git a/docs/settings.md b/docs/settings.md index 2d827cae42..6e6d0b50f7 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -45,6 +45,7 @@ Below are complete list of settings available along with their default values. I "PhysicsEngineName": "", "SpeedUnitFactor": 1.0, "SpeedUnitLabel": "m/s", + "Wind": { "X": 0, "Y": 0, "Z": 0 }, "Recording": { "RecordOnMove": false, "RecordInterval": 0.05, @@ -222,6 +223,10 @@ The `InitMethod` determines how object IDs are initialized at startup to generat If `MeshNamingMethod` is "" or "OwnerName" then we use mesh's owner name to generate random hash as object IDs. If it is "StaticMeshName" then we use static mesh's name to generate random hash as object IDs. Note that it is not possible to tell individual instances of the same static mesh apart this way, but the names are often more intuitive. +## Wind Settings + +This setting specifies the wind speed in World frame, in NED direction. Values are in m/s. By default, speed is 0, i.e. no wind. + ## Camera Settings The `CameraDefaults` element at root level specifies defaults used for all cameras. These defaults can be overridden for individual camera in `Cameras` element inside `Vehicles` as described later. From 9b422ac7345b9987c7effe508293c30dad0c4ea2 Mon Sep 17 00:00:00 2001 From: Rajat Singhal Date: Sat, 1 Aug 2020 13:27:14 +0530 Subject: [PATCH 4/4] [Unity] Set Wind API implementation --- .../AirsimWrapper/Source/SimMode/SimModeBase.cpp | 7 +++++++ .../AirsimWrapper/Source/SimMode/SimModeBase.h | 1 + .../AirsimWrapper/Source/SimMode/SimModeWorldBase.cpp | 5 +++++ .../AirsimWrapper/Source/SimMode/SimModeWorldBase.h | 2 ++ Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.cpp | 5 +++++ Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.h | 2 ++ 6 files changed, 22 insertions(+) diff --git a/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeBase.cpp b/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeBase.cpp index eaf72efaab..c8d5ef1129 100644 --- a/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeBase.cpp +++ b/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeBase.cpp @@ -86,6 +86,13 @@ void SimModeBase::setTimeOfDay(bool is_enabled, const std::string& start_datetim //throw std::domain_error("setTimeOfDay is not implemented by SimMode"); } +void SimModeBase::setWind(const msr::airlib::Vector3r& wind) const +{ + // should be overridden by derived class + unused(wind); + throw std::domain_error("setWind is not implemented by SimMode"); +} + std::unique_ptr SimModeBase::createApiServer() const { //this will be the case when compilation with RPCLIB is disabled or simmode doesn't support APIs diff --git a/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeBase.h b/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeBase.h index c8804f5076..6e4020c7ee 100644 --- a/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeBase.h +++ b/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeBase.h @@ -46,6 +46,7 @@ class SimModeBase virtual bool isPaused() const; virtual void pause(bool is_paused); virtual void continueForTime(double seconds); + virtual void setWind(const msr::airlib::Vector3r& wind) const; void startApiServer(); void stopApiServer(); bool isApiServerStarted(); diff --git a/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeWorldBase.cpp b/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeWorldBase.cpp index 0e943db03f..1712c1c480 100644 --- a/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeWorldBase.cpp +++ b/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeWorldBase.cpp @@ -94,6 +94,11 @@ void SimModeWorldBase::continueForTime(double seconds) physics_world_->continueForTime(seconds); } +void SimModeWorldBase::setWind(const msr::airlib::Vector3r& wind) const +{ + physics_engine_->setWind(wind); +} + void SimModeWorldBase::updateDebugReport(msr::airlib::StateReporterWrapper& debug_reporter) { unused(debug_reporter); diff --git a/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeWorldBase.h b/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeWorldBase.h index b186d31ac0..95cc54ed81 100644 --- a/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeWorldBase.h +++ b/Unity/AirLibWrapper/AirsimWrapper/Source/SimMode/SimModeWorldBase.h @@ -36,6 +36,8 @@ class SimModeWorldBase : public SimModeBase virtual void pause(bool is_paused) override; virtual void continueForTime(double seconds) override; + virtual void setWind(const msr::airlib::Vector3r& wind) const override; + private: std::unique_ptr physics_world_; PhysicsEngineBase* physics_engine_; diff --git a/Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.cpp b/Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.cpp index d352439ca0..e4c1d99b2b 100644 --- a/Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.cpp +++ b/Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.cpp @@ -173,4 +173,9 @@ bool WorldSimApi::isRecording() const return false; } +void WorldSimApi::setWind(const Vector3r& wind) const +{ + simmode_->setWind(wind); +}; + #pragma endregion diff --git a/Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.h b/Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.h index b81df7648b..fbc04694fb 100644 --- a/Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.h +++ b/Unity/AirLibWrapper/AirsimWrapper/Source/WorldSimApi.h @@ -59,6 +59,8 @@ class WorldSimApi : public msr::airlib::WorldSimApiBase virtual void stopRecording() override; virtual bool isRecording() const override; + virtual void setWind(const Vector3r& wind) const override; + private: SimModeBase * simmode_; std::string vehicle_name_;