Showing posts with label Uno. Show all posts
Showing posts with label Uno. Show all posts

Sunday, September 13, 2015

Arduino and Servos

This little project has been lying around waiting to be done for far to long, so I have resurrected it on a rainy Sunday and hope to make something useful out of it.

I have this little AZ/EL camera mount pair of servos that are quite stout.  They have external feedback potentiometers for the servo position, so even though they are geared down, they can be accurately positioned.


Coupling these up to an Arduino UNO is trivial.  I need one signal pin, power and ground.  Do not try to power servos from the USB power on the Arduino, use an external power supply.

The first task at hand was to decide on the range of pulse widths that would be allowed for the servo.  The defaults are 544 us to 2400 us.  The APIs decide that if you set a pulse width less than the minimum, then it must be an angle in degrees 0-359.  I didn't take the time to sort this out.  Instead, I decided arbitrarily that angle zero is 500 us. and everything is counterclockwise from there.

I placed a mark on the Azimuth gear right at the servo gear and through experimentation determined that a change of 768 microseconds would rotate the gear 360 degrees.



From there, it was simple to create a function that would convert an angle in degrees to the required microseconds pulse width to position the servo as desired.

// For the azimuth servo, angle is mapped 0-360 degrees to 500-128 us
int deg2usAZ(int angle)
{
  return map(angle, 0, 360, 500, 1268);

}

Now in the case of the elevation servo, we have some limitations to the range of motion due to the physical characteristics of the assembly.  I decided first to figure out where level was and call this zero degrees of elevation.



Next I determined the setting for negative 45 degrees of elevation (pointing down).



And finally, I determined the setting for pointing straight up.  Now it was trivial to create a function to map degrees to these settings.

// For elevation servo, angle is mapped from -45-90 to 1112 to 2220 us
int deg2usEL(int angle)
{
  return map(angle, -45, 90, 1112, 2220);

}

Now with the addition of a button, I have a simple test application that will postion to zero degrees azimuth and elevation when started and then move to 90 degrees elevation and 45 degrees of azimuth when the button is pressed..

// Servo test code

#include <Servo.h>

int button1 = 4; //button pin, connect to ground to move servo
int press1 = 0;

Servo servoEL;
Servo servoAZ;

void setup()
{
  pinMode(button1, INPUT);
  servoEL.attach(7, 500, 2400);
  servoAZ.attach(9, 500, 2400); 

  servoEL.writeMicroseconds(deg2usEL(0));
  servoAZ.writeMicroseconds(deg2usAZ(0));

  digitalWrite(4, HIGH);
}

// For the azimuth servo, angle is mapped 0-360 degrees to 500-128 us
int deg2usAZ(int angle)
{
  return map(angle, 0, 360, 500, 1268);
}

// For elevation servo, angle is mapped from -45-90 to 1112 to 2220 us
int deg2usEL(int angle)
{
  return map(angle, -45, 90, 1112, 2220);
}

void loop()
{
  press1 = digitalRead(button1);
  if (press1 == LOW)
  {
    servoEL.writeMicroseconds(deg2usEL(90));
    servoAZ.writeMicroseconds(deg2usAZ(45));
  }
  else 
  {
    servoEL.writeMicroseconds(deg2usEL(0));
    servoAZ.writeMicroseconds(deg2usAZ(0));
  }

}

So, next I obtained the Arduino port of Plan13 which is a port of some very old basic code for determining a satellite location given the latitude/longitude/elevation of an observer, the Keplerian Elements for the satellite of interest and the date/time of interest. Keplerian Elements (or just Keps), named after Johann Kepler [1571-1630] are a set of seven numbers called satellite orbital elements that define an ellipse oriented about the earth and place the satellite on the ellipse at a particular time.

I have the Arduino port of Plan13 up and running and calculating azimuth and elevation values.  The precision is really insufficient on the Arduino to have very accurate calculations due to the fact that double precision floating point is required, but the Arduino defines double precision as a single precision value.  So the calculations do not have the precision they might otherwise have, but I find it is quite sufficient for simple experiments like this.

The remaining work is to provide a little more glue logic to have what amounts to a desktop pointer to the satellite as it passes overhead.

More to come.
.

Monday, January 19, 2015

Arduino ADC conversion rate

I know a lot of postings have been written about analogue to digital conversion rates in the 8 bit Arduino processors.  I decided to do a little poking around and performance timing to see for myself how well these little processors perform.  I will compare the performance of the 8 bit ATMega328 and ATMega2560 processors with the 32 bit Arduino Due processor.

The ADC clock is 16 MHz divided by a prescale factor.  The default setting is found in wiring.c:

        // set a2d prescale factor to 128
        // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
        // XXX: this will not work properly for other clock speeds, and
        // this code should use F_CPU to determine the prescale factor.
        sbi(ADCSRA, ADPS2);
        sbi(ADCSRA, ADPS1);
        sbi(ADCSRA, ADPS0);

        // enable a2d conversions
        sbi(ADCSRA, ADEN);

