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

Thursday 3 April 2014

Practice - Blinking LED

Description

In this practice we had to deal with LEDs (Light Emitting Diode) in order to perform a useful system; concretely, a program was developed to turn on and turn off the LEDs after a certain amount of time (moreover, we could do the same using switches/buttons). This task formed the minimum requirements to start experimenting with more complex ideas.

One of the main issues we found consisted in deciding how to put the button in the breadboard to turn on and turn off the LEDs. As you will see later in this entry, we have seen that when the button is switched on, the terminals on the same side become connected; otherwise, they are not connected. This fact can be observed on the following image, where terminals A and C are directly connected (as B and D). When the button is switched on, the current flows through all the nodes.


Image 1: Button functionality [1]

The additional work we did consisted in creating a traffic light using three different LED: red, yellow and green. We thought it was a good way to show how LEDs blink and moreover it has an important application in everyday life, specially for those zones where people's concurrency is low.

This traffic light remains always in red until someone pushes a button. Then some actions are done in order to indicate that it is going to change its state (to green) soon. After that, the green light is on for a while and the same actions than before (later specified clearly) are done to indicate that it is going to change to red again. To summarize, it is not an automatic traffic light: in order to pass through the street, we have to ask for permission first.

It works as follows:
  1. The traffic lights remain in red if the button is not pushed.
  2. When the button is pushed:
    1. Keep the red light on for 2 more seconds (for security reasons before crossing the street).
    2. Turn on/off alternatively the red and the yellow lights to indicate that the colour is going to change soon. This process is repeated five times and each light remains 200 ms on and 200 ms off for each iteration.
    3. Turn off the red and the yellow lights; turn on the green light for 3 seconds.
    4. Turn on/off alternatively the green and the yellow lights to indicate that the colour is going to change soon. This process in the same way as in step 2.
    5. Turn off the green and the yellow lights; turn on the red light indefinitely (return to the first step).

Circuit schema

Image 2: Traffic lights circuit schema

Circuit photograph

Image 3: Traffic lights photograph

Video

 

Code


 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
/**
 * Traffic lights
 * Represents the traffic lights system we find in cities.
 * It is a variation in which the permission for a green 
 * light is asked through a button. 
 */

// Button and traffic lights ports
const int BUTTON = 2;
const int ledR = 13;
const int ledY = 12;
const int ledG = 8;

// Time waited before starting to change from red to turn 
// on alternatively red and yellow
const int waitForPass = 5000;

// Time we keep the green light on
const int timeGreen = 10000;

// Time we keep a light on when alternates with another one
const int alternTurnTime = 200;

// Number of times that two lights are alternatively turned on/off
const int Nblinks = 14;

// Indicates whether the button is pushed (1) or not (0)
int val = 0;


// the setup routine runs once when you press reset:
void setup()
{                
  // initialize the digital pin as an output.
  pinMode(ledR, OUTPUT);
  pinMode(ledY, OUTPUT);
  pinMode(ledG, OUTPUT);
  pinMode(BUTTON, INPUT);
  Serial.begin(9600);  
}


// the loop routine runs over and over again forever:
void loop()
{
  // Read the value of the button (to see if it is pushed or not)
  val = digitalRead(BUTTON);
  delay(10);
  
  // Print the value for debugging reasons
  Serial.println(val);
  
  // Turn the red light on
  digitalWrite(ledR, HIGH);
  
  // If the red button is pushed, make the transition to green.
  //  Then return to red again.
  if (val == HIGH)
  {
    // Keep the red light on for 'waitForPass' time
    //  Then turn this light off
    delay(waitForPass);
    digitalWrite(ledR, LOW);
    
    // Turn on alternatively both yellow and red lights
    turnLightsAlternatively(ledY, ledR);
    
    // Turn on the green light for a specified amount of time
    digitalWrite(ledG, HIGH);
    delay(timeGreen);
    digitalWrite(ledG, LOW);
    
    // Turn on alternatively both yellow and green lights
    //  When finished, note that red light will be turned on
    //  automatically when loop function restarts.
    turnLightsAlternatively(ledY, ledG);
  }
}


// Function to turn two lights alternatively
void turnLightsAlternatively(const int light1, const int light2)
{
  for (int i = 0; i < Nblinks; ++i)
  {
    digitalWrite(light1, HIGH);
    delay(alternTurnTime);
    digitalWrite(light1, LOW);
    
    digitalWrite(light2, HIGH);
    delay(alternTurnTime);
    digitalWrite(light2, LOW);
  }
}

Download the code here.

References

[1] Picture of the functionality of the button, retrieved on March, 3th from:
http://www.varesano.net/blog/fabio