Saturday, March 5, 2016

Static Wireless Sensor Network with Arduino NRF24l01

Hi,
   Right from my childhood I wanted to control appliances and had an eye for Automation
may be I'm just too lazy , two years back I wrote the software for this !

Video of my WSN NRF24L01+Arduino
code is somewhat like this .

NRF24L01 packet

class packet {
  public :
    unsigned char  frame_type; // data or synchronization 
    unsigned short int to_add; // packet destination address
    unsigned short int from_add; // packet origin address 
    unsigned short int h_from_add; // packet immediate hopped address
    unsigned short int frame;          // packet send on frame 
    unsigned long data1;                 // data holder
};


Arduino setup function , here were are setting up nrf24l01/serial/ZCD .

void setup()
{
  if ( cid == 0 ) {
    pinMode(2, OUTPUT);
  } else {
    pinMode(2,INPUT);
  }
  
  pinMode(DETECT, INPUT);     //zero cross detect
  digitalWrite(DETECT, HIGH); //enable pull-up resistor
  pinMode(GATE, OUTPUT);      //triac gate control

  Serial.begin(57600);

  while (!Serial) ;
  Serial.println("start ");

  if (!nrf24.init())
    Serial.println("NRF24 init failed");
    
  if (!nrf24.setChannel(B_Freq))
    Serial.println("setChannel failed");

   mask1 = mask | cid;
   if (!nrf24.setThisAddress((uint8_t*)(&mask1), 5))
     Serial.println("setThisAddress failed");

  if (!nrf24.setPayloadSize(len))
    Serial.println("setPayloadSize failed");

  if (!nrf24.setRF(NRF24::NRF24DataRate2Mbps, NRF24::NRF24TransmitPower0dBm))
    Serial.println("setRF failed");    

    ping_s = 0;
    cnt =0;
    frame = 150;
    route_packet = 0;
    route_pac_delay = 0;
    num_retries = 0 ;
    b_cnt = 0;
    data.h_from_add = cid ;

    data.frame_type = 0;
    noInterrupts();           // disable all interrupts
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;

    OCR1A = 30000;            // compare match register 16MHz/256/2Hz
    TCCR1B |= (1 << WGM12);   // CTC mode
    TCCR1B |= (1 << CS11);    // 256 prescaler 
    TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
    interrupts();             // enable all interrupts 
    
    if ( cid == 0 )  {
          is_sync = 1;
    } else {
          is_sync = 0;
    }
    randomSeed(cid*10);
    b_cnt = random(200,500);
    
    ping_timeout=random(200,500);
    ping_retries=0;
    
    Serial.print("Curr ID ");
    Serial.println(data.h_from_add,DEC);
    attachInterrupt(1,zeroCrossingInterrupt, CHANGE );
}


Below Function will send data to next hop address based on routing table .

bool route_data () {
    routed = 0 ;
    for ( cnt = 0 ; cnt <= luk_len ; cnt ++ ) {
if ( (data.to_add >= luk_tab[cnt][0] && data.to_add <= luk_tab[cnt][1] ) ) {
                      routed = 1;
if ( cnt == luk_len ) {
send_to(up_link);
} else {
       send_to(luk_tab[cnt][0]);
}
                        break ;
if ( routed == 1 ) {
break ;
}
      }
   }
      
   if ( routed == 0 || routed != 1 ) {
// NOT ABLE TO SEND THE data .
   }
   return (routed==1) ;
}

Actual function which will send data via NRF24L01 , it will also select frequency based on to_address and frame number .

bool send_to (unsigned short int to_addr ) {
        if ( b_flag == 0 ) {
        f  = to_addr * 11117 + ( frame *31 ) ;
         f = (f/13) % 11 ;
                f = (f * 10) +1 ;
        } else {
                f = B_Freq;
        }
                
        if (!nrf24.setChannel(f))
          Serial.println("setChannel failed");
        
mask1 = mask | to_addr ;

  if (!nrf24.setTransmitAddress((uint8_t*)(&mask1), 5)) {
  Serial.println("setTransmitAddress failed");
routed = 2; 
}

        delayMicroseconds(700);
       
        if ( b_flag == 1 ) {
          data.frame = frame;
          rtt = TCNT1;
          data.data1 = rtt + 1700 ;
          data.frame_type = 3;
        }
        data.h_from_add = cid;       
        if ( debug == 1 && data.frame_type == 2) {
          Serial.print(to_addr,DEC);
          Serial.print(" to add ,S'dg ");
          Serial.print(data.data1,DEC);
          Serial.print(" frame is ");
          Serial.println(frame,DEC);
        }
        if (!nrf24.send((uint8_t*)&data, sizeof(data),b_flag)) {
            Serial.println("E4"); 
   routed = 3;
}
        
        if (!nrf24.waitPacketSent()) {
          Serial.print("Sndg Fail ");
 routed = 4;
        }
        return ( routed == 1 || b_flag ) ;
}

Receiver function , configures NRF24L01 in RX mode and selects frequency based on same formula used in TX mode .

