Pages

Thursday 10 April 2014

Practice - Chatting with XBee

Description

In this lab we have experimented with the XBee devices and how they can complement with Arduino. Firstly, we set a chat between two computers using the XBee's without Arduino; secondly, as an extra activity, we decided to establish a chat such as the messages sent from one computer through an XBee, were received by a second XBee connected to the Arduino. Moreover, these messages were shown through a LCD screen.

We used the following components:
  • 2 Digi XBee.
  • 2 Xbee Explorer.
  • 2 Type-A USB to mini-USB cables.
  • 2 Computers.
  • 1 Arduino Uno.
  • 1 (or 2) Breadboard.
  • 1 Display.
  • Several wires to interconnect the breadboard and Arduino.
The needed sofware to complete the task is the following:

Part 1: Simple Chat

The first step consists in achieving communication between two machines connected to the following set:


Figure 1: Xbee Module

We used the software XCTU to configure the devices and to set the PAN ID. We can also implement some stuff like changing device’s name, applying security, changing transmission power, etc.

After connecting the XBee modules to the computer, we must set a coordinator and a router as follows:

Figure 2: Coordinator setting

After setting one of the XBee module as a coordinator, we should see this on the XCTU screen:

Figure 3: Coordinator setting

We do the same for setting the other XBee module as router:

Figure 4: Router setting

We check that the change has been done successfully:

Figure 5: Router checking

Once the configuration has been done and the PAN ID is the same for both devices, we can run the “discover nodes in the same network” functionality:

Figure 6: Device discovered

The last step for chatting is switching to the consoles working mode and opening the serial connection with the radio module. The figure below shows a conversation maintained between two ZigBee modules connected to different computers.

Figure 7: Chatting
For more specific details, see the YouTube video attached at the end of the post.

Part 2: Chat display

In this second part we are going to show how we can display the information transmitted between two XBee in a screen connected to Arduino. To do that, we need to understand how the XBee Explorer works:

Figure 8: XBee Explorer
The previous figure shows the pins we must connect to the Arduino in order to be able to display the information sent by the other XBee module. We note that the input voltage must be 3.3V instead of 5V to avoid potential problems (however, we can use the 5V pin placed at the upper-right side). The XBee Explorer is not only important to connect the XBee to the computer, but also to put it in the breadboard so as connections can be set (later we will show the figure).

The connection between the XBee modules must be implemented as shown on part 1. In this case, however, we have set that one of the XBee's acts as a coordinator and the other one as an end-device (it could be used as a router too).

One of the main aspects we have to take into account when establishing the connection is that if we send broadcast messages, these messages will probably arrived much more delayed than in the case were we have specified the addresses. Moreover, it is very useful to observe that until RSSI leds in each XBee Explorer are not high, messages will not be sent (so be patient).

Once connectivity between the two XBee modules has been established, we can implement the part where we display the information in a screen. The image below also shows the connections done for our purpose and we can observe that we have the same type of pins as for ZigBee Explorer: Voltage input (5V), Ground, TX and RX.

Circuit schema

The image below shows the circuit. We must say that is not exactly the schema we followed because there are some pieces that are not included in the software (Fritzing): XBee Explorer (which is not the same as the one put in the image) and an I2C module we used for the LCD screen (see figure 15). At the link [5] you will find information on how to use I2C module.
Figure 9: Physical Schema

Circuit photographs

Figure 10: General image of the circuit

Figure 11: General image of the circuit

Figure 12: Zoom in the Arduino board

Figure 13: Zoom in the XBee (receiver) module part

Figure 14: Zoom in the LCD screen part

Figure 15: The I2C module

Video


Code

Now we can see two versions that correspond to the second part explained before. In both cases some characters written from the XBee connected from a computer are received in another XBee and shown through the display. However, there are some differences that are explained in the header comments of the code.

You can download the code from the code section.

Version 1

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
/**
 * Chatting with Xbee - Version 1
 * In this version an Xbee connected to XCTU software sends a
 * message finished by an INTRO (like in a real chat). Because
 * of display length restrictions, just those characters that
 * fit in the screen are displayed.
 */

#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
#include <Wire.h>  

// Set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
// Set the LCD I2C address
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); SoftwareSerial xbee(0, 1); // Pin: RX, TX /** * Constants */ // Number of flashes before starting to show the characters
// received
const int N_FLASHES = 3;

