I have implemented a localization algorithm with 4 nodes topology and it is working fine but in the log file I am getting this error and I am not able to understand where the problem is. The algorithm gets stuck for sometime and this error appears and after that it again resumes the normal flow.how to remove this error ?
Exception in agent: simulator
java.lang.NullPointerException: Cannot get property 'location' on null object
Stack trace: ...
org.arl.unet.sim.SimulationAgent$_doMotion_closure1.doCall(initrc.groovy:236)
jdk.internal.reflect.GeneratedMethodAccessor103.invoke(Unknown Source)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ...
org.arl.unet.sim.SimulationAgent.doMotion(initrc.groovy:235)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ...
org.arl.unet.sim.SimulationAgent.this$dist$invoke$2(initrc.groovy)
org.arl.unet.sim.SimulationAgent$3.methodMissing(initrc.groovy)
jdk.internal.reflect.GeneratedMethodAccessor201.invoke(Unknown Source)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ...
org.arl.unet.sim.SimulationAgent$3.onExpiry(initrc.groovy:227)
org.arl.fjage.BackoffBehavior.action(BackoffBehavior.java:90)
org.arl.fjage.Agent.executeBehavior(Agent.java:774)
org.arl.fjage.Agent.run(Agent.java:811) ...
Following are my scripts :
simulation.groovy
import org.arl.fjage.*
println '''
3-node network
--------------
'''
platform = RealTimePlatform
simulate {
def m=node 'B', address:107, location: [-600.m, -22.m, -15.m], web:8081,api: 1101, shell:
true, mobility:true,stack: "$home/etc/setup2"
m.motionModel=[ [duration:1.minutes, speed:0.mps, heading:100.deg],
[time:1.minutes, duration:3.minutes, speed:1.mps, heading:100.deg]
]
node 'n1', address: 101, location: [900.m, 900.m, -15.m], web:8082,api: 1102, shell: 5101,
stack: "$home/etc/setup3"
node 'n2', address: 102, location: [-900.m, 900.m, -15.m], web:8083,api: 1103, shell: 5102,
stack: "$home/etc/setup3"
node 'n3', address: 103, location: [ -900.m, -800.m, -15.m], web:8084,api: 1104, shell: 5103,
stack: "$home/etc/setup3"
}
anchor_agent.groovy
import org.arl.fjage.*
import org.arl.fjage.Message
import org.arl.fjage.RealTimePlatform
import org.arl.unet.phy.*
import org.arl.unet.mac.*
import org.arl.unet.*
import org.arl.unet.PDU
import org.arl.unet.net.Router
import org.arl.unet.nodeinfo.NodeInfo
import org.arl.unet.localization.*
import org.arl.unet.localization.RangeNtf.*
import org.arl.unet.localization.Ranging.*
import org.arl.unet.localization.RangeReq
import org.arl.unet.net.RouteDiscoveryReq
class anchor_agent extends UnetAgent {
def addr;
def nme;
def phy;
def nodeInfo;
private final static PDU format = PDU.withFormat
{
uint16('source');
}
void startup()
{
def phy = agentForService Services.PHYSICAL;
subscribe topic(phy);
nodeInfo = agentForService Services.NODE_INFO;
}
void processMessage(Message msg)
{
phy = agentForService Services.PHYSICAL;
subscribe topic(phy);
addr = nodeInfo.address;
nme = nodeInfo.nodeName;
def datapacket = format.encode(source: addr);
if(msg instanceof DatagramNtf && msg.protocol==Protocol.MAC)
{
def n=rndint(4);
def k=rndint(5);
// def l=rndint(4);
def delay=(n+1)*(k+1);
println "Broadcast packet received at node "+nme;
println "Node "+nme+" will respond after "+ delay +" seconds"
println ' '
add new WakerBehavior(delay*1000,{
phy << new TxFrameReq(to: msg.from,
protocol: Protocol.MAC,
data: datapacket)
})
}
}
}
node_agent.groovy
import org.arl.fjage.*
import org.arl.fjage.Message
import org.arl.fjage.RealTimePlatform
import org.arl.unet.phy.*
import org.arl.unet.mac.*
import org.arl.unet.*
import org.arl.unet.PDU
import org.arl.unet.net.Router
import org.arl.unet.nodeinfo.NodeInfo
import org.arl.unet.localization.*
import org.arl.unet.localization.RangeNtf.*
import org.arl.unet.localization.Ranging.*
import org.arl.unet.localization.RangeReq
import org.arl.unet.net.RouteDiscoveryReq
import groovy.time.TimeCategory
import groovy.time.TimeDuration
class node_agent extends UnetAgent {
float neighbor_addr;
float distance;
def ranging;
def nodeInfo;
def start;
def stop;
def nos=0;
def xlist = [];
def ylist = [];
def zlist = [];
def dlist = [];
def adlist = [];
private final static PDU format = PDU.withFormat
{
uint16('source')
}
void startup()
{
def phy = agentForService Services.PHYSICAL;
subscribe topic(phy);
ranging = agentForService Services.RANGING;
subscribe topic(ranging);
nodeInfo = agentForService Services.NODE_INFO;
println 'Starting discovery...'
start = currentTimeMillis() ;
xlist.clear();
ylist.clear();
zlist.clear();
dlist.clear();
adlist.clear();
phy << new DatagramReq(to: 0, protocol:Protocol.MAC);
add new TickerBehavior(120000, {
nos=0;
xlist.clear();
ylist.clear();
zlist.clear();
dlist.clear();
adlist.clear();
println 'Starting discovery...'
start = currentTimeMillis() ;
phy << new DatagramReq(to: 0, protocol:Protocol.MAC);
})
}
void processMessage(Message msg)
{
if(msg instanceof RxFrameNtf && msg.protocol==Protocol.MAC && nos<3)
{
nos++;
def rx = format.decode(msg.data);
neighbor_addr=rx.source;
println "Found one anchor with address "+neighbor_addr;
adlist.add(neighbor_addr)
println adlist;
if(adlist.size()==3) //As soon as I get the address of 3 neighbour
{ //nodes query the range and coordinates information.
println "Found 3 anchor nodes, getting locations....";
println ' '
def i=0;
float n1=adlist[0];
float n2=adlist[1];
float n3=adlist[2];
//waker behavior to avoid collision in RangeNtf
add new WakerBehavior(0,{
ranging<< new RangeReq(to: n1,requestLocation: true)})
add new WakerBehavior(7000,{
ranging<< new RangeReq(to: n2,requestLocation: true)})
add new WakerBehavior(14000,{
ranging<< new RangeReq(to: n3,requestLocation: true)})
}
}
else if (msg instanceof RangeNtf )
{
distance = msg.getRange();
def locat=new double[3];
locat = msg.getPeerLocation();
double x,y,z;
x=locat[0];
y=locat[1];
z=locat[2];
xlist.add(x);
ylist.add(y);
zlist.add(z);
dlist.add(distance);
println " The coordinates of "+msg.to + " are " +locat+ " and the distance is "+distance;
if(dlist.size()==3)
{
println ' '
println 'x-coordinates'+ xlist;
println 'y-coordinates'+ ylist;
println 'z-coordinates'+ zlist;
println 'ranges'+ dlist;
BigDecimal X, Y, Va, Vb, Xa, Xb, Xc, Ya, Yb, Yc, Da, Db, Dc, tmp1, tmp2, tmp3, tmp4, tmp5;
Xa = xlist[0]; // Initializing the parameters
Ya = ylist[0];
Xb = xlist[1];
Yb = ylist[1];
Xc = xlist[2];
Yc = ylist[2];
Da = dlist[0];
Db = dlist[1];
Dc = dlist[2];
tmp1=(Math.pow(Xb, 2) - Math.pow(Xa, 2))
tmp2=(Math.pow(Yb, 2) - Math.pow(Ya, 2))
tmp3=(Math.pow(Db, 2) - Math.pow(Da, 2)) // tmp1, tmp2, tmp3 are intermediate variables to avoid overflow
Va = ( tmp1 + tmp2 - tmp3) / 2;
tmp1=(Math.pow(Xb, 2) - Math.pow(Xc, 2))
tmp2=(Math.pow(Yb, 2) - Math.pow(Yc, 2))
tmp3=(Math.pow(Db, 2) - Math.pow(Dc, 2)) // tmp1, tmp2, tmp3 are intermediate variables to avoid overflow
Vb = (tmp1 + tmp2 - tmp3) / 2;
tmp4=(Va * (Yb - Yc) - Vb * (Yb - Ya))
tmp5=((Yb - Yc) * (Xb - Xa) - (Yb - Ya) * (Xb - Xc)) // tmp4, tmp5 are intermediate variables to avoid overflow
X = tmp4 / tmp5;
tmp4=(Va * (Xb - Xc) - Vb * (Xb - Xa))
tmp5=((Yb - Ya) * (Xb - Xc) - (Xb - Xa) * (Yb - Yc)) // tmp4, tmp5 are intermediate variables to avoid overflow
Y = tmp4 / tmp5
X = Math.round(X * 100000) / 100000
Y = Math.round(Y * 100000) / 100000 // precision of upto 5 digits after decimal
println ' '
println 'THE ACTUAL COORDINATES AT THIS INSTANCE ARE '+ nodeInfo.location;
stop = currentTimeMillis() ;
int td = stop - start;
td=td/1000;
def e1=td*0.98480775301;
def e2=td*(-0.17364817766);
///////////////////////////////////////////////////////////
def p=Math.pow((X-(nodeInfo.location[0])),2);
def q=Math.pow((Y-(nodeInfo.location[1])),2);
def r=Math.sqrt(p+q);
r=Math.round(r * 100000) / 100000;
//////////////////////////////////////////////////////////
BigDecimal X1,Y1;
Y1=Y+e2;
X1=X+e1;
def j=Math.pow((X1-(nodeInfo.location[0])),2);
def k=Math.pow((Y1-(nodeInfo.location[1])),2);
def l=Math.sqrt(p+q);
l=Math.round(l * 100000) / 100000;
//////////////////////////////////////////////////////////
if(r < l)
{
println "The coordinates of the Blind node are "
println "("+ X + " , " + Y + " , " + zlist[0] + ")" ;
println "Distance between actual coordinates and estimated coordinates: r ";
println ' '+r;
}
else{
println "The coordinates of the Blind node are "
println "("+ X1 + " , " + Y1 + " , " + zlist[0] + ")" ;
println "Distance between actual coordinates and estimated coordinates: l ";
println ' '+l;
}
println "Total time taken "+td+' seconds';
xlist.clear();
ylist.clear();
zlist.clear();
dlist.clear();
adlist.clear();
}
}
}
}
setup2.groovy
import org.arl.fjage.Agent
boolean loadAgentByClass(String name, String clazz) {
try {
container.add name, Class.forName(clazz).newInstance()
return true
} catch (Exception ex) {
return false
}
}
boolean loadAgentByClass(String name, String... clazzes) {
for (String clazz: clazzes) {
if (loadAgentByClass(name, clazz)) return true
}
return false
}
loadAgentByClass 'arp', 'org.arl.unet.addr.AddressResolution'
loadAgentByClass 'ranging', 'org.arl.unet.localization.Ranging'
loadAgentByClass 'mac', 'org.arl.unet.mac.CSMA'
loadAgentByClass 'uwlink', 'org.arl.unet.link.ECLink', 'org.arl.unet.link.ReliableLink'
loadAgentByClass 'transport', 'org.arl.unet.transport.SWTransport'
loadAgentByClass 'router', 'org.arl.unet.net.Router'
loadAgentByClass 'rdp', 'org.arl.unet.net.RouteDiscoveryProtocol'
loadAgentByClass 'statemanager', 'org.arl.unet.state.StateManager'
//loadAgentByClass 'pri', 'org.arl.unet.UnetAgent.node_agent'
container.add 'remote', new org.arl.unet.remote.RemoteControl(cwd: new File(home, 'scripts'), enable: false)
container.add 'bbmon', new org.arl.unet.bb.BasebandSignalMonitor(new File(home, 'logs/signals-0.txt').path, 64)
container.add 'myagent' , new node_agent()
setup3.groovy
import org.arl.fjage.Agent
boolean loadAgentByClass(String name, String clazz) {
try {
container.add name, Class.forName(clazz).newInstance()
return true
} catch (Exception ex) {
return false
}
}
boolean loadAgentByClass(String name, String... clazzes) {
for (String clazz: clazzes) {
if (loadAgentByClass(name, clazz)) return true
}
return false
}
loadAgentByClass 'arp', 'org.arl.unet.addr.AddressResolution'
loadAgentByClass 'ranging', 'org.arl.unet.localization.Ranging'
loadAgentByClass 'mac', 'org.arl.unet.mac.CSMA'
loadAgentByClass 'uwlink', 'org.arl.unet.link.ECLink', 'org.arl.unet.link.ReliableLink'
loadAgentByClass 'transport', 'org.arl.unet.transport.SWTransport'
loadAgentByClass 'router', 'org.arl.unet.net.Router'
loadAgentByClass 'rdp', 'org.arl.unet.net.RouteDiscoveryProtocol'
loadAgentByClass 'statemanager', 'org.arl.unet.state.StateManager'
container.add 'remote', new org.arl.unet.remote.RemoteControl(cwd: new File(home, 'scripts'), enable: false)
container.add 'bbmon', new org.arl.unet.bb.BasebandSignalMonitor(new File(home, 'logs/signals-0.txt').path, 64)
container.add 'resp_agent' , new anchor_agent()
I ran your simulation using the code you provided and managed to reproduce the error. Tracing through the logs, I found that the error occurred on the third motion update for node B, whereas your simulation script only seemed to have 2 legs in the motion model. That gave me a hint as to what the problem was.
Your motion model states:
[
[duration:1.minutes, speed:0.mps, heading:100.deg],
[time:1.minutes, duration:3.minutes, speed:1.mps, heading:100.deg]
]
This has 2 problems:
I updated the motion model to:
[
[duration:1.minutes, speed:0.mps, heading:100.deg],
[speed:1.mps, heading:100.deg]
]
and the exception goes away. The second leg continues forever. Alternatively, if you wanted the node to stop moving after 3 minutes, you could do:
[
[duration:1.minutes, speed:0.mps, heading:100.deg],
[duration:3.minutes, speed:1.mps, heading:100.deg],
[speed:0.mps]
]
and that should work too.
P.S. The exception thrown by UnetSim for this case was not very informative and so I'll file an issue to improve error checking/messages for motion models.