arduino servo example analysis

futaba s3003 arduino servo example script
futaba s3003 arduino servo example script

I admit I know little about pulse width modulation, and have limited experience with robotics or servos. I’ve had a futaba s3003 servo in my toolbox for some time, and done nothing with it. On a lazy day when I had some down time, I decided to get it out and do some experimentation.

I’ve been doing some labor intensive projects at work lately, and while hard work is very rewarding, it takes a lot of physical and mental energy and crowds out innovation. Just out of boredom, I burned the most basic servo script example provided by the arduino IDE into a nano clone I recently bought, and analyzed it with pulseview to better understand pwm.

close up of PWM controlling a futaba s3003 servo
close up of PWM controlling a futaba s3003 servo

Above is a trace of the output of the default arduino ide servo script with me tuning a 10K pot. In this example script, the position of the servo corresponds to the position of the potentiometer. Just at a glance, you can see pulses bunched up at different intervals. What I empirically observed is that when the servo was at position 1, the pulse width was about 0.55ms in duration at the standard 50Hz required by the servo. This pulse was constant, and the servo was stationary. If the pulse width changes at all, it changes position proportionally.

The futaba s3003 has 180 degrees of rotation. At position 3 (180 degrees) the constant pulse width is about 2.4msec. as you can see in the graphic below:

futaba s3003 servo at 180 degrees of rotation

This simple analysis has demystified pwm somewhat for me. Next, I hope to experiment with some pwm on the raspberry pi using perl.

rssi vs. relative humidity

receive signal strength indication vs. relative humidity data logger
receive signal strength indication vs. relative humidity data logger

I finally got around to deploying my rssi / temperature / relative humidity data logger and recorded nearly 6,000 samples of each metric over a five day period. This radio system operates in the ISM band, and is susceptible to propagation issues due to atmospheric conditions, especially humidity. The logic board provides a terminal that outputs a DC voltage that represents the rssi in dBm. My data logger uses a raspberry pi zero w, and reads the rssi voltage with an MCP3004 analog to digital converter using a bit-banged driver I wrote in perl. Each reading is timestamped using time derived from a DS3231 i2c real-time clock chip.

I use a HTU21 temperature / relative humidity sensor break out board from adafruit. This chip is MUCH MORE STABLE & RELIABLE than the DHT22 I was originally using.

temperature vs. relative humidity data capture
temperature vs. relative humidity data capture

For starters, here is the temperature in fahrenheit (red) vs. the relative humidity (green). Predictably, when the temperature rises, the relative humidity goes down and vice versa.

rssi level vs. relative humidity at 900MHz
rssi level vs. relative humidity at 900MHz

Now here is the relative humidity vs. the rssi. This radio is about 20 miles away from the transmitter over flat terrain with an output of 37dBm (5 watts), and has an average rssi of about -90dBm. You can see from the above graph that at about sample 4,000 when the relative humidity takes a noticeable dip that the rssi has a corresponding, albeit small, increase: precisely what we would expect to see.

Nothing surprising here. It just proves the effectiveness of my data logger device. It would be useful in situations where an RF path is going up and down due to atmospheric conditions or other obstructions, and real-time data would be useful in diagnosing problems and coming up with solutions like a higher gain antenna or increasing height.

ssh to a raspberry pi zero over usb

connecting to a rapsberry pi zero via usb
connecting to a raspsberry pi zero via usb

I am working on a data logging project based on the raspberry pi zero.  NOT a pi zero w,  just the pi zero.  Adding software packages to the pi zero is a little more difficult, because it has no wifi or ethernet connection.  I have been taking the sd card out ant putting it in a pi 3b+ to get packages that I need then putting it back in the pi zero.  I have tried and failed to use minicom and zmodem to transfer deb files over UART.

I found this great tutorial that explains how to ssh into a pi via the usb port on the pi.  I did everything it said and was still not able to connect to the pi.  I did an ifconfig on the pi, and saw that it had a APIPA on it’s usb network interface like so:

usb network interface on pi zero
usb network interface on pi zero

I had a usb network interface appear on my laptop, but no ipv4 address:

usb network interface on ubuntu machine
usb network interface on ubuntu machine

I finally got it to work by issuing an ifconfig command to my laptop’s usb interface and assigning an IP address in the same class B subnet :

ifconfig on usb network interface APIPA
ifconfig on usb network interface APIPA

