New Anemometer

Today the new ADS anemometer arrived from Hobby Boards.  Here’s what was in the package

Anemometer Package Contents

I started out following the instructions to assemble it.  First put the pole together.

Assembled Pole

Assembled Pole

Next I installed the mounting arm.

Mounting Arm Installed

Mounting Arm Installed

Then mount the anemometer and wind vane.

Sensors Mounted

Sensors Mounted

Then I added the controller board and connected the wires.  Or so I thought.  In my excitement I had stopped following the instructions.  I paid for that later on when I started testing.

Completed Anemometer

Completed Anemometer

Next came time for some testing.  I hooked the anemometer board to my 1-Wire network and fired up the 1-Wire viewer application.  It showed the DS2423 and DS2438 chips from the anemometer board.  I updated the information in my application configuration file and started up the application.  Now the problems started.  The sensors would appear and disappear intermittently.  Sometimes the bus was shorted.  The anemometer board was intermittent.   Sensors would come and go.  This problem occured with both my application and the 1-Wire viewer.

I checked my power supply (this anemometer, my barometer, and the hub itself all require external power).  My voltmeter read right around 15 volts, which would meet the power requirements.  I removed all the other sensors and was able to isolate the problem as being with the anemometer board.  I finally decided to open the case for the anemometer, and I immediately saw my mistake.

If I had continued to follow the instructions I wouldn’t have had any problems, as they instructed me to open the case.  That’s where the jack is for connecting the sensors to the anemometer board.  I had connected the sensors directly to the 1-Wire bus.  This next picture clearly shows the third connector for the anemometer that isn’t visible until you open the case.  I want to stress that this was my mistake.  The instructions were clear on how to connect things (provided you read and follow them).

1-Wire Anemometer Board

1-Wire Anemometer Board

Now that I had everything wired up correctly, the board worked fine  My software updates to read the new sensors worked just as they should.  My only comment is that the wind direction sensor isn’t linear.  Directions such as NNE or ESE don’t cover as many degrees of rotation as the others.  In all fairness, the sensor only claims to have a resolution of 22.5 degrees.  And it probably does meet that specification.  For people who need greater accuracy than that Hobby Boards carries a higher quality sensor with a higher price tag to match.  This one will suit my needs.  Another plus is that this sensor doesn’t appear to have positions that are between directions and return an error like my old AAG anemometer would do.

Here’s some code for how to read the anemometer board and the ADS sensors.  A lot of this is specific to my application, but the basic logic should still make sense.  The formatting got messed up in moving the code to the Web.

Here’s code for the wind direction:

import com.dalsemi.onewire.OneWireException;
import com.dalsemi.onewire.adapter.DSPortAdapter;
import com.dalsemi.onewire.container.OneWireContainer26;

public class ADSWindDirectionSensor
{
    private static final int maxRetryCount = 3;
    private static final double WIND_DIR_ADJUST = 1.000;
    private OneWireContainer26 windDirectionDevice = null;

    public ADSWindDirectionSensor(DSPortAdapter adapter,
         SensorConfiguration config)
    {
        super(adapter, config);

        windDirectionDevice =
            new OneWireContainer26(adapter, config.getID());
    }

    public int getWindDirection()
    {
        int windDir = WIND_DIRECTION_ERROR;
        boolean bOK = false;
        int retryCount = 0;

        if (windDirectionDevice != null && isEnabled())
        {
            while(!bOK && retryCount < maxRetryCount)
            {
              try
              {
                if (this.isDebugFlag())
                {
                  ErrorLog.logError("Wind Dir: Device = " +
                    windDirectionDevice.getName() + "  ID = " +
                    windDirectionDevice.getAddressAsString());
                }

                this.getPath().open();

                // read 1-wire device's state
                byte[] state = windDirectionDevice.readDevice();

                // Read sensor's output voltage
                windDirectionDevice.doADConvert(
                    OneWireContainer26.CHANNEL_VAD, state);
                double Vad = windDirectionDevice.getADVoltage(
                    OneWireContainer26.CHANNEL_VAD, state);

                // Read the sensor's power supply voltage -
                //    mostly for debugging
                windDirectionDevice.doADConvert(
                           OneWireContainer26.CHANNEL_VDD, state);
                double Vdd = windDirectionDevice.getADVoltage(
                           OneWireContainer26.CHANNEL_VDD, state);

                // compensate for supply variations
                Vad = Vad * WIND_DIR_ADJUST;

                // convert the A to D voltage to a wind direction
                windDir = lookupWindDir(Vad);

                if (this.isDebugFlag())
                {
                  ErrorLog.logError("Wind Dir A to D = " + Vad +
                    " Wind Dir Supply = " + Vdd +
                    " Wind Direction  = " + windDir);
                }

                if (windDir == WIND_DIRECTION_ERROR)
                {
                  if (isDebugFlag())
                  {
                    ErrorLog.logError("Wind dir: ERROR - Vad: " +
                       Vad + " Vdd; " + Vdd);
                  }

                  retryCount++;
                }
                else
                {
                  bOK = true;  
                  if (isDebugFlag())
                  {
                    ErrorLog.logError("Wind dir: - Vad: " +
                      Vad + " Vdd; " + Vdd);
                  }
                }

            this.getPath().close();
        }
        catch (OneWireException e)
        {
            if (this.isDebugFlag())
            {
            ErrorLog.logError("Error Reading Wind Direction: " + e);
            }
            retryCount++;
        }
        }
        if (retryCount >= maxRetryCount)
        {
        ErrorLog.logError("Wind Direction: Retry count exceeded");
        }
    }

    return windDir;
    }

