Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   Copy Cat (http://www.chiefdelphi.com/forums/showthread.php?t=33511)

Meandmyself 27-01-2005 21:35

Copy Cat
 
I haven't seen any threads about copycat in a while, so I figure I'll share what I know. My team used a simplified version of copycat for the past two years as a backup to the code we couldn't get working. It's quite simple.
The idea is that you push a button in user control mode, then it writes to EEPROM the values you send to your motors. In autonomous mode, you play back the recording and that's your autonomous mode.

put this in your user_routines.c()
Code:

void storemotors(void)
{
        static char lr = 0;

        if (lr==0)                                                //alternate writing lmotor & rmotor
        {
                writeEE(address, lmotor);                //writes the motor value to EEPROM
                lr=1;
        }else
        {
                writeEE(address, rmotor);
                lr=0;
        }//endif
        address++;                                        //increments address

}//end storemotors





char readEE(unsigned short address) {

// Load address into address register
EEADRH = ((address>>8)&0x03);  //Bits 2-7 are masked off since EEPROM is only 1KB
EEADR =(address&0xFF);

//Configuration as per manual
EECON1bits.EEPGD =0;
EECON1bits.CFGS =0;
EECON1bits.RD =1;


return EEDATA;
}

void writeEE(unsigned short address, char data)
{
EEADRH = ((address>>8)&0x03);
EEADR =(address&0xFF);
EEDATA = data;

//Configuration as per manual
EECON1bits.EEPGD =0;
EECON1bits.CFGS =0;
EECON1bits.WREN =1;
INTCONbits.GIE = 0;
EECON2 = 0x55;
EECON2 = 0xAA;
EECON1bits.WR = 1;
INTCONbits.GIE = 1;
EECON1bits.WREN = 0;
}

put this in your user_routines_fast()
Code:

void readmotors(void)
{
        static char lr = 0;

        if (lr == 0)
        {
                lmotor = readEE(address2);
                lr = 1;
        }else
        {
                rmotor = readEE(address2);
                lr=0;
        }//endif

        address2++;

}//end readmotors

address and address2 are unsigned shorts defined in user_routines.c and _fast.c respectively. lmotor is the pwm you used for your left motor and rmotor is the address you used for your right motor.
you can alias lmotor and rmotor like this:
Code:

#define lmotor pwm01
#define rmotor pwm02

that should save you some cutting and pasting.

you call storemotors() so long as a certain button, like p1_sw_top, is pushed. That way, as long as the button is pushed, you're recording the data you send to the motors. call storemotors() only once you're done processing data and are ready to send it to the pwms.
like this:
Code:

        if (writebutton && (address <= 1023)) {storemotors();}               
//stores data in EEPROM for recall in auto mode

you call readmotors() in user_autonomous_code(). It reads out data from the EEPROM directly into the motors.
like this:
Code:

if (address2 <= 1023) {readmotors();}                //reads data from EEPROM to motors
else {lmotor = rmotor = 127;}

that's it. simple. The only problem you might run into is that it takes a while to write to the EEPROM. If you try to write two bits of data right after the other, it won't write the second bit. This is why I only write one motor per cycle. It definitely took me a while to figure that one out.

This is a really simplified version. It can only record one autonomous mode. The 1023 bytes of space should definitely allow you fifteen seconds of recording time. If not, you can always call storemotors and readmotors every other loop. My goal here is to help you understand copycat, not to provide you with the most function.

this code has not been tested on the new compiler, so if there's a big problem please tell me.

Please post if you have questions! If you have better versions of copycat please share, and explain too!

Sachiel7 27-01-2005 22:34

Re: Copy Cat
 
Heh, its interesting to see where my CopyCat project has gone over the years :P
I'm glad that people are still trying to keep it alive!
Combined with the PID this year it could be pretty effective... :rolleyes:

ConKbot of Doom 28-01-2005 09:02

Re: Copy Cat
 
Do storemotors() and readmotors() execute once every long long loop (26.2 ms) or every short loop? I'm still a bit confused to those and it would seem like and awful waste of space to do it more than every 26.2ms.

But either way, does this ever have ideas brewing in my head. :D

EDIT: misunderstanding about the loops, got it all sorted out now.

Meandmyself 28-01-2005 12:35

Re: Copy Cat
 
Quote:

Originally Posted by ConKbot of Doom
Do storemotors() and readmotors() execute once every long long loop (26.2 ms) or every short loop? I'm still a bit confused to those and it would seem like and awful waste of space to do it more than every 26.2ms.

But either way, does this ever have ideas brewing in my head. :D


Either way. so long as it's the same for both. I do it every long loop because that's when you have new data. readmotors is in _fast because that's where use_autonomous_mode is.

Meandmyself 28-01-2005 12:39

Re: Copy Cat
 
Quote:

Originally Posted by Sachiel7
Heh, its interesting to see where my CopyCat project has gone over the years :P
I'm glad that people are still trying to keep it alive!
Combined with the PID this year it could be pretty effective... :rolleyes:


It works really well as a backup because it's so simple. I programmed this in an hour while watching Austin Powers. If you have a fairly simple (and not precise) autonomous strategy in mind.

russell 08-02-2005 02:30

Re: Copy Cat
 
Hmmm. I just tried to compile it and I got a bunch of errors.....

Quote:

Originally Posted by MPLAB
D:\Code\Copy Cat v1\user_routines.c:116:Error [1105] symbol 'address' has not been defined
D:\Code\Copy Cat v1\user_routines.c:116:Warning [2058] call of function without prototype
D:\Code\Copy Cat v1\user_routines.c:120:Error [1105] symbol 'address' has not been defined
D:\Code\Copy Cat v1\user_routines.c:120:Warning [2058] call of function without prototype
D:\Code\Copy Cat v1\user_routines.c:123:Error [1105] symbol 'address' has not been defined
D:\Code\Copy Cat v1\user_routines.c:123:Error [1101] lvalue required
D:\Code\Copy Cat v1\user_routines.c:146:Error [1109] type mismatch in redeclaration of 'writeEE'
D:\Code\Copy Cat v1\user_routines.c:311:Error [1105] symbol 'address' has not been defined

what does that mean?

Mike Betts 08-02-2005 03:15

Re: Copy Cat
 
Quote:

Originally Posted by russell
...what does that mean?

Please show your variable declaration for "address" and I'll be able to tell you what the problem is.

russell 08-02-2005 11:03

Re: Copy Cat
 
AHA! You found the problem! I left adress as adress. I take it I am supposed to either change it or declare it as a variable?

Greg Ross 08-02-2005 11:06

Re: Copy Cat
 
Quote:

Originally Posted by russell
Hmmm. I just tried to compile it and I got a bunch of errors.....


what does that mean?

It looks like you didn't follow ALL the instructions:
Quote:

Originally Posted by Meandmyself
address and address2 are unsigned shorts defined in user_routines.c and _fast.c respectively.

Try reading the whole post carefully. :rolleyes:

FWIW, the lines should probably be something like:
Code:

unsigned short address; // In user_routines.c
        and
unsigned short address2; // In user_routines_fast.c

Actually, since I didn't see anywhere in the code snippets where the address variables are initialized, that should be:
Code:

unsigned short address = 0; // In user_routines.c
        and
unsigned short address2 = 0; // In user_routines_fast.c

And assuming that these variables don't need to be used outside of these modules, I would make them:
Code:

static unsigned short address = 0; // In user_routines.c
        and
static unsigned short address2 = 0; // In user_routines_fast.c

Further, it looks to me like these address variables aren't needed outside of the storemotors and readmotors functions so, IMHO, these variable declarations should be moved inside their respective functions. E.g.:
Code:

void storemotors(void)
{
        static unsigned short address = 0;
        static char lr = 0;

        if (lr==0)                        //alternate writing lmotor & rmotor
        etc.
}//end storemotors


slickguy2007 08-02-2005 12:20

Re: Copy Cat
 
Our programmer figured the out copy cat program last year, but due to his hard work he doesn't want me to share. From what I have seen some of you pretty close. Good luck to everyone trying and happy programming!


GO 1403!!!

Meandmyself 06-03-2005 17:05

Re: Copy Cat
 
THIS IS NOT MEANT TO BE COMPLETE CODE!!

of course you have to define these variables. you also have to prototype these functions, but I'm not your team's programmer, so I'm going to let you figure that part out.

Thanks, though, for pointing out where my code has holes. I didn't actually use copycat this year, so I did not compile an actual working version.

thinkpad 12-03-2005 00:16

Re: Copy Cat
 
Hey,

After spending months on a PID control without a lot of success, i believe we will have to develop Copy Cat as a backup. Since we are a newbie team we have no experience with this at all so I would request to know the ins and outs of these controls, and the things to keep in mind before using it. Is it controlled using a joystick when its getting recorded? and How many motors does it record, meaning will it record the movements of the arm or only the mobility?

Having less than a week to get this to work we are in a state of urgency, any assistance is highly appreciated.

Thanks.

Meandmyself 12-03-2005 13:13

Re: Copy Cat
 
Quote:

Originally Posted by thinkpad
Hey,

Is it controlled using a joystick when its getting recorded?


while recording, it's controlled in the same way you control it while driving. The way you record is to call the function storemotors while you are actually driving the bot. you don't want to call it all the time, though, because every time you call it it messes up whatever you've already got recorded.
Quote:

Originally Posted by Meandmyself
you call storemotors() so long as a certain button, like p1_sw_top, is pushed. That way, as long as the button is pushed, you're recording the data you send to the motors. call storemotors() only once you're done processing data and are ready to send it to the pwms.

Quote:

Originally Posted by thinkpad
and How many motors does it record, meaning will it record the movements of the arm or only the mobility?


You can record as many motors as you want. You just have to watch out because the more motor values you want to record simultaneously, the less accurate your playback will be. There's a simple way to get around this. Let me illustrate:

Suppose I want to control the motion of an arm moving up and down, and suppose I am controlling said arm with a PWM, however the only values I ever send to this arm are 0,127, and 254. I can do this two ways:
1) every third loop I record the value I'm sending to the arm. This is interspersed with the recording of the left and right motors, so that the left motor is stored every third loop and the right motor is stored every third loop.
Code:

void storemotors(void)
{
        static char lr = 0;

        switch (lr)                                                //alternate writing lmotor & rmotor
        case 0:
            {
                writeEE(address, lmotor);                //writes the motor value to EEPROM
                lr=1; break;
        }
            case 1:
        {
                writeEE(address, rmotor);
                lr=2; break;
        }
            case 2:
            {
                        writeEE(address, armmotor);          //writes arm motor value to EEPROM
                        lr = 0; break;
            }
        address++;                                        //increments address

}//end storemotors

and you do the same sort of thing in Readmotors to get the values out.

2)since the PWM value 255 is never sent to the motors, you can use 255 as a marker to tell the autonomous mode, "Hey! Arm going up now!" you would also need another unused pwm value to tell the autonomous that the arm is going down. When my team wrote our drive code, we had a little "dead zone" in the middle of the joystick's range, so that if the joystick was in between 117 and 137 the motor was set to 127. this gave us a whole bunch of unused pwm values.
Code:

void storemotors(void)
{
        static char lr = 0;
        static char armupordown = 0;
           

        if(armmotor== 254 && armupordown != 1)  //if the arm is going up and the arm wasn't going up last loop
        {
                writeEE(address, unused pwm value 1);  //stores motor going up marker
                armupordown = 1; //the arm just started going up
        }else if(armmotor == 127 && armupordown != 0) //if the arm has stopped moving and has just this loop stopped moving
        {
                writeEE(address, unused pwm value 2);  //motor stopped marker
                armupordown = 0;
        }else if (armmotor == 0 && armupordown != -1) //if arm just this loop started going down
        {
                writeEE(address, unused pwm value 3);  // motor going down marker
                armupordown= -1;
        }else if (lr==0)                                                //alternate writing lmotor & rmotor
        {
                writeEE(address, lmotor);                //writes the motor value to EEPROM
                lr=1;
        }else
        {
                writeEE(address, rmotor);
                lr=0;
        }//endif
        address++;                                        //increments address

}//end storemotors

and then of course somthing similar in readmotors to recognize the markers.

Hope this helps. Ask as many questions as you like.

thinkpad 12-03-2005 20:19

Re: Copy Cat
 
Thank you very much for this valuable information, this makes it clearer.

Another, question, do the recorded values remain on the memory after the robot has been switched ON/OFF or Robot Reset is used, meaning is the same record of joystick control on the EEPROM repeatable from game to game or do we have to record every time we want to run autonomous?

Thanks again for sharing your expertise on the topic,
Vick.

Meandmyself 13-03-2005 12:09

Re: Copy Cat
 
Quote:

Originally Posted by thinkpad
Thank you very much for this valuable information, this makes it clearer.

Another, question, do the recorded values remain on the memory after the robot has been switched ON/OFF or Robot Reset is used, meaning is the same record of joystick control on the EEPROM repeatable from game to game or do we have to record every time we want to run autonomous?

Thanks again for sharing your expertise on the topic,
Vick.


The recorded memory remains in EEPROM even after you switch the robot off. It wouldn't be very useful if it was erased every time you turned the robot on, would it? Watch out, though, because every time you download new code to the RC it erases any stored EEPROM memory, including your recorded autonomous!!!
Be very careful about making changes to your code if you don't have time to re-record your autonomous.


All times are GMT -5. The time now is 11:05.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi