|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
| Thread Tools | Rate Thread | Display Modes |
|
#1
|
|||
|
|||
|
Auto mode... need help
Hey guys,
ok i doign some stuff in automode.. nothing tooo cool.. but its a start. Basicaly all i am doing is driving the robot forward and backwards. Now.. i have it program in "if" statements example. if (count == 1) { pwm01 = 254; } sooo... i need a timer. count is what the time is. Sorta confusing but at 1 second its goign to go forward. But the problem i am having is creating code for the timer. Does the orignal code have a timer programmed already ? or should i make my own. let me know ![]() |
|
#2
|
||||
|
||||
|
Re: Auto mode... need help
The easiest way to do this is to increment a variable every time you get new data from the master processor.
Default Autonomous: Code:
while (autonomous_mode) /* DO NOT CHANGE! */
{
if (statusflag.NEW_SPI_DATA) /* 26.2ms loop area */
{
Getdata(&rxdata); /* DO NOT DELETE, or you will be stuck here forever! */
/* Add your own autonomous code here. */
Generate_Pwms(pwm13,pwm14,pwm15,pwm16);
Putdata(&txdata); /* DO NOT DELETE, or you will get no PWM outputs! */
}
}
Code:
static int i; Code:
while (autonomous_mode) /* DO NOT CHANGE! */
{
if (statusflag.NEW_SPI_DATA) /* 26.2ms loop area */
{
Getdata(&rxdata); /* DO NOT DELETE, or you will be stuck here forever! */
i++; // this will increment the 'i' variable by 1.
/* Add your own autonomous code here. */
Generate_Pwms(pwm13,pwm14,pwm15,pwm16);
Putdata(&txdata); /* DO NOT DELETE, or you will get no PWM outputs! */
}
}
Code:
int time;
while (autonomous_mode) /* DO NOT CHANGE! */
{
if (statusflag.NEW_SPI_DATA) /* 26.2ms loop area */
{
Getdata(&rxdata); /* DO NOT DELETE, or you will be stuck here forever! */
i++; // this will increment the 'i' variable by 1.
time = (i * 262)/2500 // if you avoid the decimal, by multiplying the time span by 10, your code will execute faster because it will not use a floatig points.
// I divide the time(in 10000enths of a second) by 2500 so I get a result in 1/4 of a second
Generate_Pwms(pwm13,pwm14,pwm15,pwm16);
Putdata(&txdata); /* DO NOT DELETE, or you will get no PWM outputs! */
}
}
Code:
int time;
while (autonomous_mode) /* DO NOT CHANGE! */
{
if (statusflag.NEW_SPI_DATA) /* 26.2ms loop area */
{
Getdata(&rxdata); /* DO NOT DELETE, or you will be stuck here forever! */
i++; // this will increment the 'i' variable by 1.
time = (i * 262)/2500 // if you avoid the decimal, by multiplying the time span by 10, your code will execute faster because it will not use a floatig points.
// I divide the time(in 10000enths of a second) by 2500 so I get a result in 1/4 of a second
//drive code\\
if (time < 4) pwm01 = pwm02 = 255; //forward
else if(time < 8) pwm01 = pwm02 = 0; //reverse
else if(time > 8) pwm01 = pwm02 = 127;//stop
Generate_Pwms(pwm13,pwm14,pwm15,pwm16);
Putdata(&txdata); /* DO NOT DELETE, or you will get no PWM outputs! */
}
}
Hope this helps, and sorry for the long post. ![]() |
|
#3
|
|||
|
|||
|
Re: Auto mode... need help
That assumes that your code will take the same time as the default code does. Maybe you have some intensive stuff and each loops takes longer than the 26.2 ms loop. Your code works effectivly for most things though. teh_pwnerer795, if you wanted to use the chips timer post back and ill post code for using that.
|
|
#4
|
||||
|
||||
|
Re: Auto mode... need help
I used a simpler approach this year and had no issue with it.
I would doubt that you could tax the processor to the point that the autonomous code would take longer than 26.2ms |
|
#5
|
||||
|
||||
|
Re: Auto mode... need help
Quote:
I would suggest using real timers. For more information, take a look at IFI's white-paper (PDF). They have a very nice explanation of how to use the timers built into the PIC. |
|
#6
|
|||
|
|||
|
Re: Auto mode... need help
Awesome.
I know rite now my code isnt very intensive at the moment.. but i do tend to have long code.. lol my engineering program for turing was 1500 lines when someppls were 100. but got it down to 150 once i got some logic into it!! ...but ye i'll keep u posted if it works or not... |
|
#7
|
|||
|
|||
|
Re: Auto mode... need help
Code:
int time;
while (autonomous_mode) /* DO NOT CHANGE! */
{
if (statusflag.NEW_SPI_DATA) /* 26.2ms loop area */
{
Getdata(&rxdata); /* DO NOT DELETE, or you will be stuck here forever! */
i++; // this will increment the 'i' variable by 1.
time = (i * 262)/2500 // if you avoid the decimal, by multiplying the time span by 10, your code will execute faster because it will not use a floatig points.
// I divide the time(in 10000enths of a second) by 2500 so I get a result in 1/4 of a second
Generate_Pwms(pwm13,pwm14,pwm15,pwm16);
Putdata(&txdata); /* DO NOT DELETE, or you will get no PWM outputs! */
}
}
no problem for the post... im sorta confused.. if the computer cycles at 26.2 ms... will it not cycle rougly 38 times in a second? if so... your code.. where 'i' is increased by 1 every cycle, when it reaches 1 second.. i == 38..... if so... time == 4 roughly at 1 second... shouldnt u divide it by 4? to get 1 second??? srry if i confused you ![]() lol srry just trying to understand the logic behind 'time' |
|
#8
|
|||
|
|||
|
Re: Auto mode... need help
Quote:
OMG i am such an idiot I GET IT NOW ![]() SOO SRRY hm.. another question... how do i round? i remember doing it in java... not suer if its the same in C |
|
#9
|
||||
|
||||
|
Re: Auto mode... need help
Quote:
Actually the problem as mentioned before is its very unlikely to take that long. If memory serves it loops as fast as possible, so it could run anywhere from about 12ms to 26.2 and it will change depending on your autonomous code, if its really time sensitive, you should use the hardware timer, and its just good to know how to use that anyway. |
|
#10
|
||||
|
||||
|
Re: Auto mode... need help
Quote:
If you really needed the decimal part, you could use the float type instead of int. There are some problems with doing this discussed here, and I wouldn't really recommend doing this on the RC. EHaskins offered up some good suggestions, but there is a slight annoyance with it. What happens if you have a 10 step time based routine and you need to change the first duration to be a little longer or shorter? You have to change them all. One way to fix it would be to use constants, and make them relative to each other. Code:
#define AUTO_STEP1_END (10)
#define AUTO_STEP2_END (AUTO_DURATION_STEP1 + 5)
.....
if(i <= AUTO_STEP1_END)
{
....
}
else if(i <= AUTO_STEP2_END)
{
...
}
...
Code:
#define NOT_DONE 0
#define DONE 1
...
#define MAX_AUTO_STEP 3
...
enum
{
PROG_STEP1,
PROG_STEP2,
PROG_STEP3,
PROG_STEP_LAST = PROG_STEP2,
};
...
static int prog_done = NOT_DONE;
static int prog_step = 0;
...
int ret;
if(prog_step < PROG_STEP_LAST)
{
switch prog_step
{
case PROG_STEP1:
ret = do_step1(); // These function names could be more specific
break;
case PROG_STEP2:
ret = do_step2(); // These function names could be more specific
break;
case PROG_STEP3:
ret = do_step3(); // These function names could be more specific
break;
default:
// Bad step number, exit now
prog_step = PROG_STEP_LAST;
break;
}
if(ret == DONE)
{
// Step is complete, move on
prog_step++;
}
}
else
{
// Set all pwms to 127 to terminate the run
}
....
// Then you would define your program step functions to do what you needed
int do_step1(void)
{
static int i = 0;
int status = NOT_DONE;
if(i >= 40)
{
// Set PWM values here
}
else
{
status = DONE;
}
return stats;
}
int do_step2(void)
{
static int i = 0;
int status = NOT_DONE;
if(i >= 30)
{
// Set PWM values here
}
else
{
status = DONE;
}
return stats;
}
int do_step3(void)
{
.....
}
Here's another perk. If you want to add a delay between step 2 and 3, you could change the enum to have PROG_STEP_2A between PROG_STEP_2 and 3. Then, in your switch, you could do something like Code:
...
case PROG_STEP_2A:
ret = do_wait(100);
break;
...
int do_wait(int loops)
{
static int i = 0;
int ret = NOT_DONE;
if(i >= loops)
{
i = 0; // Leave the loop counter ready to go the next time.
ret = DONE;
}
else
{
// Turn PWMs off
i++;
}
return ret;
}
Code:
... case PROG_STEP_2A: ret = DONE; // ret = do_wait(100); break; ... Last edited by Dave Scheck : 08-12-2006 at 11:10. |
|
#11
|
||||
|
||||
|
Re: Auto mode... need help
Quote:
|
|
#12
|
||||
|
||||
|
Re: Auto mode... need help
Quote:
Hope this helps, Paul |
|
#13
|
||||
|
||||
|
Re: Auto mode... need help
Quote:
|
|
#14
|
|||||
|
|||||
|
Re: Auto mode... need help
I have to say, after a season and a half of asking the strategy guy how long he wants it to go out, then stepping into Calculator, then punching the wrong numbers, then typing the wrong number I just calculated into my code (now converted to 26.2ms cycles), then seeing it totally mess up when I put it on the field...having a *real* timer is SO nice. I implemented the hardware timer, so now I have a Windows-style GetTickCount() type function, and it works very accurately. The scouts tell me that the bot needs to be in front of the other bot in 2 seconds: I give them 2 seconds. Not 2000ms / 26.2ms = 76 cycles--blech. Those never worked right for me.
What I haven't solved yet is the overflow issue. What data type do I use to hold the huge number? I have no idea. I can't reset the tick count to 0 each time it hits the upper limit my code is waiting for because I have more than one part of my code using this tick count. I think I'll use the hugest data type I can get--I'll have to look it up; I don't know C in and out. JBot |
|
#15
|
||||
|
||||
|
Re: Auto mode... need help
Here's some code for an interrupt-driven timer.
Call Timer_1_Initialize() in the User_Initialization routine in user_routines.c, add the call to the interrupt handler to user_routines_fast.c. Time is in the timer_ variables. Mike Code:
/*******************************************************************************
*
* TITLE: wallclock.h
*
* VERSION: 0.1 (Beta)
*
* DATE: 23-Sep-2006
*
* AUTHOR: Mike Luckham
* sunrise@sunsys.net
*
********************************************************************************
*
* You are free to use this source code for any non-commercial
* use. Please do not make copies of this source code, modified
* or un-modified, publicly available on the internet or
* elsewhere without permission. Thanks.
*
* Copyright ©2006-2007 Mike Luckham. All rights are reserved.
*
********************************************************************************
*
* CHANGE LOG:
*
* DATE REV DESCRIPTION
* ----------- --- ----------------------------------------------------------
* 23-Sep-2006 0.1 Mike Luckham - Original code.
*
*******************************************************************************/
#ifndef _WALLCLOCK_H
#define _WALLCLOCK_H
typedef struct {
unsigned int hours;
unsigned int minutes;
unsigned int seconds;
unsigned int msec;
unsigned int usec;
unsigned long timestamp;
} WallTime;
// Do not write to any of these variables
extern volatile unsigned long timer_msecClock; // milliseconds since system start (overflows after 49.7 days)
extern unsigned long Timer_1_MicrosecondsTimestamp(void);
#define timer_usecClock Timer_1_MicrosecondsTimestamp() // microseconds since system start (overflows after about 71 minutes)
// current time decoded
#define timer_microseconds Timer_1_Microseconds()
extern volatile unsigned int timer_milliseconds;
extern volatile unsigned int timer_100msec;
extern volatile unsigned int timer_seconds;
extern volatile unsigned int timer_minutes;
extern volatile unsigned int timer_hours;
extern void Timer_1_Reset(void);
extern void Timer_1_Initialize(void);
extern void Timer_1_Int_Handler(void);
extern void Timer_1_Load_Prescale(void);
extern unsigned int Timer_1_Microseconds(void);
extern void Timer_1_ReadTimeStruct(WallTime *);
#endif
Code:
/*******************************************************************************
*
* TITLE: wallclock.c
*
* VERSION: 0.1 (Beta)
*
* DATE: 23-Sep-2006
*
* AUTHOR: Mike Luckham
* sunrise@sunsys.net
*
* COMMENTS: This source code in this file implements a clock that is useful
* for tracking time at millisecond resolution. A timestamp value
* is useful for comparing the time between events. The timestamp
* is decoded into hours/minutes/seconds/milliseconds, and the
* current time can be read at microsecond resolution.
*
* Since the clock is interrupt-driven, it runs independently and
* maintains correct time between calls to user_routines.c by the master
* scheduler.
*
* To use the code, include wallclock.h in the user_routines.c and
* user_routines_fast.c source files, and:
*
* 1) call Timer_1_Initialize() from user_routines.c in User_Initialization()
*
* 2) add the following to user_routines_fast.c in InterruptHandlerLow():
*
* if (PIR1bits.TMR1IF && PIE1bits.TMR1IE)
* {
* PIR1bits.TMR1IF = 0; // clear the interrupt flag
* Timer_1_Int_Handler();
* }
*
* 3) when you need to measure elapsed time, store timer_msecClock into
* an unsigned long variable at the beginning of the interval, then subtract
* timer_msecClock from the saved value at the end of the interval to obtain
* the number of milliseconds which have elapsed.
*
* If you need the microsecond portion of the time, store the value returned
* by the timer_microseconds macro into an unsigned long variable. Probably this
* is of limited usefulness, although it could be useful in a busy-loop.
*
* The decoded time is available in the timer_ variables. Here is an example of
* how to use them:
*
* printf("%u:%u:%u.%u.%u\n", timer_hours, timer_minutes, timer_seconds, timer_milliseconds, timer_microseconds);
*
*
********************************************************************************
*
* You are free to use this source code for any non-commercial
* use. Please do not make copies of this source code, modified
* or un-modified, publicly available on the internet or
* elsewhere without permission. Thanks.
*
* Copyright ©2006-2007 Mike Luckham. All rights are reserved.
*
********************************************************************************
*
* CHANGE LOG:
*
* DATE REV DESCRIPTION
* ----------- --- ----------------------------------------------------------
* 23-Sep-2006 0.1 Mike Luckham - Original code.
*
*******************************************************************************/
#include "ifi_aliases.h"
#include "ifi_default.h"
#include "wallclock.h"
/********** GLOBAL CLOCK VARIABLES ***********************************************/
volatile unsigned long timer_msecClock = 0L; // milliseconds since system start (overflows after 49.7 days)
// current wall-clock time
volatile unsigned int timer_100msec = 0; // increments once every 100 milliseconds
volatile unsigned int timer_milliseconds = 0; // increments once per millisecond
volatile unsigned int timer_seconds = 0; // increments once per second
volatile unsigned int timer_minutes = 0; // increments once per minute
volatile unsigned int timer_hours = 0; // increments once per hour
// for the current microseconds count, use Timer_1_Microseconds
WallTime wTime;
// preload the timer so that the interrupt-on-overflow occurs 1000 microseconds later
// for microprocessor clock crystal 40MHz/4 = 10MHz tick rate = 65535 - 10000 (0xD8EF)
#define PRELOAD_LOW 0xD8
#define PRELOAD_HIGH 0xEF
/*******************************************************************************
* FUNCTION NAME: Timer_1_Reset
* PURPOSE: resets clock variables to zero
* CALLED FROM: user_routines.c
* ARGUMENTS: none
* RETURNS: real-time clock variables are reset
*******************************************************************************/
void Timer_1_Reset(void)
{
timer_msecClock = 0L;
timer_milliseconds = 0;
timer_seconds = 0;
timer_minutes = 0;
timer_hours = 0;
}
/*******************************************************************************
* FUNCTION NAME: Timer_1_Load_Prescale
* PURPOSE: preload the timer to overflow after 1000 microseconds
* CALLED FROM: user_routines_fast.c, user_routines.c
* ARGUMENTS: none
* RETURNS: Timer1 is preloaded
*******************************************************************************/
void Timer_1_Load_Prescale(void)
{
// NOTE: Timer specification requires MUST write high byte
// first, then low byte
TMR1H = PRELOAD_LOW; // preload the timer so that the interrupt-on-overflow occurs 1000 microseconds later
TMR1L = PRELOAD_HIGH; // for microprocessor clock crystal 40MHz/4 = 10MHz tick rate = 65535 - 10000 (0xD8EF)
}
/*******************************************************************************
* FUNCTION NAME: Timer_1_Int_Handler
* PURPOSE: Updates the real time clock variables
* CALLED FROM: user_routines_fast.c
* ARGUMENTS: none
* RETURNS: real-time clock variables are updated
*******************************************************************************/
void Timer_1_Int_Handler(void)
{
// update the millisecond-counter
// probably will be more useful than the msec/sec/min/hours/days variables
// avoid calling a function from within the Interrupt handler, other register
// context will need to be saved with a #pragma in user_routines_fast.c
// Timer_1_Load_Prescale();
TMR1H = PRELOAD_LOW; // reload the timer so that the interrupt-on-overflow occurs 1000 microseconds later
TMR1L = PRELOAD_HIGH; // for microprocessor clock crystal 40MHz/4 = 10MHz tick rate = 65535 - 10000 (0xD8EF)
timer_msecClock++;
timer_milliseconds++;
if (timer_milliseconds > 999)
{
timer_milliseconds = 0;
if (++timer_seconds > 59)
{
timer_seconds = 0;
if(++timer_minutes > 59)
{
timer_minutes = 0;
timer_hours++;
}
}
}
if ((timer_milliseconds % 100) == 0)
timer_100msec++;
}
/***********************************************************************************
* FUNCTION NAME: Timer_1_Microseconds
* PURPOSE: fetch the number of microseconds since the timer last interrupted
* CALLED FROM: user_routines.c
* ARGUMENTS: none
* RETURNS: microseconds since the last interrupt
***********************************************************************************/
unsigned int Timer_1_Microseconds(void)
{
unsigned int tmr1;
// NOTE: Timer specification requires MUST read low byte
// first, then high byte
tmr1 = (unsigned int) TMR1L + ((unsigned int) TMR1H << 8); // convert to 16-bit, then negate
tmr1 = ~tmr1 + 1; // (2's complement) to get remaining ticks until overflow
// scale to the clock frequency - see Timer_1_Load_Prescale() comments for the number
// of ticks per microsecond
return (tmr1 / 10);
}
/***********************************************************************************
* FUNCTION NAME: Timer_1_MicrosecondsTimestamp
* PURPOSE: fetch a timestamp which includes the number of microseconds
* CALLED FROM: user_routines.c
* ARGUMENTS: none
* RETURNS: microseconds since the last interrupt
***********************************************************************************/
unsigned long Timer_1_MicrosecondsTimestamp(void)
{
// WARNING: this is quite expensive to call, probably not very useful
return (timer_msecClock * 1000) + (unsigned long) Timer_1_Microseconds();
}
/*******************************************************************************
* FUNCTION NAME: Timer_1_Initialize
* PURPOSE: configure the Timer1 interrupt to overflow and interrupt after
* 1000 microseconds
* CALLED FROM: user_routines.c
* ARGUMENTS: none
* RETURNS: Timer1 is configured and TMR1IF interrupt enabled
*******************************************************************************/
void Timer_1_Initialize(void)
{
T1CONbits.TMR1ON = 0; // disable the clock while programming it
T1CONbits.TMR1CS = 0; // use internal clock (10 MHz)
T1CONbits.T1CKPS0 = 0; // set prescaler to 1:1, or OSC/4. A 40 MHz crystal divided by 4 gives 10 ticks per microsecond.
T1CONbits.T1CKPS1 = 0;
T1CONbits.RD16 = 0; // read timer using two 8-bit reads of TMR1L followed by TMR1H
// reading the timer and subtracting it's value from FFFFh gives the number of microseconds
// since the timer was last loaded
Timer_1_Load_Prescale();
Timer_1_Reset(); // reset time variables
T1CONbits.TMR1ON = 1; // enable the clock
PIE1bits.TMR1IE = 1; // enable the Timer1 overflow interrupt
}
/*******************************************************************************
* FUNCTION NAME: Timer_1_ReadTimeStruct
* PURPOSE: safely read the time values without disturbance from the
* interrupt service routines
* CALLED FROM: user_routines.c
* ARGUMENTS: none
* RETURNS: pointer to WallTime structure
*******************************************************************************/
void Timer_1_ReadTimeStruct(WallTime * wTime)
{
int intEnabled;
intEnabled = PIE1bits.TMR1IE; // disable timer interrupts while loading structure
if (intEnabled != 0)
PIE1bits.TMR1IE = 0; // disable the Timer1 overflow interrupt
wTime->hours = timer_hours;
wTime->minutes = timer_minutes;
wTime->seconds = timer_seconds;
wTime->msec = timer_milliseconds;
wTime->usec = Timer_1_Microseconds();
wTime->timestamp = Timer_1_MicrosecondsTimestamp();
if (intEnabled != 0)
PIE1bits.TMR1IE = 1; // enable the Timer1 overflow interrupt
}
Add this to the InterruptHandlerLow() routine in user_routines_fast.c Code:
if (PIR1bits.TMR1IF && PIE1bits.TMR1IE) // wallclock.c timer interrupt?
{
PIR1bits.TMR1IF = 0; // clear the interrupt flag
Timer_1_Int_Handler();
}
|
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| 10 ball auto mode | nuggetsyl | Scouting | 22 | 27-02-2006 20:39 |
| Sending variables to Auto Mode | Adrien | Programming | 4 | 19-02-2006 21:51 |
| auto mode | nuggetsyl | General Forum | 12 | 13-02-2006 19:45 |
| Auto mode help..... | Moloch | Programming | 2 | 18-02-2005 09:18 |
| Auto. mode!!! | skitz547 | Rules/Strategy | 1 | 09-03-2003 22:37 |