Skip to content

Commit 05074d7

Browse files
committed
Merge remote-tracking branch 'upstream/ign-gazebo6' into nontemplate_views
2 parents ef76282 + b6a1133 commit 05074d7

File tree

7 files changed

+164
-0
lines changed

7 files changed

+164
-0
lines changed

src/EntityComponentManager.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,6 +1912,10 @@ void EntityComponentManager::SetChanged(
19121912
auto oneTimeIter = this->dataPtr->oneTimeChangedComponents.find(_type);
19131913
if (oneTimeIter != this->dataPtr->oneTimeChangedComponents.end())
19141914
oneTimeIter->second.erase(_entity);
1915+
1916+
// the component state is flagged as no change, so don't mark the
1917+
// corresponding entity as one with a modified component
1918+
return;
19151919
}
19161920

19171921
this->dataPtr->AddModifiedComponent(_entity);

src/EntityComponentManager_TEST.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2238,6 +2238,17 @@ TEST_P(EntityComponentManagerFixture,
22382238
EXPECT_EQ(ComponentState::NoChange,
22392239
manager.ComponentState(e2, c2->TypeId()));
22402240

2241+
// Marking a component that isn't changed as unchanged again shouldn't effect
2242+
// the ecm's changed state
2243+
manager.RunClearNewlyCreatedEntities();
2244+
EXPECT_EQ(0, manager.ChangedState().entities_size());
2245+
manager.SetChanged(e1, c1->TypeId(), ComponentState::NoChange);
2246+
EXPECT_EQ(ComponentState::NoChange,
2247+
manager.ComponentState(e1, c1->TypeId()));
2248+
EXPECT_FALSE(manager.HasOneTimeComponentChanges());
2249+
EXPECT_EQ(0u, manager.ComponentTypesWithPeriodicChanges().size());
2250+
EXPECT_EQ(0, manager.ChangedState().entities_size());
2251+
22412252
// Mark as changed
22422253
manager.SetChanged(e1, c1->TypeId(), ComponentState::PeriodicChange);
22432254

src/rendering/SceneManager.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,9 @@ bool SceneManager::AddSensor(Entity _gazeboId, const std::string &_sensorName,
17761776
return false;
17771777
}
17781778

1779+
// \todo(anyone) change to uint64_t once UserData supports this type
1780+
sensor->SetUserData("gazebo-entity", static_cast<int>(_gazeboId));
1781+
17791782
if (parent)
17801783
{
17811784
sensor->RemoveParent();

test/integration/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,9 @@ set_tests_properties(INTEGRATION_tracked_vehicle_system PROPERTIES TIMEOUT 300)
139139
if(TARGET INTEGRATION_examples_build)
140140
set_tests_properties(INTEGRATION_examples_build PROPERTIES TIMEOUT 320)
141141
endif()
142+
143+
if(VALID_DISPLAY AND VALID_DRI_DISPLAY)
144+
target_link_libraries(INTEGRATION_sensors_system
145+
ignition-rendering${IGN_RENDERING_VER}::ignition-rendering${IGN_RENDERING_VER}
146+
)
147+
endif()

test/integration/sensors_system.cc

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <gtest/gtest.h>
1919

2020
#include <string>
21+
#include <unordered_set>
2122
#include <vector>
2223

2324
#include <sdf/Model.hh>
@@ -27,6 +28,11 @@
2728
#include <ignition/transport/Node.hh>
2829
#include <ignition/utilities/ExtraTestMacros.hh>
2930

31+
#include <ignition/rendering/Camera.hh>
32+
#include <ignition/rendering/RenderEngine.hh>
33+
#include <ignition/rendering/RenderingIface.hh>
34+
#include <ignition/rendering/Scene.hh>
35+
3036
#include "ignition/gazebo/EntityComponentManager.hh"
3137
#include "ignition/gazebo/EventManager.hh"
3238
#include "ignition/gazebo/SdfEntityCreator.hh"
@@ -37,15 +43,57 @@
3743

3844
#include "ignition/gazebo/components/Model.hh"
3945
#include "ignition/gazebo/components/Name.hh"
46+
#include "ignition/gazebo/components/Sensor.hh"
4047
#include "ignition/gazebo/components/World.hh"
4148

49+
#include "ignition/gazebo/rendering/Events.hh"
50+
4251
#include "plugins/MockSystem.hh"
4352
#include "../helpers/EnvTestFixture.hh"
4453

4554
using namespace ignition;
4655
using namespace std::chrono_literals;
4756
namespace components = ignition::gazebo::components;
4857

58+
std::unordered_set<gazebo::Entity> g_sensorEntityIds;
59+
rendering::ScenePtr g_scene;
60+
61+
/////////////////////////////////////////////////
62+
void OnPostRender()
63+
{
64+
if (!g_scene)
65+
{
66+
g_scene = rendering::sceneFromFirstRenderEngine();
67+
}
68+
ASSERT_TRUE(g_scene);
69+
70+
EXPECT_LT(0u, g_scene->SensorCount());
71+
for (unsigned int i = 0; i < g_scene->SensorCount(); ++i)
72+
{
73+
auto sensor = g_scene->SensorByIndex(i);
74+
ASSERT_TRUE(sensor);
75+
EXPECT_TRUE(sensor->HasUserData("gazebo-entity"));
76+
auto variant = sensor->UserData("gazebo-entity");
77+
78+
// todo(anyone) change int to uint64_t once user data supports it
79+
const int *value = std::get_if<int>(&variant);
80+
ASSERT_TRUE(value);
81+
g_sensorEntityIds.insert(*value);
82+
}
83+
}
84+
85+
/////////////////////////////////////////////////
86+
void testSensorEntityIds(const gazebo::EntityComponentManager &_ecm,
87+
const std::unordered_set<gazebo::Entity> &_ids)
88+
{
89+
EXPECT_FALSE(_ids.empty());
90+
for (const auto & id : _ids)
91+
{
92+
auto sensorComp = _ecm.Component<gazebo::components::Sensor>(id);
93+
EXPECT_TRUE(sensorComp);
94+
}
95+
}
96+
4997
//////////////////////////////////////////////////
5098
class SensorsFixture : public InternalFixture<InternalFixture<::testing::Test>>
5199
{
@@ -127,20 +175,35 @@ TEST_F(SensorsFixture, IGN_UTILS_TEST_DISABLED_ON_MAC(HandleRemovedEntities))
127175

128176
gazebo::Server server(serverConfig);
129177

178+
common::ConnectionPtr postRenderConn;
179+
130180
// A pointer to the ecm. This will be valid once we run the mock system
131181
gazebo::EntityComponentManager *ecm = nullptr;
132182
this->mockSystem->preUpdateCallback =
133183
[&ecm](const gazebo::UpdateInfo &, gazebo::EntityComponentManager &_ecm)
134184
{
135185
ecm = &_ecm;
136186
};
187+
this->mockSystem->configureCallback =
188+
[&](const gazebo::Entity &,
189+
const std::shared_ptr<const sdf::Element> &,
190+
gazebo::EntityComponentManager &,
191+
gazebo::EventManager &_eventMgr)
192+
{
193+
postRenderConn = _eventMgr.Connect<gazebo::events::PostRender>(
194+
std::bind(&::OnPostRender));
195+
};
137196

138197
server.AddSystem(this->systemPtr);
139198
server.Run(true, 50, false);
140199
ASSERT_NE(nullptr, ecm);
141200

142201
testDefaultTopics();
143202

203+
testSensorEntityIds(*ecm, g_sensorEntityIds);
204+
g_sensorEntityIds.clear();
205+
g_scene.reset();
206+
144207
// We won't use the event manager but it's required to create an
145208
// SdfEntityCreator
146209
gazebo::EventManager dummyEventMgr;

tutorials.md.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Ignition @IGN_DESIGNATION_CAP@ library and how to use the library effectively.
3838
* \subpage test_fixture "Test Fixture": Writing automated CI tests
3939
* \subpage spherical_coordinates "Spherical coordinates": Working with latitude and longitude
4040
* \subpage python_interfaces Python interfaces
41+
* \subpage headless_rendering "Headless rendering": Access the GPU on a remote machine to produce sensor data without an X server.
4142

4243
**Migration from Gazebo classic**
4344

tutorials/headless_rendering.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
\page headless_rendering Headless Rendering
2+
3+
It is often desirable to run simulation on a remote computer, such as
4+
a computer managed by cloud provider, in order to paralellize work or access
5+
specific compute resources. Simulated sensors that require GPU access have
6+
historically been difficult to use on a remote computer due to OpenGL's
7+
X server requirement on linux systems. This issue can be resolved through
8+
installation and proper configuration of X, but the steps can be complex and
9+
error prone.
10+
11+
An easier solution is through the use of [EGL](https://www.khronos.org/egl), which allows for the the creation of rendering surfaces without an X server. Ignition Gazebo has added support for EGL via the `--headless-rendering` command line option. Use of EGL is only available with OGRE2.
12+
13+
Example usage:
14+
15+
```
16+
ign gazebo -v 4 -s --headless-rendering sensors_demo.sdf
17+
```
18+
19+
If you are using Ignition Gazebo as a library, then you can configure the
20+
server to use headless rendering through the
21+
`ServerConfig::SetHeadlessRendering(bool)` function. Make sure your SDF
22+
world uses OGRE2.
23+
24+
## AWS Example
25+
26+
This example will guide you through the process of launching and configuring
27+
an AWS GPU instance with Gazebo running headless. A GPU instance is
28+
recommended when sensors that require a render engine are used. It is
29+
possible to use a machine without a GPU, in which case OGRE will revert to
30+
software rendering. You can read more about [OGRE's EGL implementation
31+
here](https://www.ogre3d.org/2021/02/06/ogre-2-2-5-cerberus-released-and-egl-headless-support).
32+
33+
1. Go to the [AWS EC2 service](https://console.aws.amazon.com/ec2)
34+
2. Click the `Launch Instance` button in the upper right.
35+
3. Select `Ubuntu Server` version 20.04 or greater from the AMI list.
36+
4. Choose a GPU enabled instance type, such as `g3.4xlarge`.
37+
5. Enable `Auto-assign Public IP` on the `Configure Instance Details` step.
38+
This is not the best practice, but it simplifies this tutorial.
39+
6. Add around 200GB storage to your instance on the `Add Storage` step.
40+
7. Enable ssh source `Anywhere` on the `Configure Security Group` step.
41+
8. Review and launch your instance. Make sure to setup a key pair in the
42+
popup that appears after clicking `Launch`.
43+
1. You can configure other options as needed. Review the [AWS
44+
documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html) for additional help.
45+
9. Select the newly launched instance on the EC2 dashboard, and take note of
46+
the `Public IPv4 address`.
47+
10. SSH into your new machine instance.
48+
```
49+
ssh -i SSH_PEM_FILE_USED_DURING_LAUNCH ubuntu@EC_INSTANCE_PUBLIC_IP
50+
```
51+
12. Install Ubuntu drivers, which will install nvidia drivers:
52+
```
53+
sudo apt-get update
54+
sudo apt install ubuntu-drivers-common
55+
sudo ubuntu-drivers install
56+
```
57+
13. Add the `ubuntu` user to the `render` group, which is required to access
58+
to the dri interfaces.
59+
```
60+
sudo usermod -a -G render ubuntu
61+
```
62+
14. Reboot the machine and log back in.
63+
```
64+
sudo reboot
65+
```
66+
11. [Install Gazebo](https://ignitionrobotics.org/docs/latest/install).
67+
12. Run a Gazebo world that uses OGRE2 with camera sensors using headless rendering. This will enable EGL.
68+
```
69+
ign gazebo -v 4 -s -r --headless-rendering sensors_demo.sdf
70+
```
71+
13. Check that simulation is producing sensor data by ssh'ing into the EC2
72+
instance from a new terminal and echoing a sensor topic.
73+
```
74+
ssh -i SSH_PEM_FILE_USED_DURING_LAUNCH ubuntu@EC_INSTANCE_PUBLIC_IP
75+
ign topic -et /thermal_camera
76+
```

0 commit comments

Comments
 (0)