    // convert wind direction A to D results to direction value
    private int lookupWindDir(double volts) // ADS
    {
      int direction = WIND_DIRECTION_ERROR;

      for (int i = 0; i < 16; i++)
      {
      if((volts <= lookupTable[i] + 0.04) &&
                   (volts >= lookupTable[i] - 0.04))
      {
          direction = i;
          break;
      }
      }

      return direction;

    }

    static final double lookupTable[] =
    {
    2.69, // N
    6.52, // NNE 1
    5.99, // NE  2
    9.38, // ENE 3
    9.30, // E   4
    9.53, // ESE 5
    8.51, // SE  6
    9.01, // SSE 7
    7.60, // S   8
    7.98, // SSW 9
    4.31, // SW  10
    4.62, // WSW 11
    0.92, // W   12
    2.23, // WNW 13
    1.57, // NW  14
    3.57, // NNW 15
    };

}

Here’s the wind speed code:

import com.dalsemi.onewire.OneWireException;
import com.dalsemi.onewire.adapter.DSPortAdapter;
import com.dalsemi.onewire.container.OneWireContainer1D;

public class ADSWindSpeedSensor
{
    private OneWireContainer1D windSpeedDevice = null;
    private static final int maxRetryCount = 3;
    private long lastCount = 0;
    private long lastTicks = 0;

    /**
     *
     * Constructor that will instantiate the wind speed sensor
     * of the specified
     * ID on the specified adapter.
     *
     * @param adapter
     *            The 1-Wire adapter this sensor is connected to.
     * @param config
     *            The SensorConfiguration that specifies all the
     *            parameters for this sensor.
     *
     */
    public ADSWindSpeedSensor(DSPortAdapter adapter,
            SensorConfiguration config)
    {
    super(adapter, config);

    windSpeedDevice = new OneWireContainer1D(adapter, config.getID());
    }

    /**
     * Method to read the wind speed sensor and return the speed in 
     * miles per hour.
     *
     * @return The wind speed in miles per hour. If there was not a 
     *         valid reading, return Float.MIN_VALUE.
     *
     */
    public float getWindSpeed()
    {
    float windSpeed = Float.MIN_VALUE;
    boolean bOK = false;
    int retryCount = 0;

    if (windSpeedDevice != null && isEnabled())
    {
        while (!bOK && retryCount < maxRetryCount)
        {
        try
        {
            this.getPath().open();

            if (this.isDebugFlag())
            {
            ErrorLog.logError("ADS Wind Speed: Device = " +
                      windSpeedDevice.getName() +
                      " ID = " + windSpeedDevice.getAddressAsString());
            }

            // read wind counter & system time
            long currentCount = windSpeedDevice.readCounter(15);
            long currentTicks = System.currentTimeMillis();

            if (lastTicks != 0)
            {
            // calculate the wind speed in MPH based on
            //  the revolutions per second
            windSpeed = (float) ((1.25 *(currentCount-lastCount)) /
                 ((currentTicks-lastTicks) / 1000f));
            }

            if (this.isDebugFlag())
            {
            ErrorLog.logError("Count = " + (currentCount-lastCount)
                    + " during " +
                (currentTicks-lastTicks) + "ms calcs to " + windSpeed);
            }

            // remember count & time
            lastCount = currentCount;
            lastTicks = currentTicks;
            bOK = true;

            this.getPath().close();
        }
        catch (OneWireException e)
        {
            if (this.isDebugFlag())
            {
            ErrorLog.logError("Error Reading Wind Speed: " + e);
            }
            retryCount++;
        }

        }

        if (retryCount >= maxRetryCount)
        {
        ErrorLog.logError("Wind Speed: Retry count exceeded");
        }
    }

    return windSpeed;
    }

}

Time for some more testing, and create a way to attach this anemometer to the rest of the weather station.  I also received a new photocell and a new lightning sensor to play with.  I need to replace my humidity sensor chip and build the new radiation shield.  Lot’s more fun to come.