Servo Motor

In this blog, I will be talking about what a servo motor is and how it operates.

A servo motor is an actuator that allows for high degree control of angles between 0 and 90 degree’s (depending on the “range” of the specific motor it could be greater), this is a level of control is achieved due to its design which can be explained in great detail the following video.

A servo motor as shown in the picture below is controlled by a length of a pulse generated from a microcontroller. 

PWM (Pulse Width Modulation) as I have mentioned in my previous blog can be used in many applications. In this scenario, we will be using PWM to control the angle of a servo motor. The minimum pulses being 0 and highest normally being 2 ms. In some servo motors the upper limit and angle will be greater than 180 degrees and 2 ms.

For my mini-project, I intend to make a simple bodyguard robot that has two arms and moves around on wheels. Since two arms are required I decided to use 2 servo motors per arm in a pan and tilt configuration.

with a bit of googling, I stumped upon this.

lynxmotion-pan-and-tilt-kit-aluminium2_2
CLICK ME!

So I decided to buy 2 sets of these arms and a dual bracket to hold them together to act as the torso of the robot. Using two the PWM channels on the DSPIC30F4011, the ADC, and a potentiometer. I used a code to see the limitations of the motors angles.
When the kit arrived, construction began.
img_3404

servomotordouble

// Written by Kevin Tighe
// Based on the code written by Ted Burke
//@batchloaf.wordpress.com or @roboted.wordpress.com
// Last updated 11/12/2016
//

#include <xc.h>
#include 			<libpic30.h>
#include <stdio.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF); // Watchdog timer off
_FBORPOR(MCLR_DIS); // Disable reset pin

//definitions
#define Second 30000000 // 1 second

// Function prototypes
unsigned int read_analog_channel(int n);

int main()
{
int voltage = 0;
int voltage2 = 0;
// Make all port D pins outputs
TRISD = 0;

// Configure AN0-AN8 as analog inputs
ADCON3bits.ADCS = 15; // Tad = 266ns, conversion time is 12*Tad
ADCON1bits.ADON = 1; // Turn ADC ON

// Configure PWM for free running mode
//
// PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * PTPER
// PWM pulse width = (Tcy/2) * prescale * PDCx
//
PWMCON1 = 0x00FF; // Enable all PWM pairs in complementary mode
PTCONbits.PTCKPS = 3; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
_PEN2H = 1; // Enable PWM1H pin
_PEN2L = 1; // Enable PWM1L pin
PTPER = 9375; // 20ms PWM period (15-bit period value)
PDC1 = 1406;
PDC2 = 1406; // 1.5ms pulse width on PWM channel 1
PDC3 = 1406;
PTCONbits.PTEN = 1; // Enable PWM time base

// Setup UART
U1BRG = 48; // 38400 baud @ 30 MIPS
U1MODEbits.UARTEN = 1; // Enable UART

// fast flsh to signal reset
int n;
for(n=0;n<10;n++) //Small tester code to see if LED / Circuit is working
{
_LATD1 = 1;
__delay32(1500000);
_LATD1 = 0;
__delay32(1500000);
}

while(1)
{
// Read analog voltage from AN0 (pin 2)
// The number returned (between 0 and 1023)
// represents a voltage in the range 0-5V.
voltage = read_analog_channel(0);
voltage2 = read_analog_channel(1);

// If the voltage is greater than 2.5V
// turn on the LED on RD0 (pin 23),
// otherwise turn it off.
if (voltage < 512) _LATD0 = 0;
else _LATD0 = 1;

// Display the voltage reading on screen
printf("\nVoltage = %d\n\n\n", voltage);
printf("\nVoltage2 = %d\n", voltage2);

// Calculate and update the servo angle
// based on potentiometer voltage on AN0.
// In this case we want voltage values
// between 0 and 1023 to be mapped onto
// PDC1 values between 600 and 1800.
PDC2 = 500 + (2000-500)*(voltage/1023.0);
PDC3 = 425 + (1500-450)*(voltage2/1023.0);
// 100ms delay
__delay32(Second/10);
}

return 0;
}
// This function reads a single sample from the specified
// analog input. It should take less than 5us when the
// microcontroller is running at 30 MIPS.
// The dsPIC30F4011 has a 10-bit ADC, so the value
// returned is between 0 and 1023 inclusive.
unsigned int read_analog_channel(int channel)
{
ADCHS = channel; // Select the requested channel
ADCON1bits.SAMP = 1; // Start sampling
__delay32(30); // 1us delay @ 30 MIPS
ADCON1bits.SAMP = 0; // Start Converting
while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
return ADCBUF0;
}

Here's a small video of the progression that was made.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s