Society of Robots - Robot Forum

Software => Software => Topic started by: jkflorek on February 22, 2009, 05:30:22 PM

Title: $50 servo control ( concerning _delay_us() and _delay_ms() )
Post by: jkflorek on February 22, 2009, 05:30:22 PM
I wondering if, instead of using delay_cycles() for servo control/delays in the $50 robot, could the_delay_us() and _delay_ms() functions from WinAVR work?

I tried modifying the code, but I haven't received my microcontroller to test it on yet.

Here it is:
SoR_Utils.h
Code: [Select]
/****************************************************************************
*
*   Copyright (c) 2007 www.societyofrobots.com
*   (please link back if you use this code!)
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License version 2 as
*   published by the Free Software Foundation.
*
*   Alternatively, this software may be distributed under the terms of BSD
*   license.
*
* SoR Utilities v1, March 10th, 2007
*
****************************************************************************/

//AVR includes
#include <avr/io.h>     // include I/O definitions (port names, pin names, etc)
#include <avr/interrupt.h> // include interrupt support
#include <util/delay.h>     // include delay support (in us and ms)

//AVRlib includes
#include "global.h" // include global settings
//#include "buffer.h" // include buffer function library
//#include "uart.h" // include uart function library
//#include "rprintf.h" // include printf function library
//#include "timer.h" // include timer function library (timing, PWM, etc)
#include "a2d.h" // include A/D converter function library

//define port functions; example: PORT_ON( PORTD, 6);
#define PORT_ON( port_letter, number ) port_letter |= (1<<number)
#define PORT_OFF( port_letter, number ) port_letter &= ~(1<<number)
#define PORT_ALL_ON( port_letter, number ) port_letter |= (number)
#define PORT_ALL_OFF( port_letter, number ) port_letter &= ~(number)
#define FLIP_PORT( port_letter, number ) port_letter ^= (1<<number)
#define PORT_IS_ON( port_letter, number ) ( port_letter & (1<<number) )
#define PORT_IS_OFF( port_letter, number ) !( port_letter & (1<<number) )


//************CONFIGURE PORTS************
//configure ports for input or output - specific to ATmega8
void configure_ports(void)
{
DDRC = 0x00;  //configure all C ports for input
PORTC = 0x00; //make sure pull-up resistors are turned off
DDRD = 0xFF;  //configure all D ports for output
DDRB = 0xC7;  //configure B ports 0, 1, 2, 6, 7 for output (google search '0b11000111 to hex')
}
//***************************************

//************DELAY FUNCTIONS************
//wait for X amount of cycles (23 cycles is about .992 milliseconds)
//to calculate: 23/.992*(time in milliseconds) = number of cycles
//void delay_cycles(unsigned long int cycles)
// {
// while(cycles > 0)
// cycles--;
// }
//***************************************

//*********SIMPLIFIED FUNCTIONS**********
//functions to make coding easier for a beginner
//but could cause port mixup confusion for intermediate users
void LED_on(void)
{
PORT_OFF(PORTD, 4);//turn LED on
}
void LED_off(void)
{
PORT_ON(PORTD, 4);//turn LED off
}
void servo_left(signed long int speed)
{
PORT_ON(PORTD, 0);
_delay_us(speed);
PORT_OFF(PORTD, 0);//keep off
_delay_ms(8);
}
void servo_right(signed long int speed)
{
PORT_ON(PORTD, 1);
_delay_us(speed);
PORT_OFF(PORTD, 1);//keep off
_delay_ms(8);
}
//***************************************
Photovore_v1.c
Code: [Select]
/****************************************************************************
*
*   Copyright (c) 2007 www.societyofrobots.com
*   (please link back if you use this code!)
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License version 2 as
*   published by the Free Software Foundation.
*
*   Alternatively, this software may be distributed under the terms of BSD
*   license.
*
* Photovore v1, March 10th, 2007
* Simple case-based method for a robot that chases light.
*
*
****************************************************************************/

//SoR Include
#include "SoR_Utils.h" //includes all the technical stuff


