Analog voltmeter using stepper motor and a Colour sensor(Draft)

 

Wiring Diagram

20121029-221000.jpg

20121029-220952.jpg

20121029-220944.jpg

Very simple use of a stepper motor, will update this post in a bit. The video seems to stop prematurely around 2/3 of the video on my laptop for some reason so just click on the tracker bar to watch the rest of it.


//
// dsPIC30F4011 Stepper motor powered analog Voltmeter
// Written by Gian Lorenzo
// Last updated 25-10-2012
//

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

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

// Function prototypes
void rotate(double degrees);	//	Rotate function
void step_forward();			//	Step forward function
void step_back();				// Step backward function
void setup();					// Setup configurations
unsigned int read_analog_channel(int channel);	// Read analog channel function
void pause(unsigned long ms);	// Pause in ms = (time in ms)*FCY/1000

// Global variable declarations
int t;
int voltage;
double svoltage;
double rotor_angle;
double step_angle;
long step_time;

int main()
{
	// Setup configurations
	setup();

	// Use initial position as angle origin
	rotor_angle = 0;

	// Stepper properties
	step_time = 120000L; // 4ms
	step_angle = 0.17578125; // 360.0 divided by 2048

	// Now rotate the stepper 6 degrees once every second
	while(1)
	{
		while(read_analog_channel(1)<500)
		{
			step_back();
		}
		rotor_angle = 0;
		while(1)
		{
			voltage = read_analog_channel(0);
			svoltage = voltage*(5/1023);
			if(rotor_angle<(voltage*step_angle)) 			{ 				step_forward(); 				printf("Voltage = %3f\n",svoltage); 			} 			else if(rotor_angle>(voltage*step_angle))
			{
				step_back();
			}
		}
	}

	return 0;
}

void rotate(double degrees)
{
	// The target angle is the current angle
	// plus the requested angle of rotation.
	double target_angle = rotor_angle + degrees;

	// Now keep stepping in the appropriate
	// direction until the target is reached.
	if (degrees > 0)
	{
		while(rotor_angle < target_angle) step_forward(); 	} 	else 	{ 		while(rotor_angle > target_angle) step_back();
	}
}

void step_forward()
{
	// Turn off the previous phase and turn
	// on the next one.
	if (LATD == 0b0001) LATD = 0b0010;
	else if (LATD == 0b0010) LATD = 0b0100;
	else if (LATD == 0b0100) LATD = 0b1000;
	else if (LATD == 0b1000) LATD = 0b0001;
	else LATD = 0b0001;

	// Increment the global angle tracker.
	rotor_angle = rotor_angle + step_angle;

	// Delay to allow rotor to move.
	__delay32(step_time);
}

void step_back()
{
	// Turn off the previous phase and turn
	// on the next one.
	if (LATD == 0b0001) LATD = 0b1000;
	else if (LATD == 0b0010) LATD = 0b0001;
	else if (LATD == 0b0100) LATD = 0b0010;
	else if (LATD == 0b1000) LATD = 0b0100;
	else LATD = 0b0001;

	// Decrement the global angle tracker.
	rotor_angle = rotor_angle - step_angle;

	// Delay to allow rotor to move.
	__delay32(step_time);
}
void setup()
{
    // Setup UART
	__C30_UART=2;
    U2BRG = 48;            // 38400 baud @ 30 MIPS
    U2MODEbits.UARTEN = 1; // Enable UART

    // Configure D ports as a digital outputs
    LATD = 0;
    TRISD = 0b11110000;

    // Configure analog inputs
    TRISB = 0x01FF;      /* Port B all inputs */
    ADPCFG = 0xFF00;     /* PORTB 0-7 are analog inputs */
    ADCON1 = 0;          /* Manually clear SAMP to end sampling, start conversion*/
    ADCON2 = 0;          /* Voltage reference from AVDD and AVSS */
    ADCON3 = 0x0005;     /* Manual Sample, ADCS=5 -> Tad = 3*Tcy = 0.1us */
    ADCON1bits.ADON = 1; /* Turn ADC ON */

    // Configure PWM
    // PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * 9470 = 20ms
    PWMCON1 = 0x00FF; // Enable all PWM pairs in complementary mode
    PTCON = 0;
    _PTCKPS = 3;      // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
    PTPER = 9470;     // 20ms PWM period (15-bit period value)
    PDC1 = 0;         // 0% duty cycle on channel 1 (max is 65536)
    PDC2 = 0;         // 0% duty cycle on channel 2 (max is 65536)
    PDC3 = 0;         // 0% duty cycle on channel 3 (max is 65536)
    PTMR = 0;         // Clear 15-bit PWM timer counter
    _PTEN = 1;        // Enable PWM time base

	/*// Configure I2c
	TRISFbits.TRISF2 = 1; // SDA
	TRISFbits.TRISF3 = 1; // SCL
	I2CCONbits.I2CSIDL = 1;	// Stop module in idle mode
	I2CCONbits.A10M = 0;	// 7-bit address
	I2CCONbits.DISSLW = 0;	// slew rate control for 400khz must be on
	I2CBRG = 45;		// 272 for 100kHz at FCY = 30MHz formula next line
							// I2CBRG = ((1/rate - 250ns)*FCY)-1
	I2CCONbits.I2CEN = 1;	// Enable i2c*/
}

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 = 1.2us
    return ADCBUF0;
}
void pause(unsigned long ms)
{
	__delay32(ms*30000L);
}

