3

我正在尝试使用广播请求从相邻节点获取坐标并将它们存储到列表中。我只能得到一个响应,我认为这是因为节点同时响应时响应之间的冲突而发生的。我曾尝试在相邻节点的代理上使用带有随机退避的退避行为,但它没有解决问题。如何同步机制以避免冲突?我为每个盲节点(将发出广播请求)和相邻节点编写了一个代理。

以下是代码片段。

盲节点上的代理:

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 node_agent extends UnetAgent {
    float neighbor_addr;
    float distance;
    
    def xlist = [];
    def ylist = [];
    def zlist = [];

    def dlist = [];
    
  private final static PDU format = PDU.withFormat
  {
    uint16('source')
  }

  void startup() 
  {
    def phy = agentForService Services.PHYSICAL;
    subscribe topic(phy);

    println 'Starting discovery...'
    phy << new DatagramReq(to: 0, protocol:Protocol.MAC);
  }
    
  void processMessage(Message msg) 
  {
    def ranging = agentForService Services.RANGING;
    subscribe topic(ranging);

    if(msg instanceof RxFrameNtf && msg.protocol==Protocol.MAC)
    {
       def rx = format.decode(msg.data);
       neighbor_addr=rx.source;
       
       println "Found one neighbour with address "+neighbor_addr;
        
       ranging<< new RangeReq(to: neighbor_addr,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;
       println xlist;
       println ylist;
       println zlist;
       println dlist;
    }
  }  
}

相邻节点上的代理:

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;
    
  private final static PDU format = PDU.withFormat
    {
        uint16('source')
    }
  
  void startup() 
  {
    def phy = agentForService Services.PHYSICAL;
    subscribe topic(phy);
  }
  
  void processMessage(Message msg) 
  {
    def phy = agentForService Services.PHYSICAL;
    subscribe topic(phy);
    
    def nodeInfo = agentForService Services.NODE_INFO;
    addr = nodeInfo.address;

    def datapacket = format.encode(source: addr);
    
    if(msg instanceof DatagramNtf && msg.protocol==Protocol.MAC)
    { 
       def n=rndint(3);
       add new BackoffBehavior(n*1000,{
  
       phy << new TxFrameReq(to: msg.from, 
                             protocol: Protocol.MAC, 
                             data: datapacket)})
                             backoff(n*1000)})
    }
  }
}

模拟脚本:

import org.arl.fjage.*

println '''
3-node network
--------------
'''
platform = RealTimePlatform

simulate {
  
  node 'B', address: 101, location: [ 0.km, 0.km, -15.m], web:8081,api: 1101, shell: true, stack: "$home/etc/setup2"
  
  node '1', address: 102, location: [ 0.km, 1.km, -15.m], web:8082,api: 1102, shell: 5101, stack: "$home/etc/setup3"
  node '2', address: 103, location: [-900.m, 0.km, -15.m], web:8083,api: 1103, shell: 5102, stack: "$home/etc/setup3"
  node '3', address: 104, location: [ 600.m, 0.km, -15.m], web:8084,api: 1104, shell: 5103, stack: "$home/etc/setup3"

}



 
4

1 回答 1

3

我已经简化了您的代理并制作了一个工作示例。锚点发现分为两个阶段:(1)找到锚点周围,(2)获取它们的位置。分解它的原因是您希望初始发现需要最少的通道访问权限以减少冲突的机会。一旦您知道周围有哪些节点,就可以更好地控制以后的位置请求。

我已将代理组合成一个模拟脚本,因此您可以简单地将代码复制到文件中并运行它:

import org.arl.fjage.*
import org.arl.unet.*
import org.arl.unet.localization.*

platform = RealTimePlatform

class NodeAgent extends UnetAgent {

  AgentID phy
  AgentID ranging
  List<Integer> anchors = []
  def anchorLocations = [:]

  void startup() {
    phy = agentForService Services.PHYSICAL
    ranging = agentForService Services.RANGING
    subscribe topic(phy)
    log.info 'Starting anchor discovery...'
    phy << new DatagramReq(to: 0, protocol: Protocol.USER)
    // wait for 15 seconds for all nodes to respond before trying to get their locations
    add new WakerBehavior(15000, this.&getLocations)
  }