Using the default setting of 128 for the prescale factor gives a conversion clock of 125 kHz.  Since ADC conversion requires 13 ADC clocks the effective sample rate at best is approximately 125 kHz / 13 = 9.615 kHz.

Using a prescale of 16 would give an ADC clock of 1 MHz and a sample rate of 76.923 kHz.  Increasing the ADC clock can affect ADC accuracy however.  ATMel recommends that the maximum ADC clock frequency is limited by the internal DAC in the conversion circuitry and should not exceed 200 kHz.  However frequencies up to 1 MHz do not reduce the ADC resolution significantly.  Operation above 1 Mhz has not been characterized however.

So to do a quick test of the impact on performance I did a quick an dirty script to measure the time required to do 1000 analogRead operations before and after speeding up the ADC clock and see how much performance gain there is.

// useful defines for setting and clearing register bits
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

void setup() {
 int start;

 Serial.begin(115200) ;
 Serial.println("ADCTest at default 9.6 kHz sample rate") ;
 start = millis() ;
 for (int i = 0 ; i < 1000 ; i++)
   analogRead(0) ;
 Serial.print(millis() - start) ;
 Serial.println(" ms (1000 calls)") ;
 Serial.println();

 // set prescale to 16
 sbi(ADCSRA,ADPS2) ;
 cbi(ADCSRA,ADPS1) ;
 cbi(ADCSRA,ADPS0) ;

 Serial.println("ADCTest at 76.93 kHz sample rate") ;
 start = millis() ;
 for (i = 0 ; i < 1000 ; i++)
   analogRead(0) ;
 Serial.print(millis() - start) ;
 Serial.println(" ms (1000 calls)") ;
}

void loop()
{

}

The results are about as you would expect with nearly an order of magnitude improvement in ADC speed.

ADCTest at default 9.6 kHz sample rate
111 ms (1000 calls)

ADCTest at 76.93 kHz sample rate

18 ms (1000 calls)

Testing the Due with the following code shows the following:

ADCTest on Due 

3 ms (1000 calls)

Here is the code used:

void setup() 
{
 int start ;
 int i ;

 Serial.begin(115200) ;

 Serial.println("ADCTest on Due ") ;
 start = millis() ;
 for (i = 0 ; i < 1000 ; i++)
   analogRead(0);
 Serial.print(millis() - start) ;
 Serial.println(" ms (1000 calls)") ;
 Serial.println();

}

void loop() 
{

}

Thursday, November 6, 2014

New Minima-like build

My good friend Wayne NB6M has kindly loaned me his Minima-like build using my controller shield for the Arduino.  His front panel is very similar to his original Minima build, but is now sporting a 20x4 display.  He has removed the reset button from the front panel and added input for paddles in anticipation of me actually finishing the integration of my keyer code to the Minima code base.



Looking at the back of the panel, we can see the Arduino Uno and my controller shield mounted on the back of the display board.  Wayne has used #12 bare copper wire soldered to the front panel to provide attach points for the Uno and shield.  My shield will be modified to provide through-hole plating and solder pads so that it can be soldered in place.

The display board has been converted to i2c with a backpack board and the rotary encoder uses pins freed up by display being converted to i2c.  The current shield design does not incorporate the proposed pins for the encoder from the discussion list, but will be modified in the final run to be compliant.


Wayne is using a pretty conventional IF strip from the Minima, but has chosen to replace the KISS mixer and BFO mixer with ADE-1 devices.  His audio section is from a pre-existing project re-purposed for this project.  The two SMA connectors connect to the VFO and BFO Si570 outputs from my controller shield.  No low pass filter sections yet.  The current configuration makes a pretty nice general coverage receiver.


I have handed off Wayne's other Minima build to Eldon so he will have a working radio to test with during his software development efforts.

Tuesday, July 15, 2014

Minima hardware build

I have spent some time today organizing my Minima hardware so that it is not quite so fragile and breadboard-ish in preparation for starting to put together my own rig.

I am comfortable that I have the software in good shape and it is time to think about pulling together my own build.

Here is what I have for a front panel.  There is a 20 column by 4 line display, three push-buttons and a rotary encoder.  Readers of my blog may recognize this as the panel for my beacon project which is being re-purposed for this project.


I have mounted an I2C daughter board on the LCD in order to reduce the number of pins required to support the LCD.  I am not going to use the plethora of buttons I have seen on other designs.  I am also using a commercially available Arduino Uno board rather than build a controller board.  I have mounted it on the back of the LCD.  The remainder of the electronics of the radio will be in the bottom of the box.


I am replacing the potentiometer tuning with a rotary encoder and adding my iambic keyer code to the main Minima sketch.  If sufficient flash is available, I will also add my Arduino beacon code to the mix.  This may require an ATMega2560 device with its larger flash and RAM.  There may be sufficient space, but RAM in particular is getting a bit tight.