Another benefit to a standard pi zero having ip connectivity via usb is that you can use piscope for troubleshooting.  Here is piscope examining i2c frames polling an HTU21D relative humidity sensor:

examining an HTU21D with piscope on a pi zero with usb network interface
examining an HTU21D with piscope on a pi zero with usb network interface

dht22 indoor use only

In my empirical observations experimenting with a dht22 temperature / humidity sensor,  I have come to the conclusion that they are most definitely for INDOOR USE ONLY!  Any time I placed one outside, they quickly max out at 99.9% humidity,  and don’t recover until I dry them out, and place them indoors.  I have ordered a HTU21D-F sensor to replace the dht22 in my rf propagation / humidity experiment.

The dht22 does work pretty well indoors.  I took over 14K samples over a 30 hr period and got clean results.

dht22 sensor temperature and humidity graph
dht22 sensor temperature and humidity graph

The temperature is in red and the humidity in green.  For most of my data logging projects using a pi, I sore the results in CSV format.  I used perl’s CSV database functions to query results and create graphs.  This is the sql query I use on the to csv tables to get the above graph:


select data.index, data.temp, temp_humidity.humidity from data outer join temp_humidity on data.index = temp_humidity.index

piscope is totally AWESOME with perl!

this is a screenshot of piscope running on my laptop analyzing the gpio lines of a raspberry pi over IP that is running my 24-port battery load test analyzer
this is a screenshot of piscope running on my laptop analyzing the gpio lines of a raspberry pi over IP that is running my 24-port battery load test analyzer program

I would assume many makers are familiar with using a logic analyzer in conjunction with sigrok + pulseview.  I love these resources.  They allow you to analyze precisely what is happening on your digital IO pins on whatever microcontroller you are using whether it be arduino, raspberry pi, etc.  They can also analyze signals at the protocol level such as i2c and are so inexpensive every maker should be equipped with these tools.

Pulseview SPI
Pulseview SPI scan

I do not like to reinvent the wheel in most cases.  I wanted to use some dht22 temp / humidity sensors on an RF signal strength project I am still working on.  As I have mentioned in earlier posts, I chose to use the RPi::PIGPIO::Device::DHT22 module on cpan to read my sensor.  This required the pigpiod daemon to be running on the raspberry pi.  I am very impressed with PIGPIO.  It allows you to very easily read / write to a raspberry pi ‘s GPIO lines over TCP/IP.  Just think of the possibilities.

The author of PIGPIO also offers an incredible logic analyzer for the raspberry pi called piscope.  I may never use a standard logic analyzer on a pi ever again.  You can invoke piscope on any linux computer once you have installed it to analyze the gpio on a remote pi.

invoking piscope to monitor the gpio lines on a raspberry pi
invoking piscope to monitor the gpio lines on a raspberry pi

After this, launch piscope:

run piscope logic analyzer
run piscope logic analyzer

I am just beginning to experiment with piscope, but so far it is very user friendly.  This is a trace of the SDA and SCL lines on the pi reading an MCP9808 temperature sensor.

piscope logic analyzer zoomed in on the i2c lines of an MCP9808 temperature sensor
piscope logic analyzer zoomed in on the i2c lines of an MCP9808 temperature sensor

This trace was taken over the net.  I didn’t have to get out my logic analyzer and connect any test leads.  Here is a trace of a poll and response from a dht22 sensor connected to gpio 24.

piscope logic analyzer reading a dht22 via perl
piscope logic analyzer reading a dht22 via perl

You can see it go low, then the sensor sends its reading, and goes high again.  pigpiod is definitely a resource hog, but that is hardly a consideration for my uses of the pi in my projects.  I will definitely be incorporating piscope into my future projects.

piscope by default uses port 8888 on the pi you are monitoring.  Out of curiosity,  I scanned the incoming frames with tcpdump.

analyzing piscope frames on port 8888 using tcpdump
analyzing piscope frames on port 8888 using tcpdump

It sends a lot of traffic over the network.

piscope network traffic on linux mint's system monitor
piscope network traffic on linux mint’s system monitor

Here is a video of me launching piscope, and live traffic from a pi 3B+.

arduino nano bike speedometer

arduino nano bike speedometer and odometer
arduino nano bike speedometer and odometer