bool listen_rx() {
  f  = cid * 11117 + ( frame *31 );
  f = (f/13) % 11 ;
  f = (f * 10) +1 ;

  nrf24.powerUpRx();
  if (!nrf24.setChannel(f))
     Serial.println("setChannel failed");
   if (nrf24.waitAvailableTimeout(5)) {
          if (!nrf24.recv((uint8_t*)&data_junk, &len)) {
            Serial.println("read failed");
   return 0;
 }

       if ( debug == 1 && data_junk.frame_type==2) {
          if ( serial_read == 'A' ) {
             trigger_delay = data_junk.data1 -65 ;
             Serial.print("setting val ");
             Serial.println(trigger_delay , DEC );        
          }
          Serial.print(data_junk.h_from_add,DEC);
          Serial.print(" rx from add ,S'dg ");
          serial_read = data_junk.data1;
          Serial.print(serial_read,DEC);
          Serial.print(" frame is ");
          Serial.println(frame,DEC);
          
        }
        
        if ( data_junk.frame_type == 2 && data_junk.to_add != cid) {
            data_in=data_junk;
            route_packet =1;
            route_pac_delay = random(2,8);
            num_retries = 0 ; 
        }
   }

  return 1;
}

Function used for synchronizing two nodes , received beacon packet will have counter value which is used to load into TCNT1 of received node .

void sync_me (bool ip) {
 
        nrf24.powerUpRx();
        if (!nrf24.setChannel(B_Freq))
  Serial.println("setChannel failed");
          
        mask1 = mask | up_link ;
        
        if (!nrf24.setTransmitAddress((uint8_t*)(&mask1), 5))
    Serial.println("setTransmitAddress failed");
         if ( ip == 1)  {
         }

         if ( ip == 1 ) {
             TCCR1B &= ~(1 << CS11);    // stop counter
    nrf24.waitAvailable() ;
             TCCR1B |= (1 << CS11);    // start counter
         } 

if (!nrf24.recv((uint8_t*)&data, &len))
 Serial.println("read failed");
        
TCNT1 = data.data1 - 500;
frame = data.frame;
mask1 = mask | data.h_from_add ;
is_sync =1; 

        nrf24.setTransmitAddress((uint8_t*)"NULL1", 5);
  
}

Function used to send beacon packet for slave nodes 

void send_beacon () {
 // Serial.print("Send beac ");
 //  Serial.println(frame,DEC);

   b_flag = 1;
   send_to(cid);
   b_flag = 0;
   b_cnt = random(300,600);

}

Function calling route_data() and from there send_to() .

void send_packet () {
  //Serial.println("send pack");
  data=data_in;
  data.frame_type =2;
  if ( ! route_data() ) {
num_retries++;
if ( num_retries > 10 ) {
                         Serial.println("Droping pack");
route_packet =0 ;
num_retries = 0 ;
}
} else {
route_packet = 0;
num_retries = 0 ;
}
route_pac_delay = random(5,15);
data.frame_type = 0;
}

MISC functions used for book keeping

bool process_state () {
  while ( ping_s == 0 ) {delayMicroseconds(1);}
  ping_s = 0 ;
  frame= frame+1 ;
  if ( frame > 150 ) {frame = 0;}
}

bool post_processing () {
// nrf24.powerDown();
if ( route_pac_delay > 0 ) {
  route_pac_delay--;
}
 b_cnt ++ ;
 ping_timeout++ ;
}

Functional loop used to send/receive/synchronize nodes .

void loop() {
 loop_var = 10;
 

 process_state();
 
 if ( cid == 0 ) {
   digitalWrite(2,HIGH); 
   digitalWrite(2,LOW); 
 }
 
     
 if ( is_sync == 0 ) {
    loop_var = 3;
   sync_me(1);
   Serial.println("sync'd");
 } else if ((cid+2) == frame  ) {
    loop_var = 4;
    send_beacon();
 }  else if ( (up_link+2)==frame ) {
    loop_var = 5;
       sync_me(0);
 } else if (route_packet == 1 && route_pac_delay == 0) {
    loop_var = 6;
      send_packet();
 } else if (route_packet == 0 && Serial.available()) {
      loop_var = 7;
     Serial.println(max_tcnt,DEC);
      data_in.data1 = Serial.read(); ;
      data_in.to_add = ping_node ;
      data_in.from_add = cid ;
      route_packet =1;
      num_retries = 0 ;
 } else {
    loop_var = 8;
    listen_rx();
 }

 nrf24.setTransmitAddress((uint8_t*)"NULL1", 5);

 post_processing();

 if ( ping_s == 1  ) {
   Serial.print("Error ");
   Serial.println(loop_var,DEC);
 //  delay(100000);
 }
}


I'll update more information and few pictures explaining how routing between nodes work .

1 comment:

  1. 2019 ford edge titanium for sale
    2019 titanium chain ford titanium gold edge titanium. Find high quality antique used titanium alloy furniture, antique accessories, vintage vintage watches, titanium app and more titanium jewelry at affordable prices.

    ReplyDelete