A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
outdoor-group-mobility-example.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Institute for the Wireless Internet of Things, Northeastern University,
3 * Boston, MA Copyright (c) 2021, University of Washington: refactor for hierarchical model
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Michele Polese <michele.polese@gmail.com>
19 * Heavily edited by Tom Henderson to use HierarchicalMobilityModel
20 */
21
22/**
23 * This example shows how to use the ns3::HierarchicalMobilityModel
24 * to construct a Reference Point Group Mobility model (RPGM) model
25 * as described in "A survey of mobility models for ad hoc network
26 * research" by Tracy Camp, Jeff Boleng, and Vanessa Davies, Wireless
27 * Communications and Mobile Computing, 2002: vol. 2, pp. 2483-502.
28 * This example is closely related to the group mobility example
29 * `src/mobility/group/reference-point-group-mobility-example.cc`
30 * except that this version is buildings-aware.
31 *
32 * The HierarchicalMobilityModel is composed of two mobility models;
33 * a parent and a child. The position of the child is expressed
34 * in reference to the position of the parent. For group mobility,
35 * each node in the group can install the same parent mobility model
36 * and different child mobility models. The parent mobility model
37 * in this case, the "RandomWalk2dOutdoorMobilityModel", is
38 * buildings-aware. The child mobility models are not, but the
39 * "Tolerance" attribute is defined on the parent model such that the
40 * child mobility models do not result in movement through a building
41 * wall.
42 *
43 * Standard ns-3 mobility model course change output is traced in
44 * outdoor-group-mobility-course-change.mob. Time series data of position
45 * is traced in outdoor-group-mobility-time-series.mob. This time series
46 * data can be animated with a corresponding Bash script. Another program
47 * output is the list of buildings ("outdoor-group-mobility-buildings.txt").
48 *
49 * There is one program option: 'useHelper'. This is simply for code
50 * demonstration purposes; it selects the branch of code that is used
51 * to either configure the mobility using a helper object, or
52 * to directly configure using CreateObject<> () and handling of pointers.
53 * The traces generated should be the same.
54 *
55 * Randomness in this program is due to the parent mobility model which
56 * executes a random walk, while the child mobility models are set as
57 * constant position offsets from the parent. Slightly different motion
58 * can be obtained by changing the ns-3 'RunNumber' value (see the
59 * documentation on ns-3 random variables).
60 */
61
62#include "ns3/buildings-module.h"
63#include "ns3/core-module.h"
64#include "ns3/network-module.h"
65#include <ns3/mobility-module.h>
66
67#include <iostream>
68
69using namespace ns3;
70
71NS_LOG_COMPONENT_DEFINE("OutdoorGroupMobilityExample");
72
73/// The time series file.
74std::ofstream g_timeSeries;
75
76/**
77 * Print the node position to the time series file.
78 *
79 * \param node The node.
80 */
81void
83{
84 if (!node)
85 {
86 return;
87 }
88 Ptr<MobilityModel> model = node->GetObject<MobilityModel>();
89 if (!model)
90 {
91 return;
92 }
93 NS_LOG_LOGIC("Node: " << node->GetId() << " Position: " << model->GetPosition());
94 g_timeSeries << Simulator::Now().GetSeconds() << " " << node->GetId() << " "
95 << model->GetPosition() << std::endl;
96}
97
98/**
99 * Print the buildings list in a format that can be used by Gnuplot to draw them.
100 *
101 * \param filename The output filename.
102 */
103void
105{
106 std::ofstream outFile;
107 outFile.open(filename, std::ios_base::out | std::ios_base::trunc);
108 if (!outFile.is_open())
109 {
110 NS_LOG_ERROR("Can't open file " << filename);
111 return;
112 }
113 uint32_t index = 1;
114 for (auto it = BuildingList::Begin(); it != BuildingList::End(); ++it)
115 {
116 ++index;
117 Box box = (*it)->GetBoundaries();
118 outFile << "set object " << index << " rect from " << box.xMin << "," << box.yMin << " to "
119 << box.xMax << "," << box.yMax << std::endl;
120 }
121}
122
123int
124main(int argc, char* argv[])
125{
126 Time simTime = Seconds(800);
127 uint32_t numPrints = 800;
128 bool useHelper = false;
129
130 CommandLine cmd(__FILE__);
131 cmd.AddValue("useHelper", "Whether to use helper code", useHelper);
132 cmd.Parse(argc, argv);
133
134 g_timeSeries.open("outdoor-group-mobility-time-series.mob");
135
137 n.Create(3);
138
139 // The primary mobility model is the RandomWalk2dOutdoorMobilityModel
140 // defined within this bounding box (along with four buildings, not shown):
141 //
142 // (0,50) (100,50)
143 // +-------------------------+
144 // | |
145 // | |
146 // | |
147 // | |
148 // | |
149 // +-------------------------+
150 // (0,0) (100,0)
151 //
152 //
153 // There are two buildings centered at (50,10) and (50,40), and two
154 // additional small buildings centered at (20,25) and (80,25) that
155 // create obstacles for the nodes to avoid.
156
157 std::vector<Ptr<Building>> buildingVector;
158 Ptr<Building> building = CreateObject<Building>();
159 building->SetBoundaries(Box(45, 55, 5, 15, 0, 10));
160 buildingVector.push_back(building);
161 building = CreateObject<Building>();
162 building->SetBoundaries(Box(45, 55, 35, 45, 0, 10));
163 buildingVector.push_back(building);
164 building = CreateObject<Building>();
165 building->SetBoundaries(Box(17.5, 22.5, 22.5, 27.5, 0, 10));
166 buildingVector.push_back(building);
167 building = CreateObject<Building>();
168 building->SetBoundaries(Box(77.5, 82.5, 22.5, 27.5, 0, 10));
169 buildingVector.push_back(building);
170
171 // print the list of buildings to file
172 PrintGnuplottableBuildingListToFile("outdoor-group-mobility-buildings.txt");
173
174 // The program now branches into two: one using the low-level API, and
175 // one using the GroupMobilityHelper. Both branches result in equivalent
176 // configuration.
177
178 int64_t streamIndex = 1;
179 if (!useHelper)
180 {
181 // The reference (parent) mobility model starts at coordinate (10, 10, 0)
182 // and performs a buildings-aware random walk.
183 //
185 CreateObject<RandomWalk2dOutdoorMobilityModel>();
186 outdoorMm->SetAttribute("Bounds", RectangleValue(Rectangle(0, 100, 0, 50)));
187 // The tolerance value is used to prevent the child mobility models from
188 // crossing building walls. The child mobility models are defined as
189 // offsets from the parent but are not buildings-aware, so it could be
190 // the case that the parent mobility model was just outside of a wall
191 // but the child mobility model was inside of a wall. The tolerance
192 // value (in meters) prevents the composite position from passing
193 // through a building wall.
194 outdoorMm->SetAttribute("Tolerance", DoubleValue(2));
195 // The initial position can be directly set
196 outdoorMm->SetPosition(Vector(10, 10, 0));
197 streamIndex += outdoorMm->AssignStreams(streamIndex);
198
199 // Each HierarchicalMobilityModel contains the above model as the Parent,
200 // and a user defined model as the Child. Two MobilityModel objects are
201 // instantiated per node, and each node also shares the same parent model.
202
203 // Mobility model for the first node (node 0)
204 Ptr<HierarchicalMobilityModel> hierarchical0 = CreateObject<HierarchicalMobilityModel>();
205 hierarchical0->SetParent(outdoorMm);
206
207 // Child model for the first node (node 0)
208 Ptr<ConstantPositionMobilityModel> child0 = CreateObject<ConstantPositionMobilityModel>();
209 child0->SetPosition(Vector(1, 0, 0)); // 1 m offset from parent position
210 // There is no need to AssignStreams() to child0 because the position
211 // is constant and deterministic
212 hierarchical0->SetChild(child0);
213 n.Get(0)->AggregateObject(hierarchical0);
214
215 // Repeat for other two nodes
216 Ptr<HierarchicalMobilityModel> hierarchical1 = CreateObject<HierarchicalMobilityModel>();
217 hierarchical1->SetParent(outdoorMm); // Same parent as before
218 Ptr<ConstantPositionMobilityModel> child1 = CreateObject<ConstantPositionMobilityModel>();
219 child1->SetPosition(Vector(-1, 0, 0));
220 hierarchical1->SetChild(child1);
221 n.Get(1)->AggregateObject(hierarchical1);
222 Ptr<HierarchicalMobilityModel> hierarchical2 = CreateObject<HierarchicalMobilityModel>();
223 hierarchical2->SetParent(outdoorMm); // Same parent as before
224 Ptr<ConstantPositionMobilityModel> child2 = CreateObject<ConstantPositionMobilityModel>();
225 child2->SetPosition(Vector(0, 1, 0));
226 hierarchical2->SetChild(child2);
227 n.Get(2)->AggregateObject(hierarchical2);
228 }
229 else
230 {
231 // This branch demonstrates an equivalent set of commands but using
232 // the GroupMobilityHelper
234
235 // The helper provides a method to set the reference mobility model
236 // for construction by an object factory, but in this case, since we
237 // are using the WaypointMobilityModel, which requires us to add
238 // waypoints directly on the object, we will just pass in the pointer.
239 group.SetReferenceMobilityModel("ns3::RandomWalk2dOutdoorMobilityModel",
240 "Bounds",
241 RectangleValue(Rectangle(0, 100, 0, 50)),
242 "Tolerance",
243 DoubleValue(2));
244 Ptr<ListPositionAllocator> listPosition = CreateObject<ListPositionAllocator>();
245 listPosition->Add(Vector(10, 10, 0));
246 group.SetReferencePositionAllocator(listPosition);
247
248 group.SetMemberMobilityModel("ns3::ConstantPositionMobilityModel");
249 listPosition = CreateObject<ListPositionAllocator>();
250 listPosition->Add(Vector(1, 0, 0)); // first child
251 listPosition->Add(Vector(-1, 0, 0)); // second child
252 listPosition->Add(Vector(0, 1, 0)); // second child
253 group.SetMemberPositionAllocator(listPosition);
254
255 // Install to all three nodes
256 group.Install(n);
257
258 // After installation, use the helper to make the equivalent
259 // stream assignments as above
260 group.AssignStreams(n, streamIndex);
261 }
262
263 AsciiTraceHelper ascii;
265 ascii.CreateFileStream("outdoor-group-mobility-course-change.mob"));
266
267 // Use a logging PrintPosition() to record time-series position
268 for (unsigned int i = 0; i < numPrints; i++)
269 {
270 for (auto nodeIt = n.Begin(); nodeIt != n.End(); ++nodeIt)
271 {
272 Simulator::Schedule(NanoSeconds(i * simTime.GetNanoSeconds() / numPrints),
274 (*nodeIt));
275 }
276 }
277
278 Simulator::Stop(simTime);
280 g_timeSeries.close();
282
283 return 0;
284}
Manage ASCII trace files for device models.
Definition: trace-helper.h:174
Ptr< OutputStreamWrapper > CreateFileStream(std::string filename, std::ios::openmode filemode=std::ios::out)
Create and initialize an output stream object we'll use to write the traced bits.
a 3d box
Definition: box.h:35
double yMax
The y coordinate of the top bound of the box.
Definition: box.h:116
double xMin
The x coordinate of the left bound of the box.
Definition: box.h:110
double yMin
The y coordinate of the bottom bound of the box.
Definition: box.h:114
double xMax
The x coordinate of the right bound of the box.
Definition: box.h:112
static Iterator End()
static Iterator Begin()
Parse command-line arguments.
Definition: command-line.h:232
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Helper class used to assign positions and mobility models to nodes for a group mobility configuration...
void SetMemberMobilityModel(std::string type, Ts &&... args)
Configure the mobility model which will be installed as the member (child) mobility model during Grou...
int64_t AssignStreams(NodeContainer c, int64_t stream)
Assign a fixed random variable stream number to the random variables used by the mobility models on t...
void SetMemberPositionAllocator(Ptr< PositionAllocator > allocator)
Set the position allocator which will be used to allocate the initial position of the member mobility...
void Install(Ptr< Node > node)
Install and configure a hierarchical mobility model to the given node, based on the configured refere...
void SetReferenceMobilityModel(Ptr< MobilityModel > mobility)
Set the reference mobility model which will be installed as the parent mobility model during GroupMob...
void SetReferencePositionAllocator(Ptr< PositionAllocator > allocator)
Set the position allocator which will be used to allocate the initial position of the reference mobil...
static void EnableAsciiAll(Ptr< OutputStreamWrapper > stream)
Keep track of the current position and velocity of an object.
keep track of a set of node pointers.
Iterator End() const
Get an iterator which indicates past-the-last Node in the container.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
Iterator Begin() const
Get an iterator which refers to the first Node in the container.
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:309
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
a 2d rectangle
Definition: rectangle.h:35
AttributeValue implementation for Rectangle.
Definition: rectangle.h:125
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:418
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:254
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
Time NanoSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1362
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns cmd
Definition: second.py:40
void PrintGnuplottableBuildingListToFile(std::string filename)
Print the buildings list in a format that can be used by Gnuplot to draw them.
std::ofstream g_timeSeries
The time series file.
void PrintPosition(Ptr< Node > node)
Print the node position to the time series file.