Labels

Showing posts with label Sensors. Show all posts
Showing posts with label Sensors. Show all posts

Wednesday, June 8, 2022

WWD #01 - Sources for Web Weather Display

 I was trying to pick through my mind and my notes to come up with a list of sources for the Web Weather Display.  I wanted to concentrate on free sources; this effectively eliminates any access to Weather Underground.  This is the list that I came up with:

  • OpenWeatherMap - using a key from OpenWeatherMap you can download current predicted values for your given lat and long (https://openweathermap.org/api/one-call-api)
  • NWS - the National Weather Service has a web services connection that allows you to gather information on current conditions in your area (https://www.weather.gov/documentation/services-web-api) as well as warnings and alerts for the area
  • NOAA - NOAA has a web services connection that can gather satellite images and loop movies for the WWD (https://www.ncdc.noaa.gov/cdo-web/webservices/v2https://www.ncdc.noaa.gov/cdo-web/token) along with other weather related information
  • DarkSky - DarkSky is another source similar to OpenWeatherMap that provides world wide data; however it will be eclipsed and merged into an Apple product in 2023, so it doesn’t appear to be a good place to get information at this time
  • Accuweather - Accuweather is another source of weather information; this one allows a limited set of 50 hits/day for free (https://developer.accuweather.com/apis)
  • WeeWx - WeeWx is a general purpose posting and data gathering platform.  It is extensible with a number of different plug-ins and thus could be merged into the WWD as a data source/sink via MQTT interactions without transferring information to either CWOP or Weather Underground.  It does provide a good general purpose interface to most existing weather stations out there as well as RTL-SDR interfaces and other sensors (http://www.weewx.com/).
  • Air Quality API - TBD
  • Hurricane Models API - TBD
  • Weather Models API - TBD

Monday, September 9, 2013

Finally got around to installing the RPi Camera

This weekend was pretty much a blur. I did manage to plug in one of the two cameras that I had bought for the RPi back a couple of months. I just followed the instructions that came with the cameras (remove tape from header next to the Ethernet port, pull up on both sides of the locking mechanism gently, insert the camera flexible cable so that the shiny part of the cable faces away from the Ethernet port, after ensuring the cable is all the way in, push down on the header lock). I then tried out the instructions found at http://www.raspberrypi.org/camera to test. Picture of the camera is below:





Monday, April 22, 2013

Got a new sensor in! A Sensor Stick.

I received a new sensor in the mail last week from China.  I ordered it online from Amazon at 10DOF (L3G4200D+ADXL345+HMC5883L+BMP085) Sensor Stick Breakout- for MWC/KK/ACM. As you can see from this photo, it is pretty small.  I wanted to get a gyro and accelerometer to use for an experiment that I was thinking about for the future and saw this online.


The description on the Amazon website says:

"This 10DOF sensor breakout is a very small sensor board with 10 degrees of freedom. It includes the ADXL345 accelerometer, HMC5883L magnetometer, BMP085,and the L3G4200D gyro. This break has a simple I2C interface and a mounting hole for fixing to your multi-project. just have a fund with it.
  • The ADXL345 is a small, thin, ultralow power, 3-axis accelerometer with high resolution (13-bit) measurement at up to ±16 g. Digital output data is formatted as 16 bit twos complement and is accessible through either a SPI (3- or 4-wire) or I2C digital interface. The ADXL345 is well suited for mobile device applications. It measures the static acceleration of gravity in tilt-sensing applications, as well as dynamic acceleration resulting from motion or shock.
  • The Honeywell HMC5883L is a surface-mount, multi-chip module designed for low-field magnetic sensing with a digital interface for applications such as low-cost compassing and magnetometry. The HMC5883L includes our state-of-the-art, high-resolution HMC118X series magneto-resistive sensors plus an ASIC containing amplification, automatic degaussing strap drivers, offset cancellation, and a 12-bit ADC that enables 1° to 2° compass heading accuracy.
  • The BMP085 is a high-precision, ultra-low power barometric pressure sensor for use in advanced mobile applications. It offers superior performance with an absolute accuracy of down to 0.03 hPa and using very low power consumption down to 3 µA.The BMP085 comes in an ultra-thin, robust 8-pin ceramic lead-less chip carrier (LCC) package, designed to be connected directly to a micro-controller of a mobile device via the I²C bus.
  • The L3G4200D is a 3 axis gyroscope, providing you with very high resolution (16 bit) measurements at up to 2000 degrees per second (dps). The gyroscope measures how much the device is rotating around all three axis, the range is user selectable and so can be adjusted to suit your application."
Obviously, I should be able to have fun with this.  One item that I did note was that the BMP085 is capable of outputting temperature readings along with the Barometric Pressure.  The barometric pressure readings give you a sense of altitude.  The sensor stick is apparently for use in small RC plane or helo type applications.  I plan on using most of the sensors for on the ground operation.  The sensor will give me the ability to have a sensor to work out a balance bot.  Woot!

Saturday, April 13, 2013

Command Testing for Serial Interface to Arduino

Ok, I have started implementing and testing the serial interface to the Arduino.  So far, I have coded the following sequences:

(1) 1/1/pinNumber/analogRate - to write an analog rate to a specific pin
(2) 1/2/pinNumber/digitalState - to write a digital state to a specific pin
(3) 2/1/pinNumber - to read an analog value from a specific pin (via serial)
(4) 2/2/pinNumber - to read the digital state from a specific pin (via serial)
(5) 3/1/servoPin - to read the current pose of a servo from a specific pin (not active)
(6) 3/2/servoPin/servoPose - to write a pose to a servo on a specific pin (not active)
(7) 3/3/servoPin - to detach a servo on a specific pin (not active)
(8) 3/4/servoNumber - to read the pose on a specific servo channel on the maestro
(9) 3/5/servoNumber/servoPWM - to set the pwm pose on a specific servo channel on the maestro
(10) 4/1/lowSweepIR/highSweepIR/speedSweepIR -

At first I had some problems trying to get servos to react.  I noticed that the servos were not zeroing at the beginning of the loop.  It turns out that my connection to the mini-maestro was not working.  After re-seating the connection everything started working correctly.

First test was the 3/5/servoNumber/servoPWM - worked correctly on two different servos (0 - for the Ultrasonic distance sensor, 6 - for the IR distance sensor).  I added some instrumentation via the LCD Panel and was able to see what the command was being interpreted as.  Servos moved, although there was a delay (I do have a one second feed in there).

Second test was to get the 3/4/servoNumber to work - although I could get some return values, they were not what I was expecting.  Need to do a little more homework on return values from the maestro and how I am able to read that through a serial interface.  I am getting absolutely nothing back from the Mini-Maestro.  I am even using code that I know works with the device (according to websites that have the listings).

Update: Am I up against a hardware problem?  If so, what is the least expensive way of implementing what I want.  Should I go back to the SSC-32?  The resolution in the analog domain was not that great, however, I am no longer using the Maestro to read the values from the IR or Ultrasonic distance sensors.

Tuesday, April 2, 2013

Located a library to use with HC-SR04

I was doing a search this morning and happened upon the site at http://code.google.com/p/arduino-new-ping/.  This appears to be a library with the ability to filter the HC-SR04 ultrasonic sensor.  It also appears that the author had many of the same problems that I encountered with the sensor and dealt with it with multiple pings, distance sensing, etc.  I will need some time to digest what it is capable of doing but maybe this is a better bet for a more stable read from the sensor.

Friday, March 29, 2013

Distance sensor data gathering

So I was able to start gathering sensor data last night.  I wanted to start gathering information on the two distance sensors in order to be able to calibrate the system.  I have enough errors propagating around, I just wanted to understand a little more about the IR and Ultrasonic Distance Sensors themselves and how they behave and how well they measure distance.
In the picture below, you can see the IR distance sensor (GP2D12).  I was able to modify the Arduino code to give me values output on the LCD display.  My measurements were from the front of the sensor housing, that means that I will need to add the offset from the front of the sensor housing to the center of the servo rotation point to get an accurate reading on the measurements.



For the ultrasonic distance sensor (HC-SR04) the measurements will be the same.  I will measure from the front of the sensor housing to the target and will add the distance from the front of the sensor housing to the center of the servo rotation point.



Wires: now that I have everything hooked up on the Lexan plate, the wire jumble on the top of the Arduino breadboard is pretty much a mess.  I am thinking of getting a proto board and putting headers on it in order to not have the jumble on top.  You can see what I mean by the picture below.



When I took the values from the IR distance sensor, I was surprised to notice how much the value changed with each sample.  The measurements are as follows:

Distance Measure1 Measure2 Measure3
2 7.24 7.22 7.26
2.25 6.76 6.72 6.72
2.5 6.84 6.91 6.82
2.75 7.54 7.64 7.68
3 8.23 8.66 8.57
3.25 9.23 9.18 9.15
3.5 9.97 9.97 9.36
3.75 10.95 10.92 10.85
4 11.39 11.32 11.46
4.25 12.28 12.24 12.24
4.5 12.84 13.05 12.84
4.75 13.72 13.72 13.72
5 14.39 14.29 14.24
5.5 15.67 15.73 15.67
5.75 16.63 16.26 16.5
6 17.08 17.14 17.08
6.25 17.96 17.89 17.89
6.5 18.47 18.4 18.18
6.75 19.01 18.7 19.01
7 19.9 20.15 19.98
7.25 20.33 20.24 20.33
7.5 21.52 21.42 21.42
7.75 21.81 21.71 21.9
8 23.26 23.04 23.04
9 25.9 25.51 26.03
10 28.63 28.79 29.11
11 32.89 32.29 33.5
12 36.64 36.4 35.92
13 35.92 31.92 36.4
14 40.65 40.65 40.65


Even though I took three measurements at each distance, the values pretty much vary pretty wildly.  A simplified graph of these measurements are as follows:

Actually, I should probably try and swap the x and y axis.  The x axis is the distance and the y axis is the measured values.  True to the data sheet, values that approach around 2 inches from the front of the sensor will change up and values over about 12 inches seem to start varying wildly.  In between, from 2 to 12 inches, the values seem to be steady and are almost linear given the formula in the sampling routine.  The values that return from the Ultrasonic sensor seem to vary even more crazily (see video below).

What I am learning from this is that I might have to rethink how the robot will follow the wall with the sensor data that I am seeing.



Thursday, March 28, 2013

Distance Calibration and Angle of Same

Ok, here are the current issues:

1. I have two distance sensors on the Lexan plate.  One is a GP2D12 ir distance sensor that is supposed to measure some short range distances.  The other is a HC-SR04 ultrasonic distance sensor that measures somewhat larger distances.  Each of these distance sensors have non-linearity in the values they return.

2. Each of the distance sensors are mounted on servos on either side of the Lexan plate, meaning that the center of rotation is off center from the iRobot Create.

3. When the servos were mounted, I noticed that they were not completely perpendicular to the Lexan plate, nor is the Lexan plate oriented in a perpendicular manner when mounted to the iRobot Create.  That means that the angle of rotation needs to be adjusted.  In addition, the Lexan plate is somewhat offset from the center of the iRobot Create and may have a rotation effect.

4. There is an area on the plate where each of the distance sensors can rotate to and an area where they cannot, a sector of a circle if you will.  There will need to be adjustments to the sweep for each of the distance sensors so that the values they return will be acceptable.

5. Servos have issues in that there are discrete steps that they make rather than a continuous movement.  Also, there needs to be a correlation between the pwm value and the angle of rotation for the servos, which may be different in each servo.

The above issues make it difficult to relate the measured values with what is really out there.  This post is an attempt to define those issues and point to a solution.  The overall requirement is to have measurements be absolute to a specific point, in this case the centroid of the iRobot Create.  In order to do this I will have to deal with a number of coordinate systems.  To simplify everything, I am going to assume an XY plane (i.e., no Z axis involved here), however I will retain XYZ coordinates for purposes of being able to add them in later.  In this case translation is only in the XY plane, rotation is only about the Z axis, and the Z value is always 0.  Note that I will assume no scaling.  I will use matrix algebra to translate everything into iRobot Create coordinates (assuming that 0,0 is at the center of the Create).  So when I take a measurement of a point, it can be translated into the iRobot Create coordinates.  So to make it easier we have rotation around the Z axis at an angle psi with translation in the X (Tx) and Y (Ty).  Note that normally the translation in Z (Tz) would be zero.




Notice that if there is no rotation, i.e. psi is zero, then cos psi is 1.0 and sin psi is 0.0 which is just a standard identity matrix with the translation parameters imposed. Where to begin:

a. Assume center of Lexan plate is the Lexan plate origin.  The centroid of the plate should be an easy calculation, assume normal XY coordinates - measurements should be consistent (i.e., in inches).

b. Assume center of servo rotation is the servo origin.  Distance measurements from each distance sensor should be to the servo origin.  This simplifies the remaining transformations.

c. Servo -> Lexan coordinates: translate servo origin to Lexan center, rotate about Lexan center to compensate for Servo angle offset, scaling values should be equal to one (no scaling).  It should be easy to measure the servo origins in relation to the plate and figure out the translation values.  The servo angle offset may be more difficult, in the initial for simplification we can assume 0 degrees.

d. Lexan -> Create coordinates: translate Lexan origin to iRobot Create origin to compensate for plate offset, rotate about iRobot Create origin to compensate for plate rotation offset, scaling values should be equal to one (no scaling).

e. Create -> World coordinates: translate Create origin to World origin, rotate about World origin to get final World coordinates correct. No scaling, probably set the first matrix to an identity matrix for no effect.

Following the normal convention for such things, the final form of the equation is:


Fiddling with a full setup on the Arduino

I decided to go ahead and put together a complete setup of software in the Arduino.  I have been developing the interfaces to the servos, ir distance sensor, ultrasonic distance sensor, and LCD serial panel.  In the course of the changes, I decided to move the read of the ir distance sensor to the Arduino rather than read it through the Maestro.  I may end up changing my mind later.  So my setup in the IDE looks something like this:

// Pololu Mini-Maestro 18 Serial Servo Controller
// Power 9v Seperate power supply from Arduino
// GND to GND on the Arduino
// SSC RX pin to Arduino TX pin Pin04
// SSC TX pin to Arduino RX pin Pin03
// Channel 0 - Ultrasonic Distance Sensor Servo
// Channel 2 - Camera Pan Servo
// Channel 4 - Camera Tilt Servo
// Channel 6 - IR Distance Sensor Servo

// GP2D12 IR Distance Sensor
// Power 5v from the Arduino
// GND to GND on the Arduino
// GP2D12 Sensor analog Rx pin to Arduino Analog pin 0

// Parallax 2x16 Serial LCD Panel
// Power 5v from the Arduino
// GND to GND on the Arduino
// LCD Rx pin to Arduino TX pin Pin06

// HC-SR04 Ultrasonic Distance Sensor
// Power 5v from the Arduino
// GND to GND on the Arduino
// HC-SR04 Trig to Arduino TX pin Pin13
// HC-SR04 Echo to Arduino RX pin Pin12


This setup ends up forcing a number of pin definitions as so:

// Define constants
// Serial pins
const int tx_ToSSC=4; ///< Tx pin going to SSC
const int rx_ToSSC=3; ///< Rx pin coming from SSC
const int tx_ToLCD=6; ///< Tx pin going to LCD panel
const int rx_FrmLCD=5; ///< Rx pin coming from LCD panel(nc)
// Digital pins
const int digtx_ToUltraTrig=12; ///< Tx pin going to ultrasonic sensor trig
const int digrx_FrmUltraEcho=13; ///< Rx pin coming from ultrasonic sensor echo
// Channels on SSC
const int chan_ultraservo=0; ///< Channel 0 - Ultrasonic Distance Sensor Servo
const int chan_camerapanservo=2; ///< Channel 2 - Camera Pan Servo
const int chan_cameratiltservo=4; ///< Channel 4 - Camera Tilt Servo
const int chan_irdistservo=6; ///< Channel 6 - IR Distance Sensor Servo
// Analog pins
const int rx_irdistanalog=0; ///< IR Distance Sensor analog Rx



I have gleaned from several sources the code that I need to access each of these items.  First up, is my interfaces to the two serial connections needed for the SSC (Maestro) and the LCD panel:

// initalizing serial connections
SoftwareSerial SSC_Serial = SoftwareSerial(rx_ToSSC, tx_ToSSC);
SoftwareSerial LCD_Serial = SoftwareSerial(rx_FrmLCD, tx_ToLCD);


Next up, I have the procedure interface to the SSC that sets a servos pwm value:

// Send a Set servo pwm command to the Maestro.
// Target is in units of quarter microseconds
// so the normal range is 4000 to 8000.
void ssc_cmnd_pwm(unsigned char servo, unsigned int target)
{
    SSC_Serial.write(0xAA); //start byte
    SSC_Serial.write(0x0C); //device id
    SSC_Serial.write(0x04); //command number
    SSC_Serial.write(servo); //servo number
    SSC_Serial.write(target & 0x7F);
    SSC_Serial.write((target >> 7) & 0x7F);
}


Next, I have a few routines for writing information out to the LCD panel:

// display two strings on the LCD panel
void lcd_display_2_str(String myvalue1, String myvalue2) {
  delay(100);
  LCD_Serial.write(12); // Clear            
  LCD_Serial.print(myvalue1); // First line
  LCD_Serial.write(13); // Form Feed
  LCD_Serial.print(myvalue2); // Second line


// display string and int value on one line, string on second line on the LCD panel
void lcd_display_2_str_int(String myvalue1, int myvalue, String myvalue2) {
  delay(100);
  LCD_Serial.write(12); // Clear            
  LCD_Serial.print(myvalue1); // First line
  LCD_Serial.print(myvalue, DEC);
  LCD_Serial.write(13); // Form Feed
  LCD_Serial.print(myvalue2); // Second line


// display integer value on the LCD panel
void lcd_display_int_val(int myvalue) {
  delay(100);
  LCD_Serial.write(12);                 // Clear            
  LCD_Serial.print("val: ");
  LCD_Serial.print(myvalue, DEC);  // First line
  LCD_Serial.write(13);                 // Form feed


Next, I deal with the gp2d12 ir range detector (along with a test):

/*
 read_gp2d12_range
 Function that reads a value from GP2D12 infrared distance sensor and returns a value in centimeters.

 This sensor should be used with a refresh rate of 36ms or greater.

 BY: Javier Valencia 2008

 float read_gp2d12_range(byte pin)

 It can return -1 if something gone wrong.

 */

float read_gp2d12_range(byte pin) {
    int tmp;

    tmp = analogRead(pin);
    if (tmp < 3)
        return -1; // invalid value

    return (6787.0 /((float)tmp - 3.0)) - 4.0;
}

void test_irdistance()
{
  float myval;
  myval = read_gp2d12_range(rx_irdistanalog);
  Serial.print("ir val: ");
  Serial.println(myval);
//  LCD_Serial.write(12);                 // Clear            
//  LCD_Serial.print("ir val: ");
//  LCD_Serial.print(myval, DEC);         // First line
//  LCD_Serial.write(13);                 // Form feed
}


Next, I deal with the Ultrasonic distance sensor (HC-SR04):

/*
  HC-SR04 Ping distance sensor
  VCC to Arduino 5v, GND to Arduino GND
  Echo to Arduino pin 13, Trig to Arduino pin 12
  more info at: http://goo.gl/kJ8G1
  */

float grab_ultrasonic()
{
  int duration;
  float distance;
  digitalWrite(digtx_ToUltraTrig, LOW);
  delayMicroseconds(2);
  digitalWrite(digtx_ToUltraTrig, HIGH);
  delayMicroseconds(10);
  digitalWrite(digtx_ToUltraTrig, LOW);
  duration = pulseIn(digrx_FrmUltraEcho, HIGH);
  distance = (duration/2) / 29.1;

  return distance;
}

void test_ultrasonic()
{
  float mydist;
  mydist = grab_ultrasonic();
  if (mydist >= 200 || mydist <= 0){
    Serial.println("Ultra: Out of range");
//    LCD_Serial.write(12);                 // Clear            
//    LCD_Serial.print("Out of range");
//    LCD_Serial.write(13);                 // Form feed
  } else {
    Serial.print("Ultra: ");
    Serial.print(mydist);
    Serial.println(" cm");
//    LCD_Serial.write(12);                 // Clear            
//    LCD_Serial.print("Out of range");
//    LCD_Serial.print(mydist, DEC);
//    LCD_Serial.print(" cm");
//    LCD_Serial.write(13);                 // Form feed
  }
}


In order to utilize these, I have the following setups:

// run once, when the sketch starts
void setup()
{
  // setup pins for serial interface to SSC
  pinMode(rx_ToSSC, INPUT);
  digitalWrite(tx_ToSSC, HIGH);
  pinMode(tx_ToSSC, OUTPUT);
  // set SSC serial interface speed
  SSC_Serial.begin(9600);

  // setup pins for serial interface to LCD
  pinMode(rx_FrmLCD, INPUT);
  digitalWrite(tx_ToLCD, HIGH);
  pinMode(tx_ToLCD, OUTPUT);
  // set LCD serial interface speed
  LCD_Serial.begin(9600);
  // initial clear and backlight for LCD
  LCD_Serial.write(12); // Clear            
  LCD_Serial.write(17); // Turn backlight on
  delay(5);             // Required delay for response

  // set SSC servos to initial state
  ssc_cmnd_pwm(chan_ultraservo,6000);
  ssc_cmnd_pwm(chan_camerapanservo,6000);
  ssc_cmnd_pwm(chan_cameratiltservo,6000);
  ssc_cmnd_pwm(chan_irdistservo,6000);
 
  // set Ultrasonic Distance Sensor pins
  pinMode(digtx_ToUltraTrig, OUTPUT);
  pinMode(digrx_FrmUltraEcho, INPUT);
 
  // setup our serial monitor
  Serial.begin(9600);
 
  // wait for settling to happen
  delay(1000); 
}


Now that I have the initial software coded, I have time to try them out and start to build the interfaces between the Arduino and the sensors/servos.  Next up will be results of the testing, followed by dealing with the interface to the RPi.