I tricked out my dad bike with an arduino nano based speedometer, odometer, clock, and temperature sensor.

A DS3231 RTC keeps the time and temperature.  I implemented a attachInterrupt() function to keep track of tire rotation via a reed switch.

reed switch for a bike speedometer / odomoeter using an arduino nano
reed switch for a bike speedometer / odomoeter using an arduino nano

This way, I do not have to programmatically monitor  the reed switch;  a routine is executed (in this case that calculates the distance traveled) each time the state of the digital pin the switch is connected to changes.

 //bike speedometer
#include 
#include "RTClib.h"
RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 10;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

float start, finished;
float elapsed, time;
//float circMetric=2.164; // wheel circumference relative to sensor position (in meters)
float circMetric=1; // wheel circumference relative to sensor position (in meters)
float circImperial; // using 1 kilometer = 0.621371192 miles
float speedk, speedm;    // holds calculated speed vales in metric and imperial
float miles_traveled = 0;
float feet_traveled = 0;
char miles[100];

void setup () {
  attachInterrupt(0, speedCalc, CHANGE); //digital pin 2
  start=millis();
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("cr3d0");
  lcd.setCursor(0,1);
  lcd.print("BIKE SPEEDOMETER!");
  delay(4500); 
  lcd.clear();
  Serial.begin(9600);
  circImperial=circMetric*.62137; // convert metric to imperial for MPH calculations

  //rtc stuff
  int temp = 0;

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }//end if

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }//end if rtc lost power
  
}//end setup

void speedCalc()
{
  elapsed=millis()-start;
  start=millis();
  speedk=((3600*circMetric)/elapsed) * 0.12; // km/h
  speedm=((3600*circImperial)/elapsed) * 0.12; // Miles per hour
  feet_traveled += 1.1; 
  miles_traveled = feet_traveled / 5280; 
  //sprintf(miles, "%.2f", miles_traveled);
  
}

void loop()
{
  DateTime now = rtc.now();  
  int temp = 0;

  lcd.clear();
  lcd.setCursor(0,0);
  //lcd.print(int(speedk));
  //lcd.print(" km/h ");
  lcd.print(int(speedm));
  lcd.print(" MPH   ");
  lcd.print(miles_traveled);
  lcd.print(" mi");;
  //lcd.setCursor(0,1);
  //lcd.print(int(elapsed));
  //lcd.print(" ms/rev      ");
  lcd.setCursor(0,1);
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
  lcd.print(' ');
  temp = rtc.getTemperature() * 9/5 + 32;
  lcd.print(temp);
  lcd.print('F');
  delay(1000); // adjust for personal preference to minimise flicker
}

 

arduino bike speedometer
arduino bike speedometer

homemade bluetooth work speaker that kicks

home made 25W stereo bluetooth speaker project
home made 25W stereo bluetooth speaker project

I have a huge project going on at work right now, and loud music is absolutely essential.  I ordered some Boss CH3220 140W speakers and used a 25W bluetooth audio amplifier board and whipped up in one evening a killer work speaker that kicks hard.

It is working great as is, but I am totally not done.  I am going to add a raspberry pi to play my saved mp3’s and roll some of my own features.

25W bluetooth audio amplifier board
25W bluetooth audio amplifier board

I am very impressed with the quality of the sound and how easy it was to pair with this board.  I tested the speakers with ‘dont tread on me’ by metallica.  The frequency response of these 3.5″ speakers is surprisingly very good.

data logging rssi on a GE MDS9710 with perl, dht22, and raspberry pi

pi zero w data logging temperature, rssi, and humidity
pi zero w data logging temperature, rssi, and humidity

I work on 900MHz point to multi-point data radio systems.  Humidity can greatly affect the propagation of rf waves at this frequency.  I wanted to do some data logging and analysis of how moisture in the air affected the received signal strength indication over time.

The GE MDS 9710 P70 radio system has an analog voltage test point that corresponds to the rssi on it’s interface board.  I used a DHT22 to measure the temperature and humidity,  an MCP3004  10-bit analog to digital converter to read the rssi voltage, and a pi zero W for the brains.

arduino nano every and DHT22. Readings displayed on 16X2 LCD
arduino nano every and DHT22. Readings displayed on 16X2 LCD

