Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. Show all posts

Saturday, February 1, 2020

Blynk, ESP8266, XBEE


Blynk, ESP8266, XBEE

AIM

The aim of this experiment is to connect a smartphone app to an Arduino, through the internet. The phone could be anywhere in the world, connected to the internet. One Arduino device will be connected to a domestic Wifi (let’s call it “Home Controller”). This Home Controller will communicate to another Arduino device (let’s call it “Remote Controller”) through Xbee radio transmitters (up to about 3km distance). The final aim is to enable two-way communication between the Remote Controller and the smartphone app. The Smartphone app will be created with the Blynk software.
Example: a farm has a Wifi network in the farmhouse. 3km from the house there is a water cistern and a pump. From the smartphone, we want to see the level of the water in the cistern and start/stop the pump. We also want a feedback to see if the pump is actually running. With this system it’s easy to add more devices (pumps, motors, actuators, and sensors of any kind).


WHAT WE NEED

Obviously we need two arduino boards, breadboards, jumper wires, potentiometers, LED, power supplies. The usual stuff.

ESP8266

The ESP8266 is a low-cost Wi-Fi microchip with full TCP/IP stack and microcontroller capability produced by Shanghai-based Chinese manufacturer, Espressif Systems, compatible with IEEE 802.11 b/g/n Wi-Fi. Basically, it's a modem, but it can be programmed as a controller or server.
The ESP8266 can be programmed with AT commands through a serial interface. It cost about $3.

5V to 3.3V logic converter

The Arduino uses a 5V logic. The ESP8266 uses a 3.3V logic. A logic converter is necessary between them.

3.3V power supply

The arduino 3.3V pin doesn't supply enough power to the ESP8266. It needs a separate power supply. I'm using an adjustable step-down power supply module with LM2596 voltage regulator.

XBEE x2

To extend the range of the microcontrollers, I’m going to use Xbee transmitters. They send digital data using radio frequencies. To connect the Arduino to the XBee module you need an Arduino Wireless Shield. To connect the XBee module to the PC for modifying the settings you need a XBee Explorer board. They can be configured to create very complex mesh networks, but I don't need it now.
The XBee module I've chosen are: XBee PRO series 2. They use 50 mW power at 2.4 GHz frequency (legal in Australia). The range of this model is about 3 km outdoor.

WIRELESS SHIELD x2

To connect the XBEE to the Arduino board, you need a module called "wireless shield".

LCD Displays

I'm using one LCD display attached to each Arduino controller, just to see if they are working correctly and they are sending/receiving the right data. When the devices are working, the LCD displays could be removed. They are the usual 16x2 but one of them has a I2C interface, just so I learn how to use it.

BLYNK

Blynk is a crowdfunded smartphone app editor which can be used not only to create your apps, but also to write the code for the Arduino, in order to communicate with your apps. It’s compatible with many other controllers as well. For small projects like this one, it’s free. Find out more at www.blynk.cc.



LET’S DO IT

SETUP THE XBEEs

Each module has to be configured using the Explorer board and X-CTU, a free software distributed by Digi International. To communicate, the two modules have to use the same ID (the name of the network), and same baud speed; one have to be a coordinator and the other can be router, end device or both. In this case I set one as coordinator and the other one as a router.


ROUTER
COORDINATOR
SH
13A200
SH
13A200
SL
40AD4579
SL
40A8E58A
16bit
B7C
16bit
0
DH
13A200
DH
0
DL
40A8E58A
DL
FFFE

The router DL and coordinator SL are the same.The router DH and coordinator SH are the same.

Once they are installed on the wireless shield of the Arduino, they use the serial port. The USB connection of the PC uses the same port, so there's a switch on the shield: you must select “USB” when using serial to upload a sketch to the Arduino, and “MICRO” when using the XBee to send data.

WIRING

REMOTE CONTROLLER

The potentiometer simulates a water level sensor. The led simulates a pump. A pin reads the status of the led to send a feedback to the app (to show that the pump is actually running).


HOME CONTROLLER

This LCD display uses the SDA/SCL pins. ESP8266 uses Serial1 (TX1,RX1). In the logic shifter, the 3.3V reference ("LV" pin) is attached to the 3.3V of the Arduino, not to the 3.3V power supply. If you attach it to the power supply it will give you intermittent faults.


TEST THE ESP8266

