Thursday, July 25, 2013

Jim Gifford's Quintet Optical Sensor

Here's a project from Jim Gifford (Hallet Cove Southern) from "Down Under" which illustrates the best of the open source paradigm.  Jim has taken parts of other projects posted here, merged them and re-purposed them to create a rather nifty project. This is what open source is about - reuse and innovation!

Jim has used a pair of LaunchPads, LEDs and optical detectors to detect the trains in his five-turn helix.  Here's Jim's description:


Quintet Optical Sensor


This project is to sense movement of a train through my helix.  The single track helix has a 33” radius and has approximately 5 ½ turns – HO scale 95 feet of track – so I have decided 10 detectors are required each having an output which stays on for around 10-12 seconds so that progression of a single railcar can be seen on a “row of LED’s” display.


In this project two LaunchPads will control the 10 LED display.  Each LaunchPad reads five of the optical sensors providing track occupancy and then illuminates respective LED’s for a predetermined time.  Please note that the “Block Occupied” indication comes from a “Block Watcher” detector to be used for signal logic.

Proposed Indicator Panel


Bill of Materials:

(1) 2 x LaunchPad with MSP430G2553IN20 processor.

(2) 10 x Optical sensor modules from a Chinese vendor IR Reflective Sensor (this link was valid at the time of publication) .
(3) 6 LED’s per LaunchPad.
(4) 5V regulated power supply to supply the optical sensors.


Optical Sensor - component side of board

Optical Sensor - emitter/detector side of board

Theory of Operation: 

Reflective optical sensors are placed adjacent to the track at predetermined locations on the helix. 





Each set of five sensors are connected to pins [Board (IC)] P1.0 (2), P1.3 (5), P1.4 (6), P1.5 (7), P1.6 (14)  and the respective indicator LED’s are connected to pins P2.0 (8), P2.1 (9), P2.2 (10), P2.3 (11), P2.4 (12) of the LaunchPad.


When a train is detected, the software in the LaunchPad causes the respective output to go high (turn on) and stay illuminated for a predetermined time.

This is achieved by using a simple counter for each Input/Output pair e.g. Input #1 P2.0 (input) and P1.0 (output) [Output_1_Timer].  The other pairs are P2.1/P1.3 [Output_2_Timer], P2.2/P1.4 [Output_3_Timer], P2.3/P1.5 [Output_4_Timer]  and P2.4/P1.6 [Output_5_Timer]. When an input is detected the respective counter is indexed by 1. If a long train is used it would be possible that all detectors are indexed at the same time. If the value of a counter is equal to 1 then the respective output is switched on. The program then checks to see if the counter exceeds the value of the variable max_time.  When the value of max_time is exceeded then the respective output in turned off and the respective counter reset to zero.  The final check is to index the respective counter for the next iteration of the while loop then the program keeps cycling at the chip operating frequency which depends on supply voltage as described on page 21 of the manual.

The Power on LED is connected to pin P2.5 (13) and illuminates when the LaunchPad is running the program.

Notes on setting the sensitivity of the detectors

  1. Turning the adjustment screw continuously clockwise increases the sensitivity eventually it detects nothing but activates (output goes low) make sure that the adjustment screw is backed off at least one turn or spurious activation results.
  2. The surface the “reflection” is sought from does matter good results where found with white, grey, orange, with varied results from dark brown & black.
  3. Direct sunlight will activate (output goes low) the sensor.

Circuit Diagram: 

Remember two of these circuits are required to illuminate the 10 LED’s.  While the diagram looks complicated, hookup is actually reasonably simple using wire wrap techniques.


The only complication comes in the fact that the relays and optical sensors require 5 VDC.  Remember that the LaunchPad runs on 3.3 VDC, so it cannot supply 5 VDC for the other modules. An external 5VDC source is wired to the relay module and to the optical sensors.  For the circuit to work with the LaunchPad running from (potentially) a different power supply, a common ground connection must be made between the 5 VDC supply and the LaunchPad and it's 3.3 VDC supply.  Run a wire from the GND pin on the LaunchPad to make a connection with the GND (-) wire from the 5 VDC supply.  The LaunchPad may be powered via it's USB port (as I did) or from an external 3.3 VDC supply.



Demonstration of the Prototype

Link to Optical sensor testing – note detector 4 fails….

Link to testing with minimal time delay.

Link to see final configuration.


The Code

The code can be found here.

The code listing follows below.

/*
* Quintet Optical Sensor Version 1.1
* COPYRIGHT © 2013 Jim Gifford
* http://halletcovesouthern.blogspot.com.au
* Provided under a Creative Commons Attribution, Non-Commercial Share Alike,3.0 Unported License
*
* I wish to acknowledge code snippets initially written by:
* “Steve Hoffy Hofmeister”
* “Terry Terrance”
* that were adapted for use.
*
* Also thanks to Toni Ryan for his clarity advice
*
* TARGETED TO MSP430 LANUCHPAD W/MSP430G2553 PROCESSOR
*
* Design Notes:
*
* This code is designed to receive inputs from 5 Optical Sensors and light 5 independent indicator LEDS, hold them on for a predefined period of time (currently set to about 12 seconds), to signal that an object as been detected.
*
*This Project has been designed to be powered by the USB connection. Consult other available instructions on how to connect your MSP430 to external power sources before attempting.
*
*
* Circuit Pinout:
* PIN 1.0 = Anode of Indicator LED #1 \
* PIN 1.1 = UNASSIGNED - UART
* PIN 1.2 = UNASSIGNED - UART
* PIN 1.3 = Anode of Indicator LED #2 \
* PIN 1.4 = Anode of Indicator LED #3 \ Cathodes to ground
* PIN 1.5 = Anode of Indicator LED #4 /
* PIN 1.6 = Anode of Indicator LED #5 /
* PIN 1.7 = UNASSIGNED
* PIN 2.0 = Input for optical sensor 1
* PIN 2.1 = Input for optical sensor 2
* PIN 2.2 = Input for optical sensor 3
* PIN 2.3 = Input for optical sensor 4
* PIN 2.4 = Input for optical sensor 5
* PIN 2.5 = Circuit Power Indicator
* PINS 1.1, 1.2, 1.7 are left unused for integration into other projects.
*/

#include <msp430g2553.h>

                /////////////////////////////////////////////
                //  Define variables
                ////////////////////////////////////////////

                volatile long Output_1_Timer =0;       //Define Output_1_Timer & set to 0
                volatile long Output_2_Timer =0;       //Define Output_2_Timer & set to 0
                volatile long Output_3_Timer =0;       //Define Output_3_Timer & set to 0
                volatile long Output_4_Timer =0;       //Define Output_4_Timer & set to 0
                volatile long Output_5_Timer =0;       //Define Output_5_Timer & set to 0

                volatile long max_time=100000;  //Define time for outputs to stay on

void main(void) {

   WDTCTL = WDTPW + WDTHOLD;        // Stop watchdog timer

   P2DIR |= BIT5;  //  Circuit Power Indicator
   P2OUT |= BIT5;  //  Used to Trouble Shooting


//Configure Optical Sensors

    P2DIR &= ~BIT0; // sets Port 2, bit 0 to input for optical detector1
    P2DIR &= ~BIT1; // sets Port 2, bit 1 to input for optical detector2
    P2DIR &= ~BIT2; // sets Port 2, bit 2 to input for optical detector3
    P2DIR &= ~BIT3; // sets Port 2, bit 3 to input for optical detector4
    P2DIR &= ~BIT4; // sets Port 2, bit 4 to input for optical detector5

    P2REN |= BIT0;  // sets pull-up resistor on Port 2, bit 0 input pin
    P2REN |= BIT1;  // sets pull-up resistor on Port 2, bit 1 input pin
    P2REN |= BIT2;  // sets pull-up resistor on Port 2, bit 2 input pin
    P2REN |= BIT3;  // sets pull-up resistor on Port 2, bit 3 input pin
    P2REN |= BIT4;  // sets pull-up resistor on Port 2, bit 4 input pin

    P2OUT |= BIT0;  // sets pull-up resistor on Port 2, bit 0 to pull-up
    P2OUT |= BIT1;  // sets pull-up resistor on Port 2, bit 1 to pull-up
    P2OUT |= BIT2;  // sets pull-up resistor on Port 2, bit 2 to pull-up
    P2OUT |= BIT3;  // sets pull-up resistor on Port 2, bit 3 to pull-up
    P2OUT |= BIT4;  // sets pull-up resistor on Port 2, bit 4 to pull-up


//Configure Outputs

   P1DIR |= BIT0;                     // Port 1 P1.0 (Indicator #1) as output
   P1OUT &= ~BIT0;                // Port 1 P1.0 (Indicator #1) Set to off State

   P1DIR |= BIT3;                     // Port 1 P1.3 (Indicator #2) as output
   P1OUT &= ~BIT3;                // Port 1 P1.3 (Indicator #2) Set to off State

   P1DIR |= BIT4;                     // Port 1 P1.4 (Indicator #3) as output
   P1OUT &= ~BIT4;                // Port 1 P1.4 (Indicator #3) Set to off State

   P1DIR |= BIT5;                     // Port 1 P1.5 (Indicator #4) as output
   P1OUT &= ~BIT5;                // Port 1 P1.5 (Indicator #4) Set to off State

   P1DIR |= BIT6;                     // Port 1 P1.6 (Indicator #5) as output
   P1OUT &= ~BIT6;                // Port 1 P1.6 (Indicator #5) Set to off State

// Let's Get Down to Business

  while( 1 )              // begin infinite loop
   {

                //Detector #1
                if( (P2IN & BIT0) == 0)                                            // When IR Detector #1 activates by going low
                                Output_1_Timer ++;                                               //Index the counter
                if (Output_1_Timer ==1)                                        // First iteration when Detector #1 active
                                P1OUT |= BIT0;                                      // Set LED Indicator #1 to ON
                if (Output_1_Timer > max_time)           // Time up?
                                {
                                Output_1_Timer =0;                                               // Reset the counter
                                P1OUT &= ~BIT0;                                                   // Set LED Indicator #1 to OFF
                                }
                if (Output_1_Timer !=0)                                         // Output_1_Timer  is active
                                Output_1_Timer ++;                                               // Index the counter
                //END of Detector #1

                //Detector #2
                if( (P2IN & BIT1) == 0)                                            // When IR Detector #2 activates by going low
                                Output_2_Timer ++;                                               // Index the counter
                if (Output_2_Timer ==1)                                        // First iteration when Detector #2 active
                                P1OUT |= BIT3;                                                      // Set LED Indicator #2 to ON
                if (Output_2_Timer > max_time)           // Time up?
                                {
                                Output_2_Timer =0;                                               // Reset the counter
                                P1OUT &= ~BIT3 ;                                  // Set LED Indicator #2 to OFF
                                }
                if (Output_2_Timer !=0)                                         // Output_2_Timer  is active
                                Output_2_Timer ++;                                               // Index the counter
       //END of Detector #2

       //Detector #3
                if( (P2IN & BIT2) == 0)                                            // When IR Detector #3 activates by going low
                                Output_3_Timer ++;                                               // Index the counter
                if (Output_3_Timer ==1)                                        // First iteration when Detector #3 active
                                P1OUT |= BIT4;                                      // Set LED Indicator #3 to ON
                if (Output_3_Timer > max_time)           // Time up?
                                {
                                Output_3_Timer =0;                                               // Reset the counter
                                P1OUT &= ~BIT4;                                                   // Set LED Indicator #3 to OFF
                                }
                if (Output_3_Timer !=0)                                         // Output_3_Timer  is active
                                Output_3_Timer ++;                                               // Index the counter
                //END of Detector #3

                //Detector #4
                if( (P2IN & BIT3) == 0)                                            // When IR Detector #4 activates by going low
                                Output_4_Timer ++;                                               // Index the counter
                if (Output_4_Timer ==1)                                        // First iteration when Detector #4 active
                                P1OUT |= BIT5;                                      // Set LED Indicator #4 to ON
                if (Output_4_Timer > max_time)           // Time up?
                                {
                                Output_4_Timer =0;                                               // Reset the counter
                                P1OUT &= ~BIT5;                                                   // Set LED Indicator #4 to OFF
                                }
                if (Output_4_Timer !=0)                                         // Output_4_Timer  is active
                                Output_4_Timer ++;                                               // Index the counter
                //END of Detector #4

                //Detector #5
                if( (P2IN & BIT4) == 0)                                            // When IR Detector #5 activates by going low
                                Output_5_Timer ++;                                               // Index the counter
                if (Output_5_Timer ==1)                                        // First iteration when Detector #5 active
                                P1OUT |= BIT6;                                      // Set LED Indicator #5 to ON
                if (Output_5_Timer > max_time)           // Time up?
                                {
                                Output_5_Timer =0;                                               // Reset the counter
                                P1OUT &= ~BIT6;                                                   // Set LED Indicator #5 to OFF
                                }
                if (Output_5_Timer !=0)                                         // Output_5_Timer  is active
                                Output_5_Timer ++;                                               // Index the counter
                //END of Detector #5


   }            //End of While

}  // END OF MAIN





3 comments:

  1. Good stuff! Wonder if it will work with low level infrared lighting? ;)

    ReplyDelete
  2. Michael I have a infrared camera in the same area and the system still seems to work ok.

    Here is a link to it operating in place: https://www.youtube.com/watch?v=bkBk-bmS4M4

    Cheers, Jim

    ReplyDelete