节点固定速度移动(ConstantVelocityMobilityModel)的实现
在官方所给的示例中,只能找到RandomWalk2dMobilityModel
的实现方法,或者查阅官方文档,可以找到GaussMarkovMobilityModel
的示例代码。下面是截取的实现RandomWalk2dMobilityModel
的部分代码:
MobilityHelper mobility;
mobility.SetPositionAllocator("ns3::GridPositionAllocator",
"MinX", DoubleValue(0.0),
"MinY", DoubleValue(0.0),
"DeltaX", DoubleValue(5.0),
"DeltaY", DoubleValue(10.0),
"GridWidth", UintegerValue(3),
"LayoutType", StringValue("RowFirst"));
mobility.SetMobilityModel("ns::RandomWalk2dMobilityModel",
"Bounds", RectangleValue(Rectangle(-50, 50, -50, 50)));
mobility.Install(nodes);
在上面的代码中,首先使用了MobilityHelper
类声明对象mobility,然后通过调用SetPositionAllocation()
函数初始化节点的初始位置,接着后面调用SetMobilityModel()
函数设置要使用的移动模型,这里的ns::RandomWalk2dMobilityModel
是使用的移动模型类名。
根据官方文档所给描述,SetMobilityModel()
第一个参数为要使用的移动模型,第二个参数为模型类初始化的形参名,第三个参数为第二个参数中指定形参的所需传入的实参。后面每两个参数为一组,每组中第一个为形参名,第二个为实参。可以通过将参数信息传递给函数SetMobilityModel
,间接将参数信息传递给所需的移动模型来进行移动模型的初始化。
很容易可以看出,上面的代码对RandomWalk2dMobilityModel
的Bounds
属性进行了初始化。
在使用其他移动模型时,也可以使用类似的方法去初始化移动模型属性。
下面我们使用这个方法来初始化一个ConstantVelocityMobilityModel
的使用,参照上面的形式,结合官方文档中的属性说明,我们可以有以下代码:
mobility.SetMobilityModel("ns::ConstantVelocityMobilityModel",
"Velocity", VectorValue(Vector(10.0, 0, 0)));
mobility.Install(nodes);
上述代码设置移动模型为ConstantVelocityMobilityModel
,并初始化Velocity
属性,即节点移动的固定速度,通过官方文档,可以知道这里我们需要传入Vector3D
类的数值。
但当我们运行这段代码时,会出现下面这样的报错信息
重点关注其中这一段ns3::Mobility: initial value cannot be set using attributes,大概意思就是Velocity
属性不能这样初始化,重新仔细看一遍官方文档可以发现,在其他移动模型,例如RandomWalk2dMobilityModel
中,官方文档属性说明的Flags
项中,是有一个construct
的标识的。
那么我们可以猜测这个是表示我们可以使用构造器来初始化这个属性,而通过查阅源码,证实了我们的想法,在类ConstantVelocityMobilityModel
的定义中,是没有关于属性Velocity
的构造器的,只存在一个空参构造器。
而同时我们也注意到,在ConstantVelocityMobilityModel
类中,存在一个名为SetVelocity()
的public方法,也就是说我们也许可以通过调用这个方法来给节点设置速度。
因为我们是通过SetMobilityModel()
来设置节点的移动模型的,我们并没有该移动模型的对象,那么我们的第一步应该是先获取到这个对象实例,我们可以通过节点身上的GetObject()
方法来获取,下面是示例代码:
cvmm = node->GetObject<ConstantVelocityMobilityModel>();
现在我们已经得到了ConstantVelocityMobilityModel
的示例对象,下面可以调用SetVelocity()
来设置节点固定移动的速度了。
cvmm->SetVelocity(Vector(10.0, 0, 0));
如果想同时设置多个节点的速度,可以参考下面的代码:
for (uint n=0 ; n < nodes.GetN() ; n++)
{
Ptr<ConstantVelocityMobilityModel> mob = nodes.Get(n)->GetObject<ConstantVelocityMobilityModel>();
mob->SetVelocity(Vector(10.0, 0, 0));
}
SetVelocity()
同样接收一个Vector
类型的数值,Vector
中三个参数分别为三个轴上的速度。
完成上述工作后,我们运行脚本查看结果,可以发现并没有报错,成功运行,节点实现了以固定速度的移动。
在0秒时,节点的初始位置为下图。
在时间到1秒时,两个节点都想右移动了10个单位距离。
在2.0015秒时,节点1向节点0发送了UDP数据。
上述模拟使用了一组PointToPoint
节点,分别安装了UdpClient
和UdpServer
,可以看到,节点可以保证正常数据传输的过程中保持移动。
完整代码如下:
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/netanim-module.h" // 可视化
#include "ns3/mobility-module.h"
using namespace ns3;
int main(int argc, char *argv[]) {
// 日志输出记录
Time::SetResolution (Time::NS);
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
// LogComponentEnableAll (LOG_LEVEL_INFO);
// 创建卫星节点
NodeContainer nodes;
nodes.Create(2);
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer devices;
devices = pointToPoint.Install(nodes);
// 运动模块
MobilityHelper mobility;
mobility.SetPositionAllocator("ns3::GridPositionAllocator",
"MinX", DoubleValue(0.0),
"MinY", DoubleValue(0.0),
"DeltaX", DoubleValue(5.0),
"DeltaY", DoubleValue(10.0),
"GridWidth", UintegerValue(3),
"LayoutType", StringValue("RowFirst"));
mobility.SetMobilityModel("ns3::ConstantVelocityMobilityModel");
mobility.Install(nodes);
// 设置节点移动速度
for(uint n = 0; n < nodes.GetN(); n++)
{
Ptr<ConstantVelocityMobilityModel> mob = nodes.Get(n)->GetObject<ConstantVelocityMobilityModel>();
mob->SetVelocity(Vector(10.0, 0, 0));
}
InternetStackHelper stack;
stack.Install(nodes);
Ipv4AddressHelper address;
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = address.Assign(devices);
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install(nodes.Get(0));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
UdpEchoClientHelper echoClient (interfaces.GetAddress(0), 9);
echoClient.SetAttribute("MaxPackets", UintegerValue(5));
echoClient.SetAttribute("Interval", TimeValue(Seconds(1.0)));
echoClient.SetAttribute("PacketSize", UintegerValue(1024));
ApplicationContainer clientApps;
clientApps.Add(echoClient.Install(nodes.Get(1)));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
AnimationInterface::SetConstantPosition (nodes.Get (0), 10, 30); //位置
AnimationInterface::SetConstantPosition (nodes.Get (1), 40, 30);
AnimationInterface anim ("satellite.xml"); // Mandatory名字
anim.EnablePacketMetadata (); // Optional
anim.EnableIpv4RouteTracking ("routingtable-satellite.xml", Seconds (0), Seconds (5), Seconds (0.25)); //Optional
Simulator::Run();
Simulator::Destroy();
return 0;
}