  void getLocations() {
    log.info "Discovered ${anchors.size()} anchor(s), getting locations..."
    anchors.eachWithIndex { addr, i ->
      // request location for each node 5 seconds apart
      add new WakerBehavior(5000*i, {
        log.info "Asking node ${addr} for its location..."
        ranging << new RangeReq(to: addr, requestLocation: true)
      })
    }
  }

  void processMessage(Message msg) {
    if (msg instanceof DatagramNtf && msg.protocol == Protocol.USER) {
      log.info "Discovered node ${msg.from}"
      anchors.add(msg.from)
    }
    if (msg instanceof RangeNtf) {
      log.info "Got location of anchor ${msg.to}: ${msg.peerLocation}"
      anchorLocations[msg.to] = msg.peerLocation
    }
  }

}

class AnchorAgent extends UnetAgent {

  AgentID phy
  AgentLocalRandom rnd

  void startup() {
    rnd = AgentLocalRandom.current()
    phy = agentForService Services.PHYSICAL
    subscribe topic(phy)
  }

  void processMessage(Message msg) {
    if (msg instanceof DatagramNtf && msg.protocol == Protocol.USER) {
      // respond back to a discovery request with a random backoff of up to 13 seconds
      long backoff = rnd.nextDouble(0, 13000)
      log.info "Discovery request from ${msg.from}, will respond after ${backoff} ms"
      add new WakerBehavior(backoff, {
        log.info 'Responding...'
        phy << new DatagramReq(to: msg.from, protocol: Protocol.USER)
      })
    }
  }

}

setup2 = { c ->
  c.add 'ranging', new Ranging()
  c.add 'agent2', new NodeAgent()
}

setup3 = { c ->
  c.add 'ranging', new Ranging()
  c.add 'agent3', new AnchorAgent()
}

simulate {
  node 'B', address: 101, location: [ 0.km, 0.km, -15.m], web:8081,api: 1101, shell: true, stack: setup2
  node '1', address: 102, location: [ 0.km, 1.km, -15.m], web:8082,api: 1102, shell: 5101, stack: setup3
  node '2', address: 103, location: [-900.m, 0.km, -15.m], web:8083,api: 1103, shell: 5102, stack: setup3
  node '3', address: 104, location: [ 600.m, 0.km, -15.m], web:8084,api: 1104, shell: 5103, stack: setup3
}

以下是示例运行的日志:

1613226179777|INFO|NodeAgent/B@83:call|Starting anchor discovery...
1613226180943|INFO|AnchorAgent/3@112:doInvoke|Discovery request from 101, will respond after 6704 ms
1613226181134|INFO|AnchorAgent/2@103:doInvoke|Discovery request from 101, will respond after 7628 ms
1613226181193|INFO|AnchorAgent/1@94:doInvoke|Discovery request from 101, will respond after 3747 ms
1613226184945|INFO|AnchorAgent/1@94:call|Responding...
1613226186356|INFO|NodeAgent/B@83:doInvoke|Discovered node 102
1613226187654|INFO|AnchorAgent/3@112:call|Responding...
1613226188764|INFO|AnchorAgent/2@103:call|Responding...
1613226188805|INFO|NodeAgent/B@83:doInvoke|Discovered node 104
1613226190731|INFO|NodeAgent/B@83:doInvoke|Discovered node 103
1613226194960|INFO|NodeAgent/B@83:doInvoke|Discovered 3 anchor(s), getting locations...
1613226194963|INFO|NodeAgent/B@83:doInvoke|Asking node 102 for its location...
1613226199126|INFO|NodeAgent/B@83:doInvoke|Got location of anchor 102: [0.0, 1000.0, -15.0]
1613226199965|INFO|NodeAgent/B@83:doInvoke|Asking node 104 for its location...
1613226203782|INFO|NodeAgent/B@83:doInvoke|Got location of anchor 104: [600.0, 0.0, -15.0]
1613226204969|INFO|NodeAgent/B@83:doInvoke|Asking node 103 for its location...
1613226209069|INFO|NodeAgent/B@83:doInvoke|Got location of anchor 103: [-900.0, 0.0, -15.0]

表明它有效!

与随机访问场景一样,仍然有可能发生冲突,但初始发现周期(当前为 15 秒)越长,冲突的可能性就会越小。如果收到 aBadFrameNtf或 a CollisionNtf,您可以通过添加重试来进一步使系统更加健壮,这表明某个节点尝试通信但失败了。

于 2021-02-13T14:35:22.797 回答