Because the pins of the ESP8266 don't fit in a breadboard, I had to build a connector.
The following steps are just to check if the ESP is working.
To setup amd test an ESP8266 through the Arduino, you have to upload and empty sketch from the Arduino IDE. Connect TX1 Arduino pin to ESP TX pin and RX1 Arduino pin to ESP RX pin. Connect GPIO-0 to GND (just for setup).
Open the serial monitor in the Arduino IDE. Select baud rate 115200 and "Both NL & CR". Now you can send AT commands to the ESP.
When the ESP is powered up, the blue led blinks quickly 3 times then stays off, the red led stays on. If not, you have a connector problem. Check your wiring.

Through the serial monitor, send "AT". You should receive "OK".
Send "AT+CWLAP", it will list the available AP (access point, or wifi).
Send "AT+CWJAP="ssid","pswd"" with your wifi name and password, it will connect to your wifi. "AT+CWQAP" will disconnect from wifi.

The default baud rate is 115200. Leave it as it is.
When you finished, remove the GPIO-0 pin from ground, and connect TX to RX1 and RX to TX1 (as in the wiring diagram).

BLYNK

I’m using the Blynk app to create a smartphone app. It’s an easy graphical editor and it doesn’t require any coding. You can download the Blynk app from Google Playstore. Create an account and design your app.
You will receive an authorization code by email.
Download the Blynk library from here. Unzip it and copy to the Arduino library folder.
Copy the Blynk example code for the Arduino from herePaste it in the Arduino IDE, change authorization token, SSID and password of your Wifi.
You need more than one serial: one is for the USB communication to your PC, one is for the ESP8266. Some boards have multiple serial pins (hardware serial), others have only one, so you have to enable software serial and assign 2 pins to it. I’m using a Mega with multiple hardware serial so I deleted the software serial part of the code.
Upload it to your board. When you open the serial monitor, the Blynk code will start connecting to the Wifi and it will give you confirmation through serial monitor.




ARDUINO CODING

REMOTE CONTROLLER

This is easy: 2 inputs (value of the potentiometer and the status of the led), 1 output (start/stop the pump). Everytime a 1 is received through serial, the pump is toggled (on/off). A string is created with the values and sent to serial. The values are also displayed on the LCD. A delay is needed to avoid buffer overflow in the receiver.


#include <LiquidCrystal.h>
LiquidCrystal lcd(26, 27, 28, 29, 30, 31);
boolean pump = false;

void setup(){

pinMode(8, OUTPUT);
pinMode(7, INPUT);
Serial.begin(9600);
lcd.begin(16,2);
}

void loop() {

  if(Serial.available() > 0) {
  int bla = Serial.parseInt();
    if (bla==1) pump = !pump; 
    }
  digitalWrite(8,pump);
  float sensor = analogRead(0);
  int value = sensor / 1024 * 100;
  
  String dataStringWater = "";
    dataStringWater += "Water:";
    dataStringWater += " ";
    dataStringWater += value;
    dataStringWater += " ";
    dataStringWater += "%";
  String dataStringPump = "";
    dataStringPump += "Pump:";
    dataStringPump += " ";
    dataStringPump += (digitalRead(7));
  Serial.print (value);
  Serial.print ("/");
  Serial.println (digitalRead(7));
  
  lcd.clear();
  lcd.print(dataStringWater);
  lcd.setCursor(0,1);
  lcd.print(dataStringPump);

  delay(1000);
}


After you upload the code, remember to switch the wireless shield to "micro".

HOME CONTROLLER

This one is a bit harder. It will receive 2 values over serial (water level, pump status). The function Serial.parseInt() is used to get those values out of the serial string.
The Blynk program will start running when a serial monitor is open. If you want it to run by itself you have to delete the line "#define BLYNK_PRINT Serial".
Because I'm using a I2C LCD, I need to include the libraries Wire.h and LiquidCrystal_I2C.h. Also you have to find out the address of that I2C device. To do that upload and run this code. Now you can enter the address value.
I have multiple hardware serial so I deleted the software serial bit.
I had few problems in reading the values from the serial string until I added:
 "while(Serial.available())  Serial.read();
  delay(500);"
That cleans the buffer and avoid messy readings.
The BLYNK_WRITE() function has to stay out of the void loop().

//#define BLYNK_PRINT Serial

#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x3F, 16, 2);