// Number of rows in the display
const int N_ROWS = 2;

// Number of characters in each row
const int MAX_CHARS_PER_ROW = 16;

/**
 * Global variables
 */
// String that will be formed from the chars sent by the other xbee
String input = "";

void setup() 
{
  // Initialize the lcd for 16 chars 2 lines, turn on backlight
  lcd.begin(MAX_CHARS_PER_ROW, N_ROWS);

  // Quick 3 flashes of backlight 
  for (int i = 0; i < N_FLASHES; ++i)
  {
    lcd.backlight();
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
  lcd.backlight(); // finish with backlight on  

  // set the data rate for the SoftwareSerial port
  xbee.begin(9600);
}

void loop()
{
  // If the xbee is receiving something...
  if (xbee.available())
  { 
    // Read the character received from the other xbee
    char c = xbee.read();
    
    // If INTRO key is pressed, print the string in the display
    //  Otherwise, keep reading it
    if (c == 13 || c == 10)
    {
      printStringInLCD();
      input = "";
    }
    else
    {
      input += c;
    }
  }
}

// Updates the LCD parameters (row, position in row) depending on
//  the current position
void printStringInLCD()
{
  // Size restriction of the display
  int length = min(input.length(), MAX_CHARS_PER_ROW * N_ROWS);
  
  int row = 0;
  int pos = 0;
  
  // Important to clear the display before writting new text
  lcd.clear();
  
  // Print char by char in order to take advantage from all 
  // the display. The string can also be divided in two parts
  // and print them separately
  for (int i = 0; i < length; ++i)
  {
    pos = i % MAX_CHARS_PER_ROW;
    
    if (i == MAX_CHARS_PER_ROW)
    {
      ++row; 
    }
    
    lcd.setCursor(pos, row);
    lcd.print(input.charAt(i));   
  }
}

Version 2

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
/**
 * Chatting with Xbee - Version 2
 * In this version an Xbee connected to XCTU software sends an 
 * infinite message to the Xbee connected to the Arduino.
 * The message is displayed character by character while the 
 * message is written in XCTU. If the message is filled with 
 * characters, then the screen is cleared.
 */

#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
#include <Wire.h>  

// Set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
// Set the LCD I2C address
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
SoftwareSerial xbee(0, 1); // Pin: RX, TX

/**
 * Constants
 */
// Number of flashes before starting to show the characters 
// received
const int N_FLASHES = 3;

// Number of rows in the display
const int N_ROWS = 2;

// Number of characters in each row
const int MAX_CHARS_PER_ROW = 16;

/**
 * Global variables
 */
int currentRow = 0;
int nextRow = 0;
int currentPos = 0;
int nextPos = 0;

void setup() 
{
  // Initialize the lcd for 16 chars 2 lines, turn on backlight
  lcd.begin(MAX_CHARS_PER_ROW, N_ROWS);

  // Quick 3 flashes of backlight 
  for (int i = 0; i < N_FLASHES; ++i)
  {
    lcd.backlight();
    delay(250);
    lcd.noBacklight();
    delay(250);
  }
  lcd.backlight(); // finish with backlight on  

  // set the data rate for the SoftwareSerial port
  xbee.begin(9600);
}

void loop()
{
  // If the xbee is receiving something...
  if (xbee.available())
  {
    updateLCDParams();
 
    // Set the cursor position in the display   
    lcd.setCursor(currentPos, currentRow);
    
    // Read the character received from the other xbee
    char c = xbee.read();
    
    // If INTRO key is pressed...
    if (c == 13 || c == 10)
    {
      nextRow = (currentRow+1) % N_ROWS;
      nextPos = 0;
    }
    else
    {
      // Print char throught the display
      lcd.print(c);
 
      // If we reach the end of the current row...
      if (currentPos == MAX_CHARS_PER_ROW-1)
      {
        nextRow = (currentRow+1) % N_ROWS;
        nextPos = 0;
      }
      else
      {
        nextRow = currentRow;
        nextPos = (currentPos+1) % MAX_CHARS_PER_ROW; 
      }
    }
  }
}

// Updates the LCD parameters (row, position in row) depending on
//  the current position
void updateLCDParams()
{
  currentRow = nextRow;
  currentPos = nextPos;
  
  if (currentRow == 0 && currentPos == 0)
  {
    lcd.clear();
  }
}

References

No comments:

Post a Comment