I originally implemented this project with an arduino nano every.   It worked great.  I was going to log the data by connecting the nano every to a pi zero via UART while a screen session was running on the pi with the screen output (STDOUT) saved to a file .  This method would require a logic level converter which I did not have on hand at the time, so I decided to implement the whole project on my pi zero.

It is much easier to use a DHT22 sensor with arduino using adafruit’s unified sensor library.

adafruit unified sensor library for DHT22
adafruit unified sensor library for DHT22

Here is the source:

 
// REQUIRES the following Arduino libraries:
// - DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
// - Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor

#include "DHT.h"
#include 
#define DHTPIN 2     // Digital pin connected to the DHT sensor

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

DHT dht(DHTPIN, DHTTYPE);

const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//number of samples
int sn = 0;

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("MDS RSSI Data   Logger");
  delay(2000);
  dht.begin();
}

void loop() {
  // Wait a few seconds between measurements.
  delay(2000);

  //increment sample number
  sn++;

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    Serial1.println(F("Failed to read from DHT sensor!"));
    return;
  }

  //read rssi voltage
  int bv = analogRead(A0);
  float v = (5 * bv) / 1023.0;
  float rssi = v - 1.5;
  rssi = (rssi/0.8) * 20 - 120; 
  
  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);

  //print to console
  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hif);
  Serial.println(F("°F"));

  //print to pi
  Serial1.print("Humidity: ");
  Serial1.print(h);
  Serial1.print(F(" Temp: "));
  Serial1.print(f);
  Serial1.print("F RSSI: ");
  Serial1.print(rssi);
  Serial1.print("dBm");
  Serial1.print("\n");

  lcd.clear();
  lcd.print("Humidity:");
  lcd.print(h);
  lcd.print("%");
  lcd.setCursor(0,1);
  lcd.print(f);
  lcd.print("F ");
  //lcd.print(v);
  //lcd.print("V");
  lcd.print(rssi);
  lcd.print("dBm");
}

To use perl to interface with the DHT22 on my pi required the RPi::PIGPIO::Device::DHT22 module on cpan.  Before I could use this,  I needed to install PIGPIO and run it as sudo before executing my script.  PIGPIO is a VERY interesting library for controlling a pi’s gpio’s locally or remotely via socket, and I will hopefully find the time to explore more possibilities in the near future.  It is, however, somewhat of a resource hog.

pigpiod daemon cpu resources on a raspberry pi
pigpiod daemon cpu resources on a raspberry pi

Once all the modules are loaded on the pi and the PIGPIO daemon is fired up,  I just had to translate the ardino C code into perl.

 
#!/usr/bin/perl 
use strict;
require "/home/pi/gpio/MCP3004.pl";
use RPi::PIGPIO;
use RPi::PIGPIO::Device::DHT22;

=pod
loggs the temperature, humidity, and rssi of a
control point radio using a DHT22.  requires
PIGPIO daemon to be started first.  from home dir, 
cd/PIGPIO.  then, sudo pigpiod.  cd back into
gpio dir, and sudo perl CTC_datalogger.pl.  
=cut

my $pi = RPi::PIGPIO->connect('127.0.0.1');
my $dht22 = RPi::PIGPIO::Device::DHT22->new($pi,23);

#ADC channel
my @ch0 = (1,1,0,0,0);

#init ADC
init3004(3,4,5,6);

#open log file
open RD, ">", "ctc_data.log" or die $!;
#print table description
print RD "index,epoch,date,humidity,temperature,voltage,rssi\n";