char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
char ssid[] = "xxxxxxxxxxxxxxxxxx";
char pass[] = "xxxxxxxxxxxxxxxxx";

// Hardware Serial on Mega, Leonardo, Micro...
#define EspSerial Serial1

// or Software Serial on Uno, Nano...
//#include <SoftwareSerial.h>
//SoftwareSerial EspSerial(2, 3); // RX, TX

#define ESP8266_BAUD 115200

ESP8266 wifi(&EspSerial);

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  EspSerial.begin(ESP8266_BAUD);
  delay(10);
  Blynk.begin(auth, wifi, ssid, pass);
}

void loop() {

  int value = Serial.parseInt();
  int pump = Serial.parseInt();
  while(Serial.available())
  Serial.read();
  delay(500);
  
  String dataStringWater = "";
    dataStringWater += "Water:";
    dataStringWater += " ";
    dataStringWater += value;
    dataStringWater += " ";
    dataStringWater += "%";
  String dataStringPump = "";
    dataStringPump += "Pump:";
    dataStringPump += " ";
    dataStringPump += pump;

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(dataStringWater);
  lcd.setCursor(0,1);
  lcd.print(dataStringPump);
  
  Blynk.run();
  Blynk.virtualWrite( V1, value);
  Blynk.virtualWrite( V2, pump);
}

BLYNK_WRITE(V5) {
// Assigning incoming value from pin V5 to a variable
 int pinValue = param.asInt(); 
 Serial.println(pinValue);
}

After you upload the code, remember to switch the wireless shield to "micro".


CONCLUSIONS

The project was successful, but it took longer than expected. I encountered several issues described below:

Issues

The 3.3V output of the Arduino doesn’t deliver enough power to the ESP8266. The Arduino provides up to 40mA, The ESP needs 250mA. I had to buy a separate power supply with voltage regulator. But when the 3.3V LV pin on the logic shifter was supplied from the 3.3V power supply, I had intermittent faults of connectivity. I solved it by connecting the 3.3V LV pin of the logic shifter to the 3.3V pin of the Arduino, and only connect the 3.3V power supply to the power pins of the ESP8266. Remember: if the ESP8266 blue led doesn't blink 3 times at startup, there's something wrong, probably in the wiring.
The Serial.parseInt() function was reading the wrong values sometimes. I fixed it by adding while(Serial.available()) Serial.read(); and delay(500); to clean the buffer.


Learning contents

During the development of the project and the research stage I learned about:
·         Frequency allocation and power limits (EIRP) in Australian Standards
·         Domestic router setup for static IP addresses
·         Wi-Fi modules and controllers (ESP8266)
·         Interface between different logics (5V, 3.3V, USB to serial), logic shifter and converter
·         Create a 2 way comms network with Xbee (2.4GHz)
·         Use multiple serial ports and set up virtual ports in the Arduino controller
·         Soldering and desoldering (some boards required modification or basic assembly)
·         Building pin header connectors using proper tools (wire stripper, crimping tool)
·         Building a smartphone app using an editor (Blynk)
·         Multiple power supplies of different voltages and current capabilities
·         I2C serial standard


Wednesday, October 8, 2014

Shift Registers

AIM

As I promised in the last posts, I'm testing the potential of shift registers. In the experiments so far, the number of devices (switches, led, etc...) we could control was limited to the number of pins of the Arduino board. Using shift registers we can control unlimited devices, using only three pins. Like usual, I'm building a graphical interface with LabView and I'm using XBee radio transmitters.


SHIFT REGISTER 74HC595

One of the Arduino pins sends a serial binary string (0 and 1). This string is recorded in the register and it's sent to the outputs of the registers. For example if the serial string from the arduino is "00101100" (8 bit), the output pins of the register will be:
  1: off
  2: off
  3: on
  4: off
  5: on
  6: on
  7: off
  8: off

Picture from www.adafruit.com

One shift register can handle 8 bits, but we can chain them together to control more devices. In this case I'm controlling 32 LEDs, so I need 4 shift registers. A chain of registers works exactly as one register. They need a data pin (where the serial string is sent to) a clock and latch. Every time the clock pin goes from low to high, the status of the data pin is recorded. When the latch pin gets low, the recorded data is sent to the 8 output pins. If you have more than one register, you can keep sending this data to the register, and after the 8th bit it keeps going to the next register. When you set the latch low, all the registers send the recorded data to the output pins. To chain shift registers they have to share clock (pin 11, blue wire) and latch (pin 12, purple wire). The output data pin of each register (pin 9) is connected to the input data pin (pin 14) of the next one. Obviously the last register is not using the output data pin. The shift register also needs connection to power (5V) and ground.


