very basic code help

Team 1771’s only programmer last year was a senior, and now he is gone. Myself and one other teammate are trying to learn how to program in time for next season.

We just got windriver installed on our team laptop and are still figuring out how to use it. No one on our team currently knows how to use it.

We both have very basic C++ skills.

We downloaded the basic starter code supplied by FIRST.

We can currently do teleop tank drive with 2 joysticks and an autonomous that goes straight forward without stopping.

Can anyone point me toward some resources for learning about windriver and about controlling basic functions of the robot, or just walk me through?

The FRC C/C++ Users Guide is a good starting point. It should be included in the windriver install (IIRC, c:\windriver\docs), otherwise it should be available from http://usfirst.org/roboticsprograms/frc/content.aspx?id=14532.

Start there then when you have specific issues/question come back and I’m sure someone here will help.

Thanks for the help, but now we have a more specific question.

We are experimenting with autonomous and we have this code

void Autonomous(void) 
{
	GetWatchdog().SetEnabled(false);
	myRobot.Drive(0.5,0.5);
}

we dont really know what GetWatchdog is, we know that the sample code has it.

What we have so far makes it drive straight at half speed indefinitely as far as we can tell. We looked at RobotDrive.cpp and .h in the WPILib but we cant figure out how to end the .drive command and move on to the next line.

NOTE: Some of the function/class/template names have changed since I began working with this, so I may accidentally use a old name.

The watchdog is a safety feature. When enabled, you call Feed(Timeout) where Timeout is the amount of time before the robot will be disabled. If you call Feed again within the timeout period the robot continues normally. If you don’t all outputs are disabled.

When you are debugging you will often disable the watchdog.

The myRobot.Drive() function sets a speed, and continues at that speed until told otherwise.

If you are using the Simple robot template you just insert a delay (I believe there is a Wait() function in there somewhere), then call Drive again.

If you are using the Itterative robot template you have a little more work todo. Essentially you would create a state machine using the number of itterations and/or sensor inputs to move between states (forward until hit wall, left turn 90 degree, ect.).

Thanks for all the help so far. One more question.
We are using the simple robot template, and as far as I can tell, everything is right, but it wont build.

#include "WPILib.h"

RobotDrive myRobot(1,2);
Joystick leftStick(1);
Joystick rightStick(2);
class RobotDemo : public SimpleRobot 
{
	RobotDemo(void)
	{
		GetWatchdog().SetEnabled(false);
	}

	void Autonomous(void) 
	{
		GetWatchdog().SetEnabled(false);
		while(1)
		{
			for(int i = 0; i < 4; i++)
			{
				myRobot.TankDrive(0.5,-0.5);
				Wait(4);
				myRobot.TankDrive(0.5,0.5);
				Wait(2);
			}
			myRobot.TankDrive(0.0,0.0);
			Wait(4);
		}
	}
	
	void OperatorControl(void) 
	{
		while(1)
		{
			GetWatchdog().SetEnabled(false);
			while (IsOperatorControl()) 
			{
				myRobot.TankDrive(leftStick, rightStick);
				Wait(0.005);
			}
		}
	}
};
START_ROBOT_CLASS(RobotDemo);

we get the following errors at build:
“RobotDemo::RobotDemo()’ is private” in reference to line 7
and
a nonspecific error at the very last line.

Can you tell what I need to do to fix it?

Your compiler is complaining because the START_ROBOT_CLASS macro attempts to instantiate an instance of your RobotDemo class. In order to instantiate a class, the class’ constructor is called. You have a constructor for your RobotDemo class, but it is declared “private” by default. This means that outside entities (like the START_ROBOT_CLASS macro) cannot call the constructor, hence the error you are seeing. To fix the behavior, your constructor (and all of the other functions required to implement a SimpleRobot, like Autonomous and OperatorControl) need to be declared as “public”.

To do this:


class RobotDemo : public SimpleRobot 
{
public:
	RobotDemo(void)
	{
		...
	};

        ... the rest of your functions here
};
START_ROBOT_CLASS(RobotDemo);

I believe that’s the only error that prevents this code from compiling (although without trying to compile it myself I may have missed something).

Oh ok, thanks. I saw that when i was reading a fragment of last years code that was left on the desktop of the laptop we use, but i didnt think we needed it because it wasn’t included in the FIRST supplied code.
I cant test it now because im at home, but im pretty sure it will work.
thanks.

