2

我已经实现了一个具有 4 个节点拓扑的本地化算法,它工作正常,但是在日志文件中我收到了这个错误,我无法理解问题出在哪里。算法卡住了一段时间,出现此错误,然后再次恢复正常流程。如何消除此错误?

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) ...

以下是我的脚本:

模拟.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"


}

锚代理.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() 
4

1 回答 1

2

我使用您提供的代码运行了您的模拟,并设法重现了该错误。跟踪日志,我发现错误发生在节点 B 的第三次运动更新时,而您的模拟脚本在运动模型中似乎只有两条腿。这给了我一个关于问题所在的提示。

您的运动模型指出:

[
  [duration:1.minutes, speed:0.mps, heading:100.deg], 
  [time:1.minutes, duration:3.minutes, speed:1.mps, heading:100.deg]
]

这有两个问题:

  1. 第一回合的持续时间为 1 分钟。第二回合从 1 分钟开始。虽然这是一致的,但它是重复的信息,并且有可能造成不一致。最好指定一个或另一个,但不要同时指定两者。在您的情况下,这不是异常的原因。
  2. 第二回合的持续时间为 3 分钟。之后发生的事情是未指定的。所以模拟器尝试进行第三次运动更新,没有找到它的规范,并抛出异常。

我将运动模型更新为:

[
  [duration:1.minutes, speed:0.mps, heading:100.deg], 
  [speed:1.mps, heading:100.deg]
]

异常消失了。第二回合永远继续。或者,如果您希望节点在 3 分钟后停止移动,您可以执行以下操作:

[
  [duration:1.minutes, speed:0.mps, heading:100.deg], 
  [duration:3.minutes, speed:1.mps, heading:100.deg],
  [speed:0.mps]
]

这也应该有效。

PS UnetSim 针对这种情况抛出的异常信息不是很丰富,因此我将提交一个问题以改进运动模型的错误检查/消息。

于 2021-04-01T17:06:33.953 回答