That's how I wired them up:



And this is how it looks:




LABVIEW

The idea of this control panel is similar to the other experiments, just with more items to control.


In this case each block of 8 switches (blue, yellow, red and green) is creating a byte as in the 8 switches experiment. The bytes are then converted to strings and concatenated together, separated by commas. 

In the diagram you can see the first block of switches and lights (blue). The pink lines coming from the bottom are the strings from the other three blocks (yellow, red and green).
The delay is necessary not to overflow the buffer of the Arduino serial port.

SKETCH

The Arduino IDE includes a useful command: shiftOut(). It writes a byte in sequence of 8 bits, while switching the clock 8 times. I'm using 4 shift registers, so I have to use that command 4 times before I switch LATCH to low (so the registers set their output pins). The values from the wireless serial string is read as an integer with the command parseInt(), but it's used as a byte by the function shiftOut().


int bval;
int yval;
int rval;
int gval;

const int SER =8; //Serial output to shift register
const int LATCH =9; //Shift register latch pin
const int CLK =10; //Shift register clock pin

void setup()
{
  Serial.begin(9600);
  pinMode(SER, OUTPUT);
  pinMode(LATCH, OUTPUT);
  pinMode(CLK, OUTPUT);
}

void loop()
{
  if(Serial.available() > 0)
  {
  gval = Serial.parseInt();
  rval = Serial.parseInt();
  yval = Serial.parseInt();
  bval = Serial.parseInt();

    digitalWrite(LATCH, LOW); //Latch low
    shiftOut(SER, CLK, MSBFIRST, bval);
    shiftOut(SER, CLK, MSBFIRST, yval);
    shiftOut(SER, CLK, MSBFIRST, rval);
    shiftOut(SER, CLK, MSBFIRST, gval);
    digitalWrite(LATCH, HIGH);
  }
}

CONCLUSIONS

Shift registers are very useful and easy to use, thanks to the Arduino library. We can control hundreds of LEDs or other devices using only 3 pins of the Arduino board.


REFERENCES

Exploring Arduino by Jeremy Blum (Chapter 7 - Shift Registers)


Saturday, October 4, 2014

Real Time Clock

AIM

I fixed one of the limits of my datalogger: the Arduino doesn't know what time it is. I just bought this DS1307 RTC (Real Time Clock) for a dollar, to add the function of time to my recordings. The DS1307 has an integrated I2C interface which makes it easy to communicate date and time using strings. It also has its own library to control the clock with easy commands. In this experiment I just added the clock function to my datalogger experiment, so I can see date and time for each data record.





SKETCH

This code is a copy of the datalogger project, plus the commands of the RTC. For the RTC I'm referring to the book "exploring arduino" from Jeremy Blum. I found it very useful and I recommend you to buy it. It covers basic to advanced topics, including practical projects, and it explains about electronics and useful components, not only Arduino. You can download the RTClib.h library here. Note that it's in a folder named "RTClib-master", which can't be read by the Arduino IDE. You have to rename it without "-" symbol.
As you can see, in the setup loop the code says "if the clock is not running write date and time from computer". Then the clock starts running. In the loop we extract the data we want from the string (year, month, day, hour, minute, seconds) and we set the format of date and time. These strings are then added to the string recorded to the SD card in the file "datalogger.log", separated by a tab ("\t").


#include <DHT11.h>
#include <SD.h>
#include <Wire.h> //For RTC
#include "RTClib.h" //For RTC

int pin=3;
DHT11 dht11(pin); 

RTC_DS1307 RTC;
String year, month, day, hour, minute, second, time, date;

const int chipSelect = 10;

void setup()
{
  pinMode(10, OUTPUT);
  
  if (!SD.begin(chipSelect)) {
    return;
  }
Wire.begin();
RTC.begin();
if (! RTC.isrunning())
{
RTC.adjust(DateTime(__DATE__, __TIME__));
}
}