Advertisements

2D mapping using servo and Sharp rangefinder(draft)

Wiring Diagram

20121029-220138.jpg

20121029-220108.jpg

Watch in HD to see my teeny text(Sorry!). Also it gave values of 0 on the 3:56 mark because one of the wires came loose.


// Basic 2D mapping using a servo motor and Sharp rangefinder
// Program written by Gian Lorenzo
// Last edited 29/10/2012
//

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

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

// Function prototypes
void setup();
unsigned int read_analog_channel(int n);
void pause(unsigned long ms);
void forward();
void back();
void forwardnum(unsigned int pdc);
void backnum(unsigned int pdc2);

int main()
{
	setup();
	int voltage;
	int status,x=1,y=1,a=0,b=1,c=0;
	int distance[36];
	int quadrant;
	int angle[5];
	int mag[5];
	int min_angle = 750, max_angle = 2230;
	
	PDC1 = min_angle;
	pause(1000);
	distance[0]=0;
	status=0;
	
	while(1)
	{
		voltage = read_analog_channel(0);
		while(x<35)
		{
			voltage = read_analog_channel(0);
			forwardnum(43);
			pause(300);
			if(voltage < 250)
			{
				distance[x]=0;
				status = 0;
			}
			else
			{
				distance[x]=voltage;
				status =1;
			}
			if(status == 1)
			{
				angle[b]=(x*5);
				mag[b]=distance[x-2];
				c=1;
				a++;
			}
			if(status == 0 && c==1 || (x==35 && c==1))
			{
				angle[b]= (angle[b] - ((a*5)/2))-5;
				c=0;
				b++;
				a=0;
			}
			
			x++;
		}
		if(x == 35)
		{
			printf("%d %d %d %d %d %d
                          %d %d %d %d %d %d
                          %d %d %d %d %d %d
                          %d %d %d %d %d %d
                          %d %d %d %d %d %d
                          %d %d %d %d %d\n\n",
			  distance[0],distance[1],distance[2],distance[3],distance[4],
              distance[5],distance[6],distance[7],distance[8],distance[9],
              distance[10],distance[11],distance[12],distance[13],
              distance[14],distance[15],distance[16],distance[17],
              distance[18],distance[19],distance[20],distance[21],
              distance[22],distance[23],distance[24],distance[25],
              distance[26],distance[27],distance[28],distance[29],
              distance[30],distance[31],distance[32],distance[33],
              distance[34]);
			if(angle[b]>179 || angle[b]<1)
			{
				b=b-1;
			}
			while(b>0)
			{
				if(mag[b]<400 && angle[b] > 90 && angle[b] < 145)
				{
					quadrant = 1;
				}
				if(mag[b]<400 && angle[b] > 45 && angle[b] < 90)
				{
					quadrant = 2;
				}
				if(mag[b]>400 && angle[b] > 0 && angle[b] < 90)
				{
					quadrant = 3;
				}
				if(mag[b]>400 && angle[b] > 90 && angle[b] < 180)
				{
					quadrant = 4;
				}
				printf("Object number %d magnitude = %d \r angle = %d and lies in quadrant %d\n\n", b, mag[b],angle[b], quadrant);
				b=b-1;
			}			
			x++;
		}
		pause(15000);
		PDC1=750;
		pause(2000);
		x=1;
		b=1;
		mag[1]=mag[2]=mag[3]=mag[4]=0;
		angle[1]=angle[2]=angle[3]=angle[4]=0;
	}

    return 0;
}

void forward()
{
	PDC1 = PDC1 + 10;
	pause(.5);
}
void back()
{
	PDC1 = PDC1 - 10;
	pause(.5);
}
void forwardnum(unsigned int pdc)
{
	PDC1 = PDC1 + pdc;
}
void backnum(unsigned int pdc2)
{
	PDC1 = PDC1 - pdc2;
	pause(10);
}

void setup()
{
    // Setup UART
    U1BRG = 48;            // 38400 baud @ 30 MIPS
    U1MODEbits.UARTEN = 1; // Enable UART

    // Configure D ports as a digital outputs
    LATD = 0;
    TRISD = 0b11110000;

    // Configure analog inputs
    TRISB = 0x01FF;      /* Port B all inputs */
    ADPCFG = 0xFF00;     /* PORTB 0-7 are analog inputs */
    ADCON1 = 0;          /* Manually clear SAMP to end sampling, start conversion*/
    ADCON2 = 0;          /* Voltage reference from AVDD and AVSS */
    ADCON3 = 0x0005;     /* Manual Sample, ADCS=5 -> Tad = 3*Tcy = 0.1us */
    ADCON1bits.ADON = 1; /* Turn ADC ON */

    // Configure PWM
    // PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * 9470 = 20ms
    PWMCON1 = 0x00FF; // Enable all PWM pairs in complementary mode
    PTCON = 0;
    _PTCKPS = 3;      // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
    PTPER = 9470;     // 20ms PWM period (15-bit period value)
    PDC1 = 0;         // 0% duty cycle on channel 1 (max is 65536)
    PDC2 = 0;         // 0% duty cycle on channel 2 (max is 65536)
    PDC3 = 0;         // 0% duty cycle on channel 3 (max is 65536)
    PTMR = 0;         // Clear 15-bit PWM timer counter
    _PTEN = 1;        // Enable PWM time base
}
// Analogue input reading
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 = 1.2us
    return ADCBUF0;
}
void pause(unsigned long ms)
{
	__delay32(ms*30000L);
}

Example UART output of the program on the PICkit2 uart tool

Robotics

**Greetings! It’s been a while since I tended my blog, I’ve been busy running around college and whatnot. But it looks like that’s about to change since I’ll be using this blog to document my Robotics module, so let’s get started!**

Robotics 3.1

As was mentioned I am starting a new module called ¬†robotics this year and I shall be documenting it using this blog. ¬†On this first official post I shall be talking about what the module aims to teach us and the components given to us to work with. And some of my ideas that I’ll use the sensors for.

The module revolves around using the dsPIC30f4011 and integrating sensors and actuators to it. The dsPIC is the beefier brother of the normal PIC we used last year in the robosumo tournament, it has more PWM pins and more analog pins and can be seen in action on my last post. Another aspect of the module is communication with the dsPIC, the main mode we shall be using is UART as far as I know, but I’ve been reading about I2C for about a month now since I’ll be using this(hopefully) for my main event. Another big thing is the concept of Pulse Width Modulation which I talked about(in babytalk) again, in my last post. I’ll be explaining it a bit more thoroughly come the post where I use my servo.

On the second week of the module, we were given a ziploc bag containing sensors and actuators to work with. These materials are:

Materials on ziploc bag:

  1. dsPIC30f4011
  2. Servo Motor
  3. Stepper motor
  4. Geared DC motor
  5. H-Bridge
  6. 1 x OPB704 IR sensor
  7. Random small components

My own materials that I plan to use:

  1. Extra dsPIC & PIC
  2. PICkit2
  3. Sharp Rangefinder
  4. Extra IR sensors
  5. IR LEDs
  6. IR reciever
  7. Piezo-Electric transducer discs
  8. Resistance Temperature Detectors
  9. Light Dependent Resistors
  10. Wii nunchuck, Wiimote , and Wii Motion Plus

As it can be seen: most of the stuff given to us; we already worked with. The only new thing really is the PIC itself but only by a trivial factor. That’s all I can think of for now anyway. I already have templates for the Servo motor made a week after my DC motor post but there’s no point posting it now as it’s just a potentiometer controlling the angle, and that’s no fun! Coming up in a few hours : Stepper motor used to make an analog voltmeter. Sneak preview here.