int main(void)
{
//declare variables here
//int i=250;//a 'whatever' variable
int sensor_left=0;//left photoresistor
int sensor_right=0;//right photoresistor
int threshold=8;//the larger this number, the more likely your robot will drive straight


/****************INITIALIZATIONS*******************/
//other stuff Im experimenting with for SoR
//uartInit();  // initialize the UART (serial port)
//uartSetBaudRate(9600);// set the baud rate of the UART for our debug/reporting output
//rprintfInit(uartSendByte);// initialize rprintf system

//timerInit(); // initialize the timer system

configure_ports(); // configure which ports are analog, digital, etc.
a2dInit(); // initialize analog to digital converter (ADC)
a2dSetPrescaler(ADC_PRESCALE_DIV32); // configure ADC scaling
a2dSetReference(ADC_REFERENCE_AVCC); // configure ADC reference voltage

//rprintf("Initialization Complete\r\n");
/**************************************************/


/*********ADD YOUR CODE BELOW THIS LINE **********/
LED_off();//turn LED on


while(1)
{
//store sensor data
sensor_left=a2dConvert8bit(5);
sensor_right=a2dConvert8bit(4);


//detects more light on left side of robot
if(sensor_left > sensor_right && (sensor_left - sensor_right) > threshold)
{//go left
servo_left(1750);
servo_right(1750);
}

//detects more light on right side of robot
else if(sensor_right > sensor_left && (sensor_right - sensor_left) > threshold)
{//go right
servo_left(1250);
servo_right(1250);
}

//light is about equal on both sides
else
{//go straight
servo_left(1250);
servo_right(1750);
}


/* Servo Test Code
i=250;
while(i>0)
{
servo_left(40);
i--;
}

i=250;
while(i>0)
{
servo_left(24);
i--;
}
*/

//rprintf("Initialization Complete\r\n");

//output message to serial (use hyperterminal)
//print("Hello, World! Read My Analog: %u\r\n", sensor_0);

_delay_ms(20);//a small delay to prevent crazy oscillations
}
/*********ADD YOUR CODE ABOVE THIS LINE **********/

return 0;
}


/*********************COMMAND LIST*************************

delay_cycles(cycles);
Delays - you can make your robot wait for a certain amount of time with this function.
Put the number of computational cycles to delay in the ().
23 cycles is about .992 milliseconds
to calculate: 23/.992*(time in milliseconds to delay) = cycles
Check servo datasheet where it says: 'Direction: Clockwise/Pulse Traveling 1500 to 1900usec'


servo_left(speed); and servo_right(speed);
Commands your servos to rotate at a certain speed.
Vary speed (which represents a delay in cycles) from 20 to 50.
Left is for port D0 and right is for port D1.


LED_on(); and LED_off();
Turns on and off your LED. The LED is on port D4.
By bringing port D4 low, you are turning on the LED.


variable=a2dConvert8bit(pin);
Reads analog pin. For example, set 'pin' to 5 to read PC5.
'variable' will store the value.

***********************************************************/
Title: Re: $50 servo control ( concerning _delay_us() and _delay_ms() )
Post by: cosminprund on February 23, 2009, 01:14:54 AM
It's probably a matter of resolution. You can't delay less then one cycle and this:

Code: [Select]
23 cycles is about .992 milliseconds

... tells you you're working with an pretty slow MCU: .992/23 ~= 0.043 ms per clock cycle, and that's ~= 43 us per clock cycle; This makes the _delay_us() pretty unusefull because it will round everything to 43 us anyway, probably more because of the inherent lost cycles: remamber an cycle is 43 us!

If you'd hook up an oscillator to that MCU you might get better use out of the _delay_us() and _delay_ms() functions but as things are it's probably better to simply use the delay_cycles routine, it's closer to what's actually happening.
Title: Re: $50 servo control ( concerning _delay_us() and _delay_ms() )
Post by: Admin on February 26, 2009, 09:34:04 PM
The delay_us() and delay_ms() functions for AVR Lib C (not WinAVR) also use cycles. You define clock rate, and it automatically calculates required cycles for you. However their method introduces rounding errors that I didn't like. You can use either method as all code comes with the $50 Robot.