void loop()
{
  DateTime datetime = RTC.now();
  year = String(datetime.year(), DEC);
  month = String(datetime.month(), DEC);
  day = String(datetime.day(), DEC);
  hour = String(datetime.hour(), DEC);
  minute = String(datetime.minute(), DEC);
  second = String(datetime.second(), DEC);
  date = year + "/" + month + "/" + day;
  time = hour + ":" + minute + ":" + second;
  
  int err;
  float temp, humi;
  if((err=dht11.read(humi, temp))==0)
  {
  int t,h;
  t = (int) temp;
  h = (int) humi;
  String dataString = "";
    dataString += date;
    dataString += "\t";
    dataString += time;
    dataString += "\t";
    dataString += "temperature:";
    dataString += String(t);
    dataString += "\t";
    dataString += "humidity:";
    dataString += String(h);
    dataString += "\t";
    dataString += "light:";
    dataString += String(analogRead(0));
    
  File dataFile = SD.open("datalog.log", FILE_WRITE);
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }
  }
  delay(3000);
}

CONCLUSIONS

This is how the data is recorded to the datalog.log file in the SD card:


Sunday, September 28, 2014

Wireless RGB LED and speaker control

AIM

Like the previous experiment, I want to send data from my computer to the Arduino to control a device, using radio frequencies. I'm using XBee transmitters for wireless communication. My model is XBee PRO S2: it uses 2.4GHz frequency at 50mW power, able to reach 3 km on open air. The configuration I'm using is always the same: AT mode, one coordinator (connected to the Arduino) and one router (connected to my computer). The purpose of the experiment is to change the colors of an RGB LED, and the volume and tune of a speaker, using a LabView graphical interface. This is different from the previous project because I need to send analog data now, so one byte is not enough. This time I need to send a string of values. The Arduino IDE includes a very useful command: Serial.parseInt() extract an integer number from a serial string.


ANALOG VOLTAGE

The arduino has some pins that can be used to output an analog voltage with 1023 increments from 0 to 5 V. This is not completely true: the 5 V pins are switched on and off at very high frequency so the average voltage changes. This works well in case of an LED because the human eyes can't see the LED going on and off hundred thousand times a second. What we see is the intensity of the light changing as a result of the time on and off. This tecnique is called PWM (pulse width modulation) and it works well also with motors. But in case of a speaker it's different. A speaker has to vibrate, which means that the power has to go an and off to produce sounds. The Arduino IDE has a function for that: tune() switches a pin on and off at a certain frequency to produce the sound we want in the speaker, always using the 5 V. 
As you can see in the following picture, the duty cycle (on/off time ratio) changes and the result average voltage (dotted line) changes as well. But the magnitude of the pulses doesn't change.
Picture from www.bristolwatch.com

This means that we can't use the PWM to control the volume. The only way to control the volume is to control the voltage of the pulses, using a potentiometer. But in this case I want to control everything from my LabView interface and that's why I'm using a Digital potentiometer (DigiPot). 

DIGIPOTS

DigiPots work as manual potentiometers, but they are IC (Integrated Circuits) controlled with digital signals. Some of them have an SPI communication interface like the MCP4231. The one I'm using is X9C103. It's controlled by 3 main pins: increment, up/down, chip select. The terminals of the variable resistance are High, Low, and Wiper, like in a normal potentiometer.

Picture from www.conrad.com

The digipot X9C103 has 99 increments of 101 Ω each for a maximum resistance of 10 kΩ. Plus the wiper has an internal resistance of 40 Ω. If we use the full scale in series with a speaker we find out that over the 1000 Ω it's really difficult to hear anything. For this reason I'm using only the first 10 increments, up to 1 kΩ. To do this, I made a scale from 0 to 10 in the labview interface and I add 90 in the Arduino sketch, so the resultant variable "vval" is between 90 and 100. I should have bought the digipot X9C102, which has a maximum resistance of 1 kΩ, so I would be able to use all 99 increments (of 10.1 Ω each).

WIRING

I spent many hours with this experiment rewiring the Digipot in different configuration but I only got it to work in this way: the Chip Select, Increment and Up/Down pins are controlled by the Arduino's pins 10, 11 and 12. The High terminal of the DigiPot is connected to pin 2 (the one we are going to "tune"), the Low is connected to ground, and the Wiper is connected to the positive of the speaker. The negative of the speaker is connected to ground. The DigiPot also needs a connection to 5V and ground.
The RGB LED is actually composed by 3 LEDs (red, green and blue) with common cathode (the negative terminal). Each LED needs a resistance: I'm using 220 Ω for the red and 330 Ω for the green and blue, because they have a different voltage drop. Pins 5,6 and 7 control the power to these LEDs (using PWM).
As usual, I connect an LCD screen to show me what's going on in the brain of the Arduino.


