Infrared networking

2017 May 25
#coding  #electronics  #comm 

Now I that I have a master-slave network setup, I would like to see if I can get the two boards to send signals back and forth autonomously.

First, I extended the sensor test sketch to react via its LED and the serial monitor. I kept the serial monitor so I could debug along the way. One board is transmitting IR signals at random intervals. The other board is checking the IR receiver and when a signal is sensed, it triggers the LED on the board to illuminate for a short time period, then resumes loking. First the code for the master:

//IR transmit; send a signal at a random interval

const int ledPin = 1; // ATtiny44 12
const int irPin = 2;  // ATtiny44 11
const int irSensor = 3;   // ATtiny44 10
long previousMillis = 0; //to calculate the interval of the blink without using a delay
unsigned long currentMillis = 0;
unsigned long ran = 0;
int interval = 125;

void setup() {
pinMode(ledPin, OUTPUT);
pinMode(irPin, OUTPUT);
pinMode(irSensor, INPUT);
}

void loop() {
ran = random(500, 2000);
while (currentMillis - previousMillis < interval)  //LED on timing
{
IR();
digitalWrite(ledPin, HIGH);
currentMillis = millis();
}
previousMillis = currentMillis;
while (currentMillis - previousMillis < ran)  //LED off timing
{
digitalWrite(ledPin, LOW);
currentMillis = millis();
}
previousMillis = currentMillis;  //reset counter offset
}

void IR()   //36kHz infrared transmitting
{
digitalWrite(irPin, HIGH);
delayMicroseconds(20);
digitalWrite(irPin, LOW);
delayMicroseconds(7);
}

And the code for the slave:

//IR receive; receive a signal and illuminate the LED for a brief time

#include <SoftwareSerial.h>
SoftwareSerial mySerial(0,7);         // RX PA7 6, TX PA0 13 (flipped)

// Using an ATTiny44
// Pin Configurations
const int ledPin = 1;         // PA1 12
const int irPin = 2;          // PA2 11
const int irSensor = 3;       // PA3 10 ADC3
int sensorValue = 0;          // variable to store the value coming from the sensor
int noSensorRead = 1;


void setup() {
pinMode(ledPin, OUTPUT);
pinMode(irPin, OUTPUT);
pinMode(irSensor, INPUT);
mySerial.begin(19200);              // I set this to 19200 and arduino monitor to 2400
mySerial.println("Hello");
}

void loop() {
sensorValue = digitalRead(irSensor);// read IR sensor write to variable
mySerial.print("sensor ");
mySerial.println(sensorValue);        // send reading to serial
//delay(10);
if (sensorValue != noSensorRead) {  // if IR sensed, pause reading and turn on LED
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
}
else {
delay(10);                         // pause between readings (not too fast for stability)
}
}

Next I will try to combine the two. As I customized this more, I needed to have a better understanding of what I was working with. millis() returns the number of milliseconds since the ATtiny44 board began running the current program. Unsigned long variables are extended size variables for number storage, and store 32 bits (4 bytes). Unlike standard longs unsigned longs won't store negative numbers, making their range from 0 to 4,294,967,295 (2^32 - 1). The only tricky bit in combining the two was getting my head around the millis() function, which is simple, if you take the time to find the information rather than making assumptions. In this way, functions can be run during a time interval, which probably would have been quite helpful a couple weeks ago when I was working with the phototransistor code variations.

//IR communication; receive a signal, send a signal, receive a signal, send a signal

#include <SoftwareSerial.h>
//SoftwareSerial mySerial(0,7);         // RX PA7 6, TX PA0 13 (flipped)

// Using an ATTiny44
// Pin Configurations
const int ledPin = 1;         // PA1 12
const int irPin = 2;          // PA2 11
const int irSensor = 3;       // PA3 10 ADC3
int sensorValue = 0;          // variable to store the value coming from the sensor
int noSensorRead = 1;
unsigned long previousMillis = 0;    //to calculate the interval of the blink without using a delay
unsigned long currentMillis = 0;
unsigned long ran = 125;
int interval = 250;

void setup() {
pinMode(ledPin, OUTPUT);
pinMode(irPin, OUTPUT);
pinMode(irSensor, INPUT);
//mySerial.begin(19200);              // I set this to 19200 and arduino monitor to 2400
//mySerial.println("Hello");
}

void loop() {
ran = random(250, 2000);  //generate a random interval

sensorValue = digitalRead(irSensor);// read IR sensor write to variable
//mySerial.print("sensor ");
//mySerial.println(sensorValue);        // send reading to serial

if (sensorValue != noSensorRead) {  // if IR sensed, pause reading and turn on LED
digitalWrite(ledPin, HIGH);
delay(interval);
digitalWrite(ledPin, LOW);
delay(ran);
currentMillis = millis();
previousMillis = currentMillis;  //set counter offset

while (currentMillis - previousMillis < interval) {  //LED on timing
IR();
digitalWrite(ledPin, HIGH);
currentMillis = millis();
}
digitalWrite(ledPin, LOW);
}

else {
delay(10);                         // pause between readings (not too fast for stability)
}
}

void IR()   //36kHz infrared transmitting
{
digitalWrite(irPin, HIGH);
delayMicroseconds(20);
digitalWrite(irPin, LOW);
delayMicroseconds(7);
}

The code works well until there is an interruption and one of the signals is missed. The smaller infrared LED has a narrower projection field. If attempting to communicate over longer distances, or with less precision in alignment, I recommend going with the wider LED. On the otherhand, a simple code like this is disrupted by any IR signal, such as an air conditioning remote, so narrowing the field of view on the receiver and/ or increasing the accuracy of the IR LED may be necessary in some scenarios.

At the beginning of that video, I pressed the signal and GND pins of one IR sensor together to fake a signal. That is one problem that needs to be addressed, when a signal is missed, how can it be re-established? To address this, I made the whole loop operate within a timing interval that exceeds the random max. If no signal is received, the board knows it missed one and immediately attempts to reestablish the network.

//IR communication; receive a signal, send a signal, receive a signal, send a signal

#include <SoftwareSerial.h>
//SoftwareSerial mySerial(0,7);         // RX PA7 6, TX PA0 13 (flipped)

// Using an ATTiny44
// Pin Configurations
const int ledPin = 1;         // PA1 12
const int irPin = 2;          // PA2 11
const int irSensor = 3;       // PA3 10 ADC3
int sensorValue = 0;          // variable to store the value coming from the sensor
int noSensorRead = 1;
unsigned long previousMillis = 0;    //to calculate the interval of the blink without using a
delay
unsigned long currentMillis = 0;
unsigned long ran = 125;
int interval = 250;

void setup() {
pinMode(ledPin, OUTPUT);
pinMode(irPin, OUTPUT);
pinMode(irSensor, INPUT);
//mySerial.begin(19200);              // I set this to 19200 and arduino monitor to 2400
//mySerial.println("Hello");
}

void loop() {
currentMillis = millis();
previousMillis = currentMillis;

while (currentMillis - previousMillis < interval) {  // Reestablishing connection
IR();
digitalWrite(ledPin, HIGH);
currentMillis = millis();
}

digitalWrite(ledPin, LOW);
previousMillis = currentMillis;  //set counter offset

while ( currentMillis - previousMillis < 2500) {  // if the timing of this exceeds random
max, reestablish
sensorValue = digitalRead(irSensor);    // read IR sensor write to variable
//mySerial.print("sensor ");
//mySerial.println(sensorValue);        // send reading to serial

if (sensorValue != noSensorRead) {  // if IR sensed, pause reading and turn on LED
digitalWrite(ledPin, HIGH);
delay(interval);
digitalWrite(ledPin, LOW);
ran = random(250, 2000);  //generate a random interval
delay(ran);
currentMillis = millis();
previousMillis = currentMillis;  //set counter offset

while (currentMillis - previousMillis < interval) {  //LED on timing
IR();
digitalWrite(ledPin, HIGH);
currentMillis = millis();
}

digitalWrite(ledPin, LOW);
previousMillis = currentMillis;  //set counter offset
}

else {
delay(10);                         // pause between readings (not too fast for stability)
currentMillis = millis();
}
}
}

void IR()   //36kHz infrared transmitting
{
digitalWrite(irPin, HIGH);
delayMicroseconds(20);
digitalWrite(irPin, LOW);
delayMicroseconds(7);
}

Next I tried to setup a system where one board would first confirm a message was received, then wait a random interval, and send a new message. After an hour and some change of work, my mind is spinning and I do not quite have it working yet. Here is my current sketch.

//IR communication; receive a signal, confirm, send a signal, confirm, receive a signal

//#include <SoftwareSerial.h>
//SoftwareSerial mySerial(0,7);         // RX PA7 6, TX PA0 13 (flipped)

// Using an ATTiny44
// Pin Configurations
const int ledPin = 1;         // PA1 12
const int irPin = 2;          // PA2 11
const int irSensor = 3;       // PA3 10 ADC3
int sensorValue = 0;          // variable to store the value coming from the sensor
unsigned long previousMillis = 0;    //to calculate the interval of the blink without using
a delay
unsigned long currentMillis = 0;
unsigned long ran = 125;
int interval = 250;


void setup() {
pinMode(ledPin, OUTPUT);
pinMode(irPin, OUTPUT);
pinMode(irSensor, INPUT);
//mySerial.begin(19200);              // I set this to 19200 and arduino monitor to 2400
//mySerial.println("Hello");
currentMillis = millis();       //reset timing
previousMillis = currentMillis;
while (currentMillis - previousMillis < interval) {  //startup
IR();
digitalWrite(ledPin, HIGH);
currentMillis = millis();
}
digitalWrite(ledPin, LOW);
}

void loop() {
sensorValue = digitalRead(irSensor);    // read IR sensor write to variable
//mySerial.print("sensor ");
//mySerial.println(sensorValue);        // send reading to serial

if (sensorValue == HIGH) {  // if IR sensed, respond, delay random, then send new

while (sensorValue == LOW) {   // wait until the entire signal was received
//digitalWrite(ledPin, HIGH);
delay(10);  //in case of missed signals
sensorValue = digitalRead(irSensor);
}
//digitalWrite(ledPin, LOW);
//delay(10);  //visual confirmation of transition from read to send

currentMillis = millis();       //reset timing
previousMillis = currentMillis;
while (currentMillis - previousMillis < interval) {  //confirm message receipt
IR();
digitalWrite(ledPin, HIGH);
currentMillis = millis();
}
digitalWrite(ledPin, LOW);

ran = random(500, 1000);  //generate a random interval then delay
delay(ran);

while (sensorValue == HIGH)  {    //send message and wait for confirm
currentMillis = millis();       //reset timing
previousMillis = currentMillis;
while (currentMillis - previousMillis < interval) {  // send a message
  IR();
  digitalWrite(ledPin, HIGH);
  currentMillis = millis();
}
digitalWrite(ledPin, LOW);
//delay(20);   //give other board a chance to respond
currentMillis = millis();       //reset timing
previousMillis = currentMillis;
while (sensorValue == HIGH && currentMillis - previousMillis < interval*1.1) {  // check
message receipt
  sensorValue = digitalRead(irSensor);
}
}
delay(200); // time for the signal to be sent before returning to sensing
}

else {
delay(10);                         // pause between readings (not too fast for stability)
}
}

void IR()   //36kHz infrared transmitting
{
digitalWrite(irPin, HIGH);
delayMicroseconds(20);
digitalWrite(irPin, LOW);
delayMicroseconds(7);
}

Download project files

I will post links to resources I have found helpful here.

  • Boolean Operators : Basic Arduino function.
  • Share this post...

    « Previous post :: Processing Light Graph

    Enough with the tutorials. Now I would like to start putting these together with some kind of simple visual or audio interface connected to sensor readings. I started by looking at this former Fab Academy student's work mapping phototransistor settings to a dynamically configurable 3D model. He was able to combine sensor readings from arduino with a Processing sketch from Open Processing Org, a wonderful place for sharing processing sketches. I went there with the intention to grab a sketch, however I was a little overwhelmed so instead I started looking at former Fab Academy students' pages for a sketch...

    Next post :: Grow Module | The science »

    The nonvascular bryophyte microbial fuel cell operates in two main zones: anode and cathode. The anode side is a layer of moss, two mixtures of cotton and carbon (10:1, cotton : carbon weight) sandwiching a single layer of stainless steel mesh (as thin as possible). This anode mixture is from the 2016 October 3 Royal Society published work of Paolo Bombelli, et al. Electrical output of bryophyte microbial fuel cell systems is sufficient to power a radio or an environmental sensor. The cathode is a sandwich of acrylic (bread), rubber (condiment), hydrogen electrode (10 wt % Pt/C + 5% Nafion...