you should also put the Joystics and RobotDrive inside the class (and move the constructors for them, you SHOULD use the watchdog (unless debugging), and you have infinite loops (and auto is longer than 15 seconds, but i am assuming it is not for a real competition):

#include "WPILib.h"

class RobotDemo : public SimpleRobot 
{

**RobotDrive myRobot;
Joystick leftStick;
Joystick rightStick;
public:**
	RobotDemo()**:myRobot(1,2), leftStick(1), rightStick(2)//need to put them here**
	{
		**//GetWatchdog().SetEnabled(false); dont need to do this here**
	}

	void Autonomous() 
	{
		GetWatchdog().SetEnabled(false);
		**//while(1)
		//{**
			for(int i = 0; i < 4; i++)
			{
				myRobot.TankDrive(0.5,-0.5);
				Wait(4);
				myRobot.TankDrive(0.5,0.5);
				Wait(2);
			}
			myRobot.TankDrive(0.0,0.0);
			Wait(4);
		**//}**
	}
	
	void OperatorControl() 
	{
		**//while(1) and you should use while(true) in C++, while(1) is so C
		//{**
			GetWatchdog().SetEnabled(**true**);
			while (IsOperatorControl()) 
			{
				**GetWatchdog().Feed();**
				myRobot.TankDrive(leftStick, rightStick);
				Wait(0.005);
			}
		**//}**
	}
};
START_ROBOT_CLASS(RobotDemo);

Just so nobody gets confused, while these suggestions are certainly reflective of good practice and may reflect the actual coder’s intent, they aren’t strictly necessary for your code to compile and work (work as in not crash as opposed to exactly what you want it to do).

while (IsOperatorControl()) 
			{
				GetWatchdog().Feed();
				myRobot.TankDrive(leftStick, rightStick);
				Wait(0.005);
			}

Is the while(IsOperatorControl()) line really necessary? because all of the code inside it is inside the teleop section of the code anyway.

And what is the difference between putting the RobotDrive and the Joysticks inside the class and moving the constructors as opposed to how i had it?

Hey, I am the other programmer working on this.

We have another problem also.

During our tele-op period, it runs our autonomous code!

Any idea as to why this could be?

At first it worked fine, then when we ran it again, it started doing autonomous in teleop, and wouldn’t accept any input from us.

I changed the battery and did a power cycle, and that fixed it; once. After I ran it again in teleop, it went back to doing autonomous.

Any idea?

you need to remove the infinite loops, the while(1) like i said above

Yes, but remove the while(1) around that, because if you dont, it will do it once and exit. the function is called and not called again untill it switches state, so if it stays there, then your program stays there

Ok, thank you.

But what about the constructors for the Joystick and RobotDrive? Why does it make a difference wether or not they are inside the class. It compiles fine either way.

In general, it is best practice to encapsulate the state of a class (i.e. the joysticks and RobotDrive) within the class. This allows you to create multiple instances of the class safely.

It also makes it easier to debug and modify since if they are contained within the class no other objects have direct access to them.

In this case it shouldn’t matter since you should only ever have a single instance of the robot class. However it is still best practice.

Thanks for all the help. I’m sure i’ll be back with a lot more questions after i get some more time with the robot on tuesday.

I’ve reproduced the running-Autonomous-forever problem (and thanks to Gunderson/2643 for the loan of their control system).

The problem is that Autonomous() never exits, it sits in the while(1) loop forever. Autonomous() gets called only once - ref: WPI’s C/C++ Programming Guide for the First Robotics Competition http://first.wpi.edu/FRC/frcupdates.html => C/C++ Programming Guide.

Even removing the while(1) the Auton routine runs 28 seconds: 4*(2+4) and 4 more at the end. I’m sure you know this; the problem is that it’s completely blind to Auton mode ending until that 28 seconds is over. In a match, if Teleop mode were to start within that 28 seconds, the 'bot would continue its Auton behaviour until the 28 seconds had lapsed.

I’ve taken the liberty of fixing this and adding some comments that I hope will explain how, feel free to post questions. It’s tested and works. And, congratulations on taking the plunge into C++ programming!

Gary


#include "WPILib.h"

// if we put the important constants here, they're
// easy to find!
#define WAIT_INTERVAL          0.1 // 0.1 sec = 10 milliseconds
#define DRIVE1_INTERVAL_TENTHS 40  // 40 * 0.1 = 4 seconds
#define DRIVE2_INTERVAL_TENTHS 20  // 2 seconds
#define AUTON_LOOPS             4  // our autonomous loop runs this many times

RobotDrive myRobot(1,2); // motors are driven by PWMs 1 and 2
Joystick leftStick(1);   // left joystick is in USB 1 of the Drivers Station
Joystick rightStick(2);  // and right JS is in USB 2 of the DS

class RobotDemo : public SimpleRobot 
{
public:
	RobotDemo(void) // this function is called only once,
	                // when the 'bot powers on or is reset.
	{
		GetWatchdog().SetEnabled(false); // disable the WDT
	}

	void Autonomous(void) // this function is called only once,
				       // when auton mode is enabled. It's NOT
	                               // called repeatedly.
	
	{  int j; // oldSchool programmers declare variables here :-)
	
		GetWatchdog().SetEnabled(false);
		
		// drive our 'bot four times (AUTON_LOOPS) of two legs each:
			for(int i = 0; i < AUTON_LOOPS; i++)
			{
				myRobot.TankDrive(0.5,-0.5); // start driving, half power (straight? turning?)
				
/* when we call Wait() the program is "blind" to any changes - eg, if Auton mode ends,
 * we can't check this 'till the wait is over. If we were to code Wait(100), for example,
 * the program would obligingly hang for 100 seconds. It couldn't interpret the joysticks,
 * test if Auton mode had ended, etc. The motors would just keep doing what they were
 * doing for those 100 seconds. The only thing that would override this is the disable switch
 * or the equivalent of the Field Control System during a match. The FCS is going to kill
 * the motors after Auton ends and before Teleop begins, but if Teleop began during that
 * 100 second interval, the 'bot would merrily resume doing what it had been doing and ignore
 * the joysticks. 
 * 
 * Until our code exits Autonomous(), OperatorControl() can't begin.
 * 
 * we're going to handle this problem by decreasing the wait to 100 msec. after
 * each 100 msec we're going to check to see if Auton mode is over, or we've looped
 * long enough time to allow the motors to drive the time interval we want.
 * 
 * why 100 msec? why not? the worst we're going to loose is the first 0.1 second
 * of Teleop mode, and no matter how much sugar, caffeine, and adrenaline the drivers
 * are on, it's going to take them that long just to get to the controls.
 * 
 * this isn't a particularly sophisticated way to do this, **but it works**. programmers
 * with more experience may want to look into state machines to do this in a more
 * structured and flexible manner.
 */
				
				// loop as long as j < DRIVE_INTERVAL_TENTHS *AND* we're in auton mode:
				for (j=0; (j < DRIVE1_INTERVAL_TENTHS) && IsAutonomous(); j++)
					{
					 Wait(WAIT_INTERVAL);
					}
				
				myRobot.TankDrive(0.5,0.5); // start driving (turning? straight?)
				
				// as above, keep driving 'till our interval is over, or auton ends:
				for (j=0; (j < DRIVE2_INTERVAL_TENTHS) && IsAutonomous(); j++)
						{
						 Wait(WAIT_INTERVAL);
						}
			} // outer for loop
			myRobot.TankDrive(0.0,0.0); // done, stop the 'bot
			
			
	} // Autonomous()
	
	void OperatorControl(void) // this function is called only once,
							   // when teleop mode begins. It's NOT
							   // called repeatedly.
							   
	{
			GetWatchdog().SetEnabled(false);
			
			while (IsOperatorControl()) // keep looping as long as in teleop mode.
			{
				myRobot.TankDrive(leftStick, rightStick);
				Wait(0.005);
			} // while operator control is true
		
	} // OperatorControl()
};
START_ROBOT_CLASS(RobotDemo);



Wow, thank you so much!

That REALLY explains why we have been having so much frustration, having to power cycle the bot to switch to tele-op! Haha.

Now, I have a very specific question for WindRiver…

How do you change what code is being built and downloaded onto the robot?

We just recently got the code from our Lunacy bot, and are trying to tinker with it on our bot. However, in WindRiver, it is only compiling the code we wrote, and not building the .out file to go onto the robot.

Basically, how do we switch what file we want to build and work on?

Hi, NF:

I’m not sure if you mean:

a) How to load your Lunacy code into WRW so you can work on it, download, etc.
b) You have the Lunacy code in WRW and are working on it, but WRW isn’t finding the right *.out file with which to download.