LABVIEW INTERFACE

This time it took me few minutes to create this simple page: the configuration of the VISA function for the serial communication is the same as in the previous project. Three colored bars control the intensity of the LEDs (0 to 255), and two horizontal bars control tune and volume of the speaker.


As you can see from the programming diagram, the numbers are converted to strings and then added together in an array, divided by commas. A delay is necessary not to overflow the buffer of the Arduino serial port.

SKETCH

I have rewritten this sketch many times before I got it to work.
After the serial string is read, the single values are extracted by the function parseInt(). The LED pins are set at these values straight away using PWM.
The X9C103 has its own library <DigiPotX9Cxxx.h> (download here) that allows us to use it easily. The variable "vval" (the wanted volume) is compared with the current volume and if it's different, the function pot.increase() and pot.decrease() adjust the value of the DigiPot.
The function "tune" has 2 arguments: the pin we want to tune and the value. This value can be seen in the file "pitches.h" included in the Arduino IDE. I didn't include this library because I'm not interested in playing particular notes, but I just wanna make some noise. Those values are between about 30 to 5000. I've chosen a range between 100 and 4000 to avoid acute or heavy noises.

#include <DigiPotX9Cxxx.h>
DigiPot pot(11,10,12);
#include <LiquidCrystal.h>
LiquidCrystal lcd(26, 27, 28, 29, 30, 31);

const int RED =7;
const int GREEN =6;
const int BLUE =5;

int rval = 0;
int gval = 0;
int bval = 0;
int tval = 0;
int vval = 0;
int currentvolume = 0;

void setup()
{
  pot.decrease(100);
  Serial.begin(9600);
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);
  lcd.begin(16, 2);
}
void loop()
{
  while (Serial.available() > 0)
  {
  rval = Serial.parseInt();
  gval = Serial.parseInt();
  bval = Serial.parseInt();
  tval = Serial.parseInt();
  vval = Serial.parseInt()+90;

  if(currentvolume < vval)
    {
    int diff = vval - currentvolume;
    pot.increase(diff);
    }
   else if(currentvolume > vval)
    {
    int diff = currentvolume - vval;
    pot.decrease(diff);
    } 
  currentvolume = vval;

  analogWrite(RED, rval);
  analogWrite(GREEN, gval);
  analogWrite(BLUE, bval);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(rval);
  lcd.setCursor(5,0);
  lcd.print(gval);
  lcd.setCursor(10,0);
  lcd.print(bval);
  lcd.setCursor(0,1);
  lcd.print(tval);
  lcd.setCursor(5,1);
  lcd.print(vval);
  lcd.setCursor(10,1);
  lcd.print(currentvolume);

  tone(2, map(tval,0,100,100,4000));
}
}

CONCLUSIONS

It was difficult to wire and program the DigiPot to control the volume of the speaker because it was altering the frequencies of the "tuned" pin and hence the sound was broken. After many hours of trouble rewiring and rewriting it finally works as expected.

Tuesday, August 26, 2014

Wireless switches control (with LabView)


This is another idea I had at work: in the entertainment industry we often install distribution board and we have to walk a long way to switch something on and off. Sometimes concerts and festivals cover a large area and our distribution board can be anywhere. It would be useful to operate them wireless. It would be even better to get some data from them, for example how much current the loads are drawing on each phase, but I'll get there when I'm more expert. In this experiment I just want to control 8 switches with my Arduino, using a LabView interface and XBee radio transmitters. In the distribution board there will be relays to open and close 240V circuits using a 5V signal. In this example I'm switching on and off simple LEDs. When I wire up the distro, I just have to replace the LEDs with relays.
In this case I'm using an Arduino Mega ADK, to make sure I have enough pins to control the switches and an LCD screen.
I've chosen to control 8 switches because the serial communication between LabView and the Arduino uses 256 characters (1 byte), exactly the number of combination we can create with 8 switches (2^8). This way, we only have to send one character (= 1 byte) and we don't need to synchronize the devices or use delays. If we want to control more switches, or we want to send an analog value over 255, we would need to send a string. We will see this in the next experiment.
The wiring is as follow:

LABVIEW INTERFACE


For the LabView interface I've used the code from the example "Advanced Serial Write and Read" downloadable from the National Instrument website. I added 8 switches. They output a boolean value (0 or 1) which is multiplied by the power of 2 correspondent to that switch number:
Switch 1 output multiply by 2^0.
Switch 2 output multiply by 2^1.
Switch 3 output multiply by 2^2.
Switch 4 output multiply by 2^3.
Switch 5 output multiply by 2^4.
Switch 6 output multiply by 2^5.
Switch 7 output multiply by 2^6.
Switch 8 output multiply by 2^7.
The values are then added to form the byte we have to send to the arduino.
This number is between 0 and 255, and each number correspond to a switches configuration. for example: 84 means (1-off, 2-off, 3-on, 4-off, 5-on, 6-off, 7-on, 8-off). This byte is then sent to the serial port through the function VISA.



ARDUINO SKETCH

Now we program the arduino to read the value from the serial port and execute the commands:

#include <LiquidCrystal.h>
LiquidCrystal lcd(26, 27, 28, 29, 30, 31);
int newvalue;
int oldvalue = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
}
void loop()
{
 if(Serial.available() > 0) {
   newvalue = Serial.read();
   
   if (newvalue != oldvalue){
   lcd.clear();
   lcd.setCursor(0, 0);
   lcd.print(newvalue);
   oldvalue = newvalue;
   }
    digitalWrite(2, HIGH && (oldvalue & B10000000));
    digitalWrite(3, HIGH && (oldvalue & B01000000));
    digitalWrite(4, HIGH && (oldvalue & B00100000));
    digitalWrite(5, HIGH && (oldvalue & B00010000));
    digitalWrite(6, HIGH && (oldvalue & B00001000));
    digitalWrite(7, HIGH && (oldvalue & B00000100));
    digitalWrite(8, HIGH && (oldvalue & B00000010));
    digitalWrite(9, HIGH && (oldvalue & B00000001));
   }
 delay(5);
}

As usual, I attached an LCD screen to display the value of the byte received by the Arduino through the serial port. It has to be the same displayed on the LabView interface.

The XBees simply replace the USB cable. I just plug them in as I would plug in a USB cable, nothing changes at the end devices. I just have to remember the switch on the Arduino XBee Shield: it has to be on "USB" when I program the controller, and on "micro" when I use the XBee.


CONCLUSIONS



The device works as expected, but it has some limitations: the communication of one byte can only control 8 switches. In the next experiments I will try to send and read strings. Also, the number of switches shouldn't be limited to the number of pins, in the future I will use shift registers to control several switches using one pin.

Monday, August 11, 2014

Remote communication between Arduino and smartphone

I developed this little device to check an analog sensor installed in a remote area using my phone. The idea is to check the level of fuel in generators we install in remote areas. So far, we had to drive there to check and refuel them. Now, we can check the level of fuel in each generator anytime and we can organize a refuelling trip more efficiently, only when necessary. The communication between the Arduino and the phone are simple text SMS.

COMPONENTS AND WIRING

To interface the arduino to the GSM network you need a GSM shield and a SIM card. I recommend the genuine Arduino GSM/GPRS shield, which has more functions, but here I'm using a SIM900 GSM/GPRS shield, which is enough for this project, and much cheaper. In Australia I bought a 20$ Vodafone simcard because it lasts one year without recharging, but I pay more than 28c per SMS (national and international). I'm sure you can get a better deal if you have time to look around.

The sensor: my employer gave me a fuel sensor to play with. It's a floating arm that moves the contact on a resistive rail. I measured the resistance across this resistor: 11 ohms when the arm is at the top (tank full), 185 ohms when the arm is completely down (tank empty). It's very important to know this value. The output value I want to see is a percentage from 0% (tank empty) to 100% (tank full).


If we connect this variable resistance in series with a fixed resistor we create a voltage divider: when we apply 5 volts we'll see a voltage drop across each resistor, and their sum will be 5 volts. The value of the fixed resistor should be about the same range of the variable. In this case I have a 68 ohms resistor. The voltage drop across resistors in series is proportional to their resistance. I wired up the circuit to measure the voltage drop across the fixed resistor with the analog input A5.


As usual, I connected a LCD to display the value in real time on the device.
The power comes from a 12V DC power supply in parallel with a 9.6V battery pack (8 x rechargable AA). When the generator is off, the batteries power the Arduino. When the generator is on, the power supply powers the Arduino and charges the batteries. To do that the power supply must have a higher voltage than the battery. The input voltage range (recommended) for the Arduino Uno is 7V to 12V.
It took me many hours to understand which pins are not used by the GSM shield. After many unsuccessful tries I was able to use pin 13,12,11,6,5,4 to run the LCD, without interfering with the operations of the shield.


SKETCH

We know the value read in the analog input is 0 to 1023, where 1023 correspond to 5 Volts. We have to apply Kirchoff Law to calculate the minimum and maximum value across the resistance, and then map this value to give an output value between 0 and 100%.

1023 * 68 / (185+68) = 275
1023 * 68 / (11+68) = 880

There is always a little error so, after few tries, I changed those values to 280 and 850 to give exactly 0 to 100% (it was close enough anyway).

I don't want to store the SMS on the SIM card, so I delete everything at the start of the program. This makes sure there is enough space to receive a command. Without this it stopped working suddenly and I couldn't understand why: the SIM was full.

A friend created an Android app to send a message to the device just pressing "test". The app sends a SMS starting with "a". The Arduino receive the message and it knows that "a" means "how much fuel is left?". It replies to the sender with the reading from the sensor.

Also, I want it to send an alarm SMS to a set "emergency phone" when the level of fuel passes the 50%, 25% and 10%.

#include <LiquidCrystal.h>
#include "SIM900.h"
#include <SoftwareSerial.h>
#include "sms.h"
SMSGSM sms;

LiquidCrystal lcd(13, 12, 11, 6, 5, 4);

int numdata;
boolean started=false;
char smsbuffer[160];
char n[20];
char sms_position;
char phone_number[20];
char sms_text[100];
int i;
char alarm_phone[20] = "+61439021813";

String dataString;
boolean alarm50 = false;
boolean alarm25 = false;
boolean alarm10 = false;


void setup()
{
  lcd.begin(16, 2);
  lcd.print("Testing...");
//  Serial.begin(9600);
//  Serial.println("GSM Shield testing.");
  if (gsm.begin(4800))
    {
//    Serial.println("\nstatus=READY");
    started=true;
    }
//    else Serial.println("\nstatus=IDLE");
  for(i=1;i<=20;i++)
    {
    sms.DeleteSMS(i);
    }
}

void loop()
{
  int val=(map(analogRead(A5), 280, 850, 0, 100));
  constrain (val, 0, 100);
  lcd.clear();
  lcd.print("Fuel:");
  lcd.setCursor(6,0);
  lcd.print(val);
  lcd.setCursor(9,0);
  lcd.print("%");
  delay(500);
 
  if(started)
    {
    sms_position=sms.IsSMSPresent(SMS_UNREAD);
    if (sms_position)
      {
//     Serial.print("SMS postion:");
//     Serial.println(sms_position,DEC);
      sms.GetSMS(sms_position, phone_number, sms_text, 100);
//      Serial.println(phone_number);
//      Serial.println(sms_text);
      sms.DeleteSMS(1);
      if(sms_text[0] == 'a')
        {
        dataString = "";
        dataString += "Fuel: ";
        dataString += (val);
        dataString += "%";
//        Serial.println(dataString);
        char charBuf[50];
        dataString.toCharArray(charBuf, 50);
        if (sms.SendSMS(phone_number, charBuf));
//        Serial.println("\nSMS sent OK");  
        }
      }
      else
      {
        if(val < 50 && !alarm50)
          {
          if (sms.SendSMS(alarm_phone, "Fuel < 50%"));
//          Serial.println("\nAlarm50 sent OK");
          alarm50 = true;
          }
          if(val < 25 && !alarm25)
          {
          if (sms.SendSMS(alarm_phone, "Fuel < 50%"));
//          Serial.println("\nAlarm25 sent OK");
          alarm25 = true;
          }
          if(val < 10 && !alarm10)
          {
          if (sms.SendSMS(alarm_phone, "Fuel < 50%"));
//          Serial.println("\nAlarm10 sent OK");
          alarm10 = true;
          }
//        Serial.println("NO NEW SMS,WAITING");
      }
  }
}

VIDEOS