Tuesday, September 29, 2015

Custom Stairway + Hallway Lighting Project - Part 3

At the end of my last writing the last thing I needed to do before ordering stuff was to test my PIR sensor in the hallway to get a feeling of if it would provide sufficient detection.  Using some painters tape, old cat5e, and some leads, I taped up a sensor roughly where it will go.  It looked terrible, but it got me what I needed.  A single sensor reliably covered about 1/2 to 2/3 of the hallway.  2 sensors would work as planned.  

I did some additional software work to support the muxing and to also take a slightly different approach to the averaging code for the active IR sensors.  (Thanks to my Father-In-Law for the idea).  Originally I had it set up to store each sensor reading for a given IR sensor in an array (within the class instance) and then on each read, move a pointer to a element of the array and update it with the new reading.  Then I would iterate through the array, sum, and average the results.  My father-in-law suggested that I keep the array, but instead do something a little different that would require no iteration.  Basically I would hold a internal variable that is the current sum of the last 4 readings.  When the read starts I would add the value of the read, move the array pointer forward one (which would then cause the pointer to be pointing at the oldest element in the array), then subtract the value of that element in the array from the total.  Then I could simply divide the running total by the number of elements (in this case 4).  This eliminated the iteration and worked fantastically. Here is the DistanceSensor class:


class DistanceSensor : public Sensor{

 int PIN;
 int stackLocation;
 double triggerDistance;
 bool debug;
 double total;

 static const int stackSize = 4;

 double avg[stackSize];

 public:
 DistanceSensor(int pinnum, double triggerDist, bool enableDebug) {
  PIN = pinnum;
      triggerDistance = triggerDist;
      stackLocation = 0;
  debug = enableDebug;
  total = 0;

  #ifdef DEBUG
  if (debug) {
   Serial.print("Adding Motion Detector on PIN:");
       Serial.print(pinnum);
       Serial.print(" | Trigger Distance:");
       Serial.println(triggerDist);
        }
        #endif
     
      for (int i = 0; i < stackSize; i++) {
       avg[i] = 100.0;
       total += 100;
      }
 }

 //Keep a running total of the distance as it relates to stack size.  
 //On each read, it will add the newest amount to the total, move the pointer forward one and remove that distance from the total.  
 //This means we don't need to loop through the stack on each read. -  Thanks to my Father-In-Law for this idea.
 bool Get() {
  double distance = 6202.3*pow(analogMuxRead(PIN),-1.056);
  
  avg[stackLocation] = distance;
  total += distance;
  
  //Move us forward one
  if (stackLocation == stackSize -1) {
   stackLocation = 0;
  }else{
   stackLocation ++;
  }
  //Remove the distance from the total for the next.  (basically removing the oldest distance)
  total -= avg[stackLocation];
  
  double temp = total / stackSize;

      #ifdef DEBUG
  if (debug) {
   Serial.print("Distance = ");
   Serial.print(distance);
   Serial.print(" | Average = ");
   Serial.println(temp);
  }
  #endif
  
  return temp <= triggerDistance;
 }
};


 The only piece I have left planned in terms of software is to do some variable lighting levels based on the ambient light.  (So if it is really dark, then the lights won't turn on as bright.  The notion being that you probably are used to the dark and don't need to be blinded.)  This isn't as simple as just finding out the light level and setting the lights output level though as I need to store the value just before the lights turn on.  Otherwise the lights themselves would alter the ambient level and would eventually cause a loop that would ultimately turn the lights on to full brightness.  However the current code doesn't return the light level when I fetch it.  It simply returns whether or not the light level is sufficiently dark to turn on the lights at all.  So refactoring will need to occur here.


I ordered all the parts and eagerly awaited their arrival.  Among them was a screw-down terminal shield from Adafruit (Picture below after I had already soldered all the components).  Also was the 16 channel multiplexer.  I also added screw down terminals to it as well.  My goal here is to solder wires directly to the boards as little as possible.  (In fact I'm hoping to avoid it entirely).

I did have to modify the redboard slightly.  In the lower left you'll see the outline of what used to be the power plug.  It turns out on the redboard with this particular shield that the power plug is just too high (by about 1/8").  Since I'm going to be feeding power via the screwshield to the VIN pin, that plug is un-needed.  So away it went.


I don't have alot of experience with PCB soldering, but overall I think this turned out fairly well.  





Next step was to get the multiplexer working, both in code and wiring.   It looks like a bit of a rats nest, but it works.  I did have a little initial trouble when I forgot to set the pin mode on the digital control pins to output.  This would cause the digital pins to float, which would cause the mux to shift around reading different pins.  Since it was reading different pins most of which weren't hooked up, those would have floating values too.  Needless to say I had some wildly inaccurate results in the logs until I cleared that up.



The box I'm putting all this into is roughly 10x6x3 (LxWxH).  The box is going to undergo a fair amount of modifications as well to handle all the input/output.  In the bottom of the box is a set of standoffs.  I cut out a piece of 1/4" poly-carbonate.


I then did a dry fit of the internal components.  I wanted to get a general feel for how everything actually would sit before I started cutting holes in the case.  My plan is to have the left side of the box contain all the sensor inputs. Those will all run into the mux (with the exception of Vcc and Ground which will go straight to the redboard).  On the right side I will have the power input, power switch, power output and USB header (so that I can easily plug in and do diagnostics without having to open the case up).  Somewhere I still need to fit a switch that when closed will cause all lights to turn on to 100%.



I ordered a black 6 port keystone plate for the Cat5e connectors.  It is a little taller than the box when the lid is off, but looks exactly right when the lid is on (which will be 99.9% of the time).  That said, the plate is not black.  Not really.  It's more of a deep brown.  But whatever...


 I have all the ports on the other side put in as well except USB.  I don't know why but I totally spaced on that, so I'll need to put that in tomorrow.  You might notice that just below the power switch there is some plastic that looks terrible.  Yeah....totally cut the hole for the switch a tad too big.  It looks terrible, but I'm not sure how to fix it really. (and I'm not buying a new box).  I do need to erase those pencil lines though.....


Here I have the components in (though still not screwed down) to make sure everything looks good.  It does, so yay!  


So tomorrow I will be getting the screws to screw down the power supply and bus bar.  I already put holes in and screwed down the controller and mux board.  I will also add in the USB header somewhere.  Then I'll start the process of wiring this thing together.  Once that is complete I'll do some basic testing on it and then it will be time to start modifying the handrails for the stairwell.

No comments:

Post a Comment