my $i = 0;
for(;;){
	#formatted date string 
	my $time_str = `date`;
	print "$i\n";
	print $time_str;
	chomp($time_str);

	$dht22->trigger();
	my $deg_f = ($dht22->temperature * (9/5)) + 32;
	#$deg_f = sprintf("%.1f", $deg_f);
	$deg_f = int($deg_f);

	print "Temp: $deg_f \n";
	my $humidity = $dht22->humidity;
	$humidity = sprintf("%.1f", $humidity);
	print "Humidity: ".$dht22->humidity."%\n";
	int($deg_f);

	#take 5 samples from ADC and avg
	my $v_avg = 0;
	my $v_accum = 0;
	for(my $s=0;$s<5;$s++){
		my ($reading, $binval, $voltage ) = read3004(\@ch0, 50, 4.966);
		#print "binval: $binval\tvoltage: $voltage vdc\n";
		#print RD "$s\n$voltage\n";
		usleep(1000);

		$v_accum += $voltage; 
	}#end for
	$v_avg = $v_accum / 5;
	$v_avg = sprintf("%.2f", $v_avg);
	#print "avg: $v_avg\n";
	
	#calculate RSSI
	my $rssi = 0;
	$rssi = $v_avg - 1.5;
	$rssi = ($rssi / 0.8) * 20;
	$rssi -= 120;
	
	#format rssi
	$rssi = sprintf("%.2f", $rssi);
	print "rssi: $rssi dBm \n";
	print "-----------------------------------\n";

	#print to LCD
	`./lcd "Humidity: $humidity%     $deg_f F $rssi dBm"`;

	#print to log file
	my $log_str = '';
	my $uts = time;
	my $hr_time = localtime();
	$log_str = "$i,$uts,$hr_time,$humidity,$deg_f,$v_avg,$rssi\n";	
	select((select(RD), $|=1)[0]);
	print RD $log_str;

	sleep(2);
	
	$i++;
}#end for

close RD;

So far, it’s working great on the test bench.

pi zero rssi humidity data logger
pi zero rssi humidity data logger

Forgot to mention.  I used a DS3231 real time clock to keep time on the pi.  It works great and was easy to set up using this tutorial.

DS3231 RTC on pi zero
DS3231 RTC on pi zero

I will be deploying the data logger in the field this week and will post the results.  My bench test results are as follows.  Here is my humidity graph after nearly 9K samples.

dht22 humidity readings with pi zero w
dht22 humidity readings with pi zero w

And here is the rssi over the same dataset.  You can definitely see a higher rssi when the humidity is lower as expected.

rssi readings using raspberry pi
rssi readings using raspberry pi

building a telecom Transmission Impairment Measuring Set (TIMS) with arduino nano III

Telecom frequency generator and counter using arduino nano
Telecom frequency generator and counter using arduino nano

I have a working hand-held arduino based telecom test set made out of a plastic capacitor kit case.  It generates audio frequency tones from 0-3000 Hz.  The tone() function produces  audio frequencies at about -9.5dBm from what I have observed.  That level is very useful to my for my intended purposes.  I also need it to generate tones at a level of -16dBm.  To achieve this,  I put a selector switch to attenuate the level to -16dBm by putting the output of the tone() pin in series with 30K Ohms of resistance.

It measures the frequencies that it generates in TX mode, but also measures frequencies from other devices from it’s RX port.   The RX port must have a level of -3dBm or greater to work at this time.  I will be experimenting with an amplifier stage to measure weaker signals.

Arduino telecom frequency counter and generator
Arduino telecom frequency counter and generator

Schematic of telecom test set using arduino nano
Schematic of telecom test set using arduino nano

building a telecom Transmission Impairment Measuring Set (TIMS) with arduino nano II

arduino nano frequency counter
arduino nano frequency counter

I have considered several design possibilities for myTIMS project.  I was going to use the TimerFreeTone library because of the timer conflict between tone() and the FreqCount library, and have the user type in the desired frequency using a keypad.  I do not have enough GPIO on my nano for this as I need 6 pins for my LCD and seven for my 4-column 3-row keypad.  (I know I could get an i2c display, but I’m using what I have laying around!)

Anyway, the two nano approach is acutally looking better.  I am using one nano to generate the desired frequency when the TIMS is in transmit / generate mode.  I am using a 10-K potentiometer to tune to the desired frequency and basically copied and pasted the tonePitchFollower example sketch with a few modifications.  The other nano does the frequency counting and drives the LCD.  As you can see above, the nano frequency counter is only off by 1 Hz from a professional TIMS.

Here is the frequency counter sketch ->

     
     1	#include \<FreqCount.h\>
     2	#include \<LiquidCrystal.h\>
       
     3	const int rs = 12, en = 11, d4 = 10, d5 = 4, d6 = 3, d7 = 2;
     4	LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
       
       
     5	void setup() {
     6	  lcd.begin(16, 2);
     7	  lcd.print("Freq:");
     8	  FreqCount.begin(1000);
     9	}
       
    10	void loop() {
    11	  if (FreqCount.available()) {
    12	    unsigned long count = FreqCount.read();
    13	    lcd.setCursor(0, 1);
    14	    lcd.print(count);
    15	    lcd.print(" Hz       ");
    16	  }
    17	}