I’ll go through both these as we’ve got a lot of hits on this ChiefDelphi thread.

First of all, please backup your hard-earned Auton code we’ve all been working on. There’s a good way to do this, please get into the habit:

In WRW, click on your Auton project in the upper left Project Explorer panel, then do Project => Build Project. This will write any modified files to disc. Then, Project => Clean, “Clean Projects Selected Below”, and check your project, leave “Start a new build immediately” off, OK. This will remove some temp files you don’t care about.

Exit WRW.

Go to My Computer => C:\WindRiver\workspace. You should see a directory (folder) with the name of your project. If in doubt, click on one, open the *.cpp file with Notepad, and satisfy yourself that it’s the project in question.

In C:\WindRiver\workspace, right-click on that folder and select “Send to compressed (zipped) folder”. You’ll get a .zip folder as a result. Click on it and rename it something meaningful. Mine is “BuiltinDefaultCode.zip” and I’ll rename it “BuiltinDefaultCode20090910AutonWorks.zip”.

Right-click on that renamed .zip, Properties, Read-only, OK.

Plug in a USB drive and right-click on that .zip, Send to => Removable Disc. Or, burn it on a CD. Or, email it to your gmail. Somehow, MOVE A COPY OFF YOUR COMPUTER. Now, no matter how bad it gets, you have a copy of that project.

Now, I’m going to assume your Lunacy code is a whole folder like we worked on above. If not, skip down after the following prose.

If WRW is running, exit it.
Put the Lunacy code folder under that same folder, C:\WindRiver\workspace. Maybe it’s the same name as an existing folder, rename it to “Lunacy” or something else meaningful.

Start WRW. File => Import => Existing Projects Into Workspace, Next. Select Root Directory, Browse, find that folder, OK, Finish.

Now in the upper left WRW “Project Explorer” panel you should see that new project. Click on it and in the center panel, click on the .cpp tab and you should see the Lunacy source code. Project => Build Project and see if it compiles.

(If you have just the Lunacy .cpp file, with WRW not running go to the
workspace\ folder, copy and paste an existing project folder. Rename it to Lunacy, open it, and replace the .cpp file with your Lunacy cpp file. (This is hacky but I don’t know a better way to do it, does anyone else?) Then, start WRW and go to the Import step above and see if you get your Lunacy cpp file. If not, let us know. Sneaking files around this way isn’t the best way to do it.)

But, we’re not done, and we’re on to b), telling WRW which file to download to the 'bot. WRW doesn’t seem to understand it should find this file automatically, maybe the 2010 season version will. In WRW, click on your Lunacy project in the project-explorer panel, and do a build. Make sure it compiles cleanly because that’s the only way to get a .out file.

In WRW: Window => Preferences => First Downloader Preferences. First of all, make sure your team number is correct. Now, you have to find the location of the .out file. Mine is (ready?):

C:\WindRiver\workspace\BuiltinDefaultCode\PPC603gnu\BuiltinDefaultCode\Debug\BuiltinDefaultCode.out

Find the corresponding .out file that matches your project, OK.

If you aren’t sure or it doesn’t work, do this:

My Computer => C:\WindRiver and right-click the workspace folder => Search. Say:

*.out

in the “All or Part of the Filename” box, Search. (wait). You should have list with one or more files. Click on the Date Modified heading and it will sort it by age. Find the one with the timestamp that matches the WRW build you did. In the WRW First Downloader Preferences window, browse to that file, OK.

After all this, WRW FIRST => Download and it should download because you already have this working. Now, you’re in business.

As long as you (and everybody lurking) are still reading, please do this as a good practice. At the very bottom of your new source code, after the
START_ROBOT_CLASS(); call, paste in this paragraph:


#if 0

2009 09 10 Nightfighter
Imported the Lunacy code from 2009 season. Compiles and downloads.

TO DO:

Learn C++.
Wait for Kickoff.
Build the robot.
Win the Chairman's award.
#endif

This is a region where you can enter free-form text, I don’t want to explain the #if 0 stuff now. At the end of the day, or after making major code changes, WHICHEVER COMES FIRST, do the Project => Build Project, Project => Clean, exit WRW, zip, rename, read-only, and write it it to your USB drive or get it off that computer somehow. If it’s the end of the day and you have 89 syntax errors, just say you have 89 syntax errors in that text, Project => Clean, and do the rest. If you’ve made lots of changes but they’re not tested yet, or you’ve found bugs, write in the TO DO section something meaningful to this effect.

If you have a bad day and stuff that used to work doesn’t, you can go back to one of the .zip folders and just start from there, it may be simpler than trying to figure out what went wrong and try to back all the changes out.

These good practices, like the backups, using #defines, and adding comments, will save you time in the long run and especially if more than one programmer is working on the source. Please get in the habit now.

Gary

Hey, thanks a bunch!

We are going to our last competition before retiring our Lunacy Bot, and the only people attending are me and 2 others! :eek:

I think it will be great coding practice, as well as driving practice for us!

Thanks for all the help garyk.

Tomorrow when I get access to the bot, I have another question to ask you. :smiley: