Picking up invisible fence cable with Arduino

ijourneaux:
Should this line

iStop -= iMax

be

iStop = iMax

I think the code is correct, at least the line you mention. The idea was that when a peak was detected to stop the data collection after collecting another 50% of the max # of samples more. That puts the peak ~ in the middle of the data collected. If the max # of samples is a 1000 then the collection should stop when the sample counter is 500 bigger than it was when the peak was detected. If the sample counter was < 500 then the iStop value is simply 500 larger. But if the iStop value (= iCtr + 500) exceeds the max # of samples, then the iStop value has to be adjusted since the counter only runs to the max # before being reset. So the if the counter is at 900 when the peak is detected then iStop should be 400 since it's 100 samples to get to 1000 (the max counter value) and then another 400 samples to get the 500 samples desired post-detection. It might be that the exact number is 1 larger or smaller, I wasn't worried about being that exact. So if iStop > iMax then iStop = iStop - iMax.

As to the problem you’re seeing … I’ll need to think about it.

ijourneaux:
In the last sample code , I am trying to understand what this code is trying to do. As it stands right now in verbose mode, I can swipe the magnet under hall sensor and see that the sensor picks it up but i don’t see it the next time the arduino is restarted and you get a dump of the data in the EEPROM.

I'm confused by the above (it's too hot here today to think properly).

In verbose mode (verBose = true) the code loops slowly looking for a detection. If it finds one, it lights the red LED until the detection (signal > threshold) goes away. It is always sending the hall reading to the serial monitor, just like the original testbed code. It does not record data to EEPROM. Since the loops runs slowly (1/sec) you can certainly move the magnet fast enough to avoid detection, perhaps detecting one test run and not the next. Is that what you’re seeing ? You can certainly speed up the loop if you want (looptimeM), I just figured readings changing faster than 1/sec would be too hard to read.

In not verbose mode (EEPROM mode) the loop runs much quicker (~2k samples/sec). No data is sent to the serial monitor during the sampling in order to keep the loop time short. The hall data is recorded into SRAM, presently in a 600 sample array. When a peak is detected, the next 300 samples are taken and then the whole 600 samples are stored, in order of oldest to last taken, into EEPROM. The mode is then switched into verbose mode until reset or power down. Upon the next power up, it will be in EEPROM mode again (and stay that way unless you recompile w/verBose = true).

In either mode, during the startup() function, whatever data is in EEPROM, is spit out over the serial link (to be recorded). This data is from the last non-verbose mode run where a peak was detected (if there ever was one). No peak, no data. Never run in not-verbose mode, no data. The EEPROM contents will still be spit out, there just won’t be any actual data in it. Is this what you meant above ?

IIRC the green LED blinks when in verbose mode and sampling, and is on steady when in EEPROM mode and sampling. It’s off during the setup() function; when the EEPROM is being dumped and when the Hall sensor offset is being measured.

I have to go back and reread all of the posts regarding the v.2 code you posted. I think I got it to work but the data coming from the EEprom is odd.

When in verbose mode, the magnitude displayed to the screen can go up to ~100 when the magnet is right close to the sensor.

When I look at the data recorded to the EEprom, the maximum value I get is in the 9-10 range

Edit

Ok I finally got a data set I can believe. I think the tigger is a little low and the loop is so fast that the acquistion is over before the magnet gets right over the sensor.

I’ll look at the code too. From your preliminary data I thought 8 bits was enough, 0 - 255 was all the range needed. Thus I figured that storing the 8 lsb’s from the 10 bit ADC into EEPROM was good enough. Perhaps I screwed that up and did some (undesired) shifting ??? As long as the signal doesn’t exceed 255, the EEPROM should agree w/the verbose printout … assuming the same test conditions.

ijourneaux:
Edit

Ok I finally got a data set I can believe. I think the trigger is a little low and the loop is so fast that the acquisition is over before the magnet gets right over the sensor.

Feel free to adjust the setpoint as needed for the test.

My thinking was that verbose mode would allow you to see the results of a slow test in real time so you could adjust the parameters as needed. EEPROM was intended to be used on the ice at normal delivery speeds.

Ok finally had time to work on it. The zip file contains the sketch I used with should be almost identical to the one you originally programmed except for change to threshold, change led pins and increased delay on startup. This is still just testing in my home as no ice nearby has the magnetic strips mounted in the ice. Could get that within the next couple of weeks.

I have been working on the code for the handle based on the hall sensor and capacitance sensor working as they have to date. I am not sure that I know how to control the sensitivity of the capacitance sensor but I will deal with that later.

Based on several different code samples this is what I have come up. I am putting the handle to sleep after a period of time. The handle wakes up when pin 2 is shorted to ground with a ball switch (or something similar). At that point the handle is activated. If a the handle is being touched, the green light blinks quickly. If not, there is no blinking,

If the handle goes over the magnetic strip with the handle touched, the red LED blinks slowly. If the handle goes over the magnetic strip with the hand off of the handle, the green light go on solid.

Then the cycle repeats.

A couple of questions

  1. Is the choice I made for sleep mode ok? Using pin 2 as a trigger to wake the handle? Is there a better way to maximize battery life?

  2. In the loop function, how big should the delay function be?

doe this look ok?

// Curling handle Code
// Version 1: Aug 27, 2014

#include <avr/sleep.h>
#include "elapsedMillis.h"
#include "multiBlinkOrig.h"  // type definitions

elapsedMillis AwakeTime; //declare global if you don't want it reset every time loop runs

//define constants used
const int WakePin = 2;     //pin for cap sensor input (ball switch)
const int CapPin = 3;      //pin for cap sensor input

const int grnLEDpin = 5;   //pin for green LED output
const int redLEDpin = 6;   //pin for red LED output
const int HallPin = A0;    //pin for Hall sensor input
const int magThrsh = 100;  //magnitude of Hall reading needed to trip red LED

//define variables used
int magOffset = 0;          //offset from Hall sensor
int magReading = 0;         //magnitude of raw Hall reading with offset removed
float magSum = 0;           //sum used in computing offset
boolean handincontact = false;
boolean activated = false;
boolean hoglineviolation = false;
boolean successfulthrow = false;


// Blink Table T - Modify this table to suit whatever the output requirements are 
// Add or delete lines as required to achieve the desired effects.
//
ledTable  T[] =
//Pin  St   State 0      State 1  LastTime
{ 
  { grnLEDpin, 0, 0, {{HIGH, 200}, {LOW, 200}}, 0 },
  { redLEDpin, 0, 1, {{HIGH, 300}, {LOW, 600}}, 0 },

};

// Self adjusting constants for loop indexes
#define  MAX_STATE  (sizeof(T[0].state)/sizeof(stateDef))
#define  MAX_LED    (sizeof(T)/sizeof(ledTable))

void setup()
{
  for (int i=0; i < MAX_LED; i++)
  {
    pinMode(T[i].ledPin, OUTPUT);
    digitalWrite(T[i].ledPin, LOW);
    T[i].active = false;
  }
  Serial.begin(9600);
  SetupSleepMode();
  pinMode(CapPin, INPUT_PULLUP);
  pinMode(HallPin, INPUT_PULLUP);

  delay(3000);
  CalculateHallSensorOffset();
  AwakeTime = 0;   
}

void loop()
{
  if(not hoglineviolation) {
    ReadSensors();
    if(handincontact) {
      T[0].active = false;
      T[0].state[0].activeTime = 200;   // Reset green blink rate
      T[0].state[0].activeTime = 200;
      if(magReading > magThrsh) {
        T[1].active = true;
        hoglineviolation = true;
      }
      AwakeTime = 0;        // Reset AwakeTime
    } else {
      T[0].active = true;
      if(AwakeTime > 10000) {    // Slow down green blink rate
        T[0].state[0].activeTime = 50;
        T[0].state[0].activeTime = 350;
      }     
    }
    for (int i=0; i < MAX_LED; i++)
    {
      if(T[i].active) {
        // check if the state active time has expired (ie, it is less than current time)
        if (millis() >= T[i].lastTransTime + T[i].state[T[i].currentState].activeTime)
        {
          // switch to the next state with wrapround
          T[i].currentState = (T[i].currentState + 1) % MAX_STATE;
          // write out the next state value
          T[i].lastTransTime = millis();
          digitalWrite(T[i].ledPin, T[i].state[T[i].currentState].activeVal);
        }
      }  
    }
    if((AwakeTime > 20000) || ((AwakeTime > 10000) && (hoglineviolation))) {
      SleepNow();
      AwakeTime = 0;
      T[0].state[0].activeTime = 200;
      T[0].state[1].activeTime = 200;
      T[0].active = false;
      T[1].active = false;
      hoglineviolation = false;
    }
  }
  delay(50);  
}

void ReadSensors()
{ 
  handincontact = digitalRead(CapPin);
  magReading = analogRead(HallPin);
  magReading = abs(magReading - magOffset);
//  Serial.print(magReading);
//  Serial.print(",");
//  Serial.println(ishandletouched);
}

void SetupSleepMode()
{
  pinMode(WakePin, INPUT);

  Serial.begin(9600);

  /* Now it is time to enable an interrupt. In the function call 
   * attachInterrupt(A, B, C)
   * A   can be either 0 or 1 for interrupts on pin 2 or 3.   
   * 
   * B   Name of a function you want to execute while in interrupt A.
   *
   * C   Trigger mode of the interrupt pin. can be:
   *             LOW        a low level trigger
   *             CHANGE     a change in level trigger
   *             RISING     a rising edge of a level trigger
   *             FALLING    a falling edge of a level trigger
   *
   * In all but the IDLE sleep modes only LOW can be used.
   */

  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                      // wakeUpNow when pin 2 gets LOW 
}
void wakeUpNow()        // here the interrupt is handled after wakeup
{
  // execute code here after wake-up before returning to the loop() function
  // timers and code using timers (serial.print and more...) will not work here.
  // we don't really need to execute any special functions here, since we
  // just want the thing to wake up
}
void SleepNow()         // here we put the arduino to sleep
{
    /* Now is the time to set the sleep mode. In the Atmega8 datasheet
     * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
     * there is a list of sleep modes which explains which clocks and 
     * wake up sources are available in which sleep mode.
     *
     * In the avr/sleep.h file, the call names of these sleep modes are to be found:
     *
     * The 5 different modes are:
     *     SLEEP_MODE_IDLE         -the least power savings 
     *     SLEEP_MODE_ADC
     *     SLEEP_MODE_PWR_SAVE
     *     SLEEP_MODE_STANDBY
     *     SLEEP_MODE_PWR_DOWN     -the most power savings
     *
     * For now, we want as much power savings as possible, so we 
     * choose the according 
     * sleep mode: SLEEP_MODE_PWR_DOWN
     * 
     */  
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 

    /* Now it is time to enable an interrupt. We do it here so an 
     * accidentally pushed interrupt button doesn't interrupt 
     * our running program. if you want to be able to run 
     * interrupt code besides the sleep function, place it in 
     * setup() for example.
     * 
     * In the function call attachInterrupt(A, B, C)
     * A   can be either 0 or 1 for interrupts on pin 2 or 3.   
     * 
     * B   Name of a function you want to execute at interrupt for A.
     *
     * C   Trigger mode of the interrupt pin. can be:
     *             LOW        a low level triggers
     *             CHANGE     a change in level triggers
     *             RISING     a rising edge of a level triggers
     *             FALLING    a falling edge of a level triggers
     *
     * In all but the IDLE sleep modes only LOW can be used.
     */

    attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW 

    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(0);      // disables interrupt 0 on pin 2 so the 
                             // wakeUpNow code will not be executed 
                             // during normal running time.
}

void CalculateHallSensorOffset()
{
  int count = 50;
  //send a recalibration message
  //Serial.println("Place the sensor down flat, going to perform offset calibration");
  // wait 3 secs
  delay(3000);
  //Serial.println("Performing offset calibration");
  //take "count" A/D readings spaced 1 msec apart
  for(int i = 0; i < count; i++){
    magSum += analogRead(HallPin);
    delay(1);
  }
  //now compute average
  magOffset = int(magSum/count);
  //Serial.print("Done. Offset is ");
  //Serial.println(magOffset);
}

ijourneaux:
A couple of questions

  1. Is the choice I made for sleep mode ok? Using pin 2 as a trigger to wake the handle? Is there a better way to maximize battery life?

  2. In the loop function, how big should the delay function be?

doe this look ok?

I'll have a look at it.

It looks OK to me but I have to admit my brain isn’t all respooled up on the nuances of this project. I may have so time tonight to BB up a test circuit and see what happens.

As for the delay in loop() … I wouldn’t have one. Let loop() run as fast as it can so it detects the hogline ASAP.

Thanks

I have been trying to get my breadboard version to go into sleep mode but not having much luck.

I was able to get my code to work the way it is supposed to. Still have to figure how to get it into, and successfully out of, sleep mode but that should not be insurmountable.

To be done.

  • need to confirm the power consumption in the various modes

  • Need to figure out a battery layout. The CR123 was good for testing purposes but is too large for the application. I would have room on the “to be designed and built” circuit board if I use smaller coin style battery holders. The current battery holder uses 4 CR2477. As we have discussed this is probably not the ideal battery for this application.

  • Need to design the circuit board and have someone make and assemble the boards for me.

Take Care.

I finally made a bunch of power consumption measurements

In SLEEP_MODE_PWR_DOWN mode, the power consumption is at 7mA. 3-4 of that seems to be the led on the Pro Micro, the hall sensor is pulling 3mA and the capacitance breakout board is pulling 1-2mA. I am guessing the voltage regulator is pulling some as well.

Both the capacitance breakout board and the hall sensor are connected to the raw voltage input. where I am supplying a 3.3V.

When the capacitance sensor is activated via touch, the power consumption is about 8mA

When the green LED is flashing quickly the current draw is about 12mA, when blinking slowing about 8-9mA and when solid on 15mA

A couple of questions

  1. How can I prevent the capacitance sensor and the hall sensor from being powered when the Arduino is in sleep mode.

  2. Can I reduce the power consumption of the LEDs; perhaps increasing the resistor? I gues I could reduce the duty cycle on the LED.

ijourneaux:

  1. How can I prevent the capacitance sensor and the hall sensor from being powered when the Arduino is in sleep mode.
How about this trick ... use a DIO pin from the MCU as a power source ? One pin for the capacitance sensor and one pin for the hall sensor. The current draw seems well within a pins sourcing capability. The MCU then has complete control of when either device is on.

Thanks. Will give that a try.

Made the change and worked as expected. Current when in sleep mode was 2mA. Still high for my purposes but that has to be a result of the on board power LED with some contribution from the voltage regulator.

One thing that did show up. When the capacitance breakout board was powered directly, it was very robust at detecting whether or not a finger was touching the pad. When powered via one of the DIO pins, if you touched the pad, the capacitance sensor would stick high and would not go back to low. You had to power cycle the breadboard to get it to return to low. This did not occur 100% of the time but enough to be problematic.

Ian

I am trying to hook up the arduino and capacitance breakout board to an actual handle. When I try to hook up the lead from the handle to the antenna point on the capacitence breakout board, the capacitance sensor indicates " the device is being touched when it isn’t.

The touche surface on the handle seems straightforward. The main lead goes to a metalized surface covering the handle. Ground goes to a metalized surface covering the entire underside of the handle.

Any thoughts on what I could try get the capacitance sensor to work with the handle?

I hope everyone has a great Thanksgiving.

I have another questions regarding the capacitance breakout board. I am powering it via one of the DIO pins. THe seems to work great.

When I go into sleep_power_down_mde, the power consumptions drops alot to about 90uA but I noticed that if I physically disconnected the DIO input pin that goes to the output of the breakout board, the power consuption drops from 90uA to about 20uA.

Any thoughts on what causes this. Cna I configure the input pin to some other mode so I can take advantage of the drop in power consumption?

Using some comments from an other thread, I was able to get the power consumption while in SLEEP_MODE_POWER_DOWN I was able to get the power consumption down t about 27uA. ( Finally have a meter that can measure uA).

I went back and measured the power consumption of the original sensor handle.

Operating Sleep

Original Handle 25-45mA <1uA

Arduino Prototype 8-12mA 26-28uA

Since the handles spend most of their time in sleep mode, I am still a little concerned about battery life of the Arduino prototype. Granted we are talking uA but the power consumption in sleep mode is about 3x greater than the original handle.

After putzing around with the sketch and battery and was able to be the power consumption when in sleep mode to about 1.7uA, Sleep mode is good. Running mode, I am averaging about 12mA compared to 25-40mA on the old circuit board. Looking for tips to try and reduce the power consumption while the circuit is active.

I haven’t been able to get the touch surface on an existing handle to work with the capacitance break out board we are using. Right now if I hook up the handle electrode to the PAD connection, the touch sensor immediately activates. If I can figure out how to use the curling handle as an electrode then I am ready to try it on the ice (Breadboard attached to the top of the handle).