functionroutestclns2

While simulating a routing protocol for Wireless Sensor Network in NS2, accessing the nodes from inside the a function gives error "No such variable"


I am trying to write a code for 60 nodes and 1 mobile sink among which 18 nodes act as high-tier nodes or Backbone nodes. The mobile sink updates the location periodically to only the Backbone nodes and other nodes can query the sink location at the time of need.

#node creation
#Node 1 to 18 are backbone nodes
#nodes 19 to 59 are normal sensor nodes
#node 60 is the mobile sink
    set node_(0) [$ns node]
    set node_(1) [$ns node]
    .
    .
    .
#node no 60 is the mobile sink..
    set node_(60) [$ns node]

    
    #node X Y coordinate initialized
    $node_(0) set X_ 2
    $node_(0) set Y_ 3
    $node_(1) set X_ 517
    $node_(1) set Y_ 299
    .
    .
    $node_(63) set  X_ 306
    $node_(63) set  Y_ 178
    
    proc distBN {n1 n2 nid1 nid2} {
        set x1 [expr int([$n1 set X_])]
        set y1 [expr int([$n1 set Y_])]
        set x2 [expr int([$n2 set X_])]
        set y2 [expr int([$n2 set Y_])]
        set d [expr int(sqrt(pow(($x2-$x1),2)+pow(($y2-$y1),2)))]
        #checking that it is in the transmission range i.e 100m
        if {$d<100} {
            if {$nid2!=$nid1} {
                return $d;
            }            
        }
    }
    
    
    #This function starts the transmission of Mobile Sink location every 5 seconds 
    proc locTrans {} {
        global ns
        set dist_min 101
        set dist 101
        set sink_loc 60
        puts "[$ns now] : Finding the nearest backbone node to sink node $sink_loc..."
        for {set j 0} {$j < 19} {incr j} {
            set dist [expr "distBN $node_($sink_loc) $node_($j) $sink_loc $j"]; ## <<< THIS LINE
            puts "Distance between sink and node $j is $dist...\n"
            if{$dist_min > $dist} {
                set dist_min $dist 
            }
            puts "Running loop for $j time...\n"
        }
        puts "The smallest distance is $dist_min between node_(60) and node_($j)\n"
        puts "[$ns now] : transmitting sink location to nearest backbone node...\n"
        $ns at [expr [$ns now] + 3.0] "locTrans"  
    }

The procedure locTrans() calls another function distBN() to calculate the distance between the nodes passed in arguments. But running the code gives the following error:

> ns: locTrans: can't read "node_(60)": no such variable
    while executing
"expr "distBN $node_($sink_loc) $node_($j) $sink_loc $j""
    (procedure "locTrans" line 9)
    invoked from within
"locTrans"

Error screenshot


Solution

  • The problem is that the global node_ array isn't in scope inside the procedure (because Tcl only makes non-local variables available if you explicitly ask for them). Luckily the fix is easy: update the global ns command a few lines above to:

    global ns node_
    

    Also be aware that you have a couple of bugs in your code: you don't handle the case where you measure the distance from a node to itself correctly (right now, you're effectively returning the empty string; I bet you don't want that!) and you have written the call to distBN wrong and should do:

    set dist [distBN $node_($sink_loc) $node_($j) $sink_loc $j]
    

    What you wrote was... not going to work.