~ Networking and Communications.
~ post date: 2017.5.23, recent update: 2017.5.16

Background

Up to this point, aside from visual information via LCD or light interactivity via serial communication, what happened on the board stayed on the board. Now seems like a proper time to broaden the horizon a bit. I am drawn to the visual quality of networking via light and thusly chose to dive into infrared driven networking.

Contents
  • Networking light : Twin PCB
  • Testing the electrical components of the twins.
  • Infrared networking
  • Jump : Index
  • Project files
  • Download twin PCB traces file
  • Download twin PCB outline file (hint: make two)
  • Download IR communication send, receive, respond, receive, respond
  • Networking light : Twin PCB

    I was introduced to a project by Enrico Bassi which uses two ATMega boards connected to IR Sensors and IR LEDs to network by reading pauses in IR light (low). Upon seeing it, I was immediately impressed with the visceral qualities of networking with light. It is visible to our eyes! And, we could control a light in our hands to communicate to a machine. Admittedly, low tech stuff here. Remote controls... Plus, technically, we cannot see the light, the red LED on Bassi's board is for human reference, the IR LED is invisible to us. Regardless, as a first project to get into networking, I am game.

    I start by breaking down Bassi's work. This is an image from his Fab Academy page. I added the component labels. I would like to do the design part of this build quick. Get into the fabrication and coding and then circle knowledge back out. In my head, I plan to pull the components from the first boards I do and re-use them in more advanced boards, working my way up to fabricating my own special Fabkit. That in mind, I start making some mods to his board. The blue labels I plan to eliminate.

    Upon investigating his code and build further, I believe this same thing could be accomplished with an ATTiny44. Indeed, in his post, Bassi mentions that he switched to the ATMega 328 early in his process because his testing code was inflated and later realized the 48 had enough memory for the final arduino sketch. Bassi's Eagle schematic:

    I prepared a schematic of the IR Networking board using an ATTiny44.

    I had an idea that I would pull all the off board connections to one header but I am not sure it is going to work. Either way, I do not think it is worth the time. I will return to the lab, double check the inventory for an IR sensor, customize the pads and split the header.

    I redesigned the schematic with through holes for larger LEDs and the IR receiver I found in the Shanghai electronics market. Then I added an ISP header and another 2x2 for external power and RX/TX.

    Outline and traces look like this in the computer.

    Like this in my hand a few minutes later.

    And like this soldered a little while later still.

    I made a mistake when orientating the three pins for the IR sensor. I should have mirrored the pins. And to do that, I might have to rearrange the lights and sensor to accomplish the traces without any zero ohm resistors. For now, I need to keep moving forward.

    Download project files

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

  • Enrico Bassi IR Network : Infrared lights in love.
  • Rashid Thattayil IR Sensor using ATTiny 44 : Final project for Fab Academy.
  • ATMega328 Pinouts : Use this to compare Bassi pins with my own.
  • Testing the electrical components of the twins

    Infrared light is invisible to the human eye, so it is a challenge to know if the infrared LED is operational. Further, the sensors need to be operationally tested. I setup some simple arduino sketches to confirm the board.

    First, you need to match the ATtiny44 pins to Arduino speak. Look at this graphic and compare it to the schematic. The LED is on ATtiny 12, irLED 11 and irSensor 10. One, two, three. I will add those as integars.

    Now, many cameras can see infared light. The front camera on newer iPhones is one such camera.

    const int irPin = 2;  // ATtiny44 11
    
    void setup() {
    
    }
    
    void loop() {
      digitalWrite(irPin, HIGH);  // Turn on the irLED
    }
    }

    The camera needs to be aligned dead on which is not easy using a camera without a viewfinder. Nonetheless, both infrared LEDs are working.

    Now I will check the sensor. For this test, I modified code from my IR sensor trials.

    #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
    
    
    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
      digitalWrite(ledPin, HIGH);            // visually confirm read timing
      delay(60);                         // pause between readings (not too fast for stability)
      digitalWrite(ledPin, LOW);
      delay(60);
    }

    I did not see any variation in the sensor readings when I pointed the infrared light at the board. When the sensor receives light, it should read a 0. Then I recalled Enrico Bassi had the same problem and he made code for transmitting infrared light at 36kHz.

    I modified my transmitter board code with Bassi's 36kHz loop.

    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;
    
    void setup() {
      pinMode(ledPin, OUTPUT);
      pinMode(irPin, OUTPUT);
      pinMode(irSensor, INPUT);
    }
    
    void loop() {
      while (currentMillis - previousMillis < 125)  //LED on timing
      {
        IR();
        digitalWrite(ledPin, HIGH);
        currentMillis = millis();
      }
      previousMillis = currentMillis;
      while (currentMillis - previousMillis < 125)  //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);
    }

    Sensor one is confirmed. I am still having problems with understanding the board clock timing and how to adjust these numbers accordingly.

    The second sensor is unresponsive. The soldering looks good. I thought it might be an issue with the smaller irLed, so I grabbed the air conditioning remote. The sensor worked so I think there must be a problem with the smaller irLed I used. No, I just realized I forgot to dictate the pinModes in the setups. Now everything is working much better. (I added the pinMode settings to the code above, whereas previously I was not using.)

    Download project files

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

  • Unit Juggler : Convert timing units.
  • Infrared networking

    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.
  • Jump : Index

    J.travis Russett © 2017
    Creative Commons License All the work contained within is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) License
    You may remix, tweak, and build upon my work non-commercially, as long as you credit me and license your new creations under the identical terms.