CODE PROBLEM - 4 bumper / 1 limit auton selections ...

Hi everyone, i have attached some code, this is designed to select 8 different autonomous routines from 4 bumpers and 1 limit switch … is there something i have done massively wrong as when i put code into it, it doesn’t work

thanks
Liam Grazier

#pragma config(UART_Usage, UART2, uartNotUsed, baudRate4800, IOPins, None, None)
#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, in1,    pot1,           sensorPotentiometer)
#pragma config(Sensor, dgtl1,  auton1,         sensorTouch)
#pragma config(Sensor, dgtl2,  auton2,         sensorTouch)
#pragma config(Sensor, dgtl3,  auton3,         sensorTouch)
#pragma config(Sensor, dgtl4,  auton4,         sensorTouch)
#pragma config(Sensor, dgtl5,  set,            sensorTouch)
#pragma config(Sensor, dgtl12, tester,         sensorTouch)
#pragma config(Sensor, I2C_1,  encoder1,       sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Sensor, I2C_2,  encoder2,       sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Motor,  port1,           frontleftmotor, tmotorVex393, openLoop, reversed, encoder, encoderPort, None, 1000)
#pragma config(Motor,  port2,           backleftmotor, tmotorVex393, openLoop, encoder, encoderPort, I2C_1, 1000)
#pragma config(Motor,  port3,           backrightmotor, tmotorVex393, openLoop, reversed)
#pragma config(Motor,  port4,           leftlift,      tmotorVex393, openLoop)
#pragma config(Motor,  port5,           rightlift,     tmotorVex393, openLoop, reversed)
#pragma config(Motor,  port6,           leftintake,    tmotorVex393, openLoop, encoder, encoderPort, I2C_2, 1000)
#pragma config(Motor,  port7,           rightintake,   tmotorVex393, openLoop, reversed)
#pragma config(Motor,  port8,           hanging1,      tmotorVex393, openLoop, reversed)
#pragma config(Motor,  port9,           hanging2,      tmotorVex393, openLoop)
#pragma config(Motor,  port10,          frontrightmotor, tmotorVex393, openLoop, reversed, encoder, encoderPort, None, 1000)
#pragma platform(VEX)

//Competition Control and Duration Settings
#pragma competitionControl(Competition)
#pragma autonomousDuration(15)
#pragma userControlDuration(105)

#include "Vex_Competition_Includes.c"   //Main competition background code...do not modify!

void pre_auton()
{
  bStopTasksBetweenModes = true;
}
task autonomous()
{
	int con1=0;
	int con2=0;
  int con3=0;
  int con4=0;
  int con5=0;
  int con6=0;
  int con7=0;
  int con8=0;
  
   if(SensorValue[auton1] == 1 && SensorValue[set] == 0)
  {
  	con1 = 1;
  }
  if(SensorValue[auton2] == 1 && SensorValue[set] == 0)
  {
  	con3 = 1;
  }
  if(SensorValue[auton3] == 1 && SensorValue[set] == 0)
  {
  	con5 = 1;
  }
  if(SensorValue[auton4] == 1 && SensorValue[set] == 0)
  {
  	con7 = 1;
  }
  if(SensorValue[set] == 1 && SensorValue[auton1] == 1)
  {
  	con2 = 1;
  }
  if(SensorValue[set] == 1 && SensorValue[auton2] == 1)
	{
	  con4 = 1;
	}
if(SensorValue[set] == 1 && SensorValue[auton3] == 1)
	{
		con6 = 1;
	}
	if(SensorValue[set] == 1 && SensorValue[auton4] == 1)
	{
		con8 = 1;
	}
while(con1 == 1)
{
	//auton1
}
while(con2 == 1)
{
	//auton2
}
while(con3 == 1)
{
	//auton3
}
while(con4 == 1)
{
	//auton4
}
while(con5 == 1)
{
	//auton5
}
while(con6 == 1)
{
	//auton6
}
while(con7 == 1)
{
	//auton7
}
while(con8 == 1)
{
	//auton8
}
}
task usercontrol()
{
	while (true)
	{
	   UserControlCodePlaceholderForTesting(); // Remove this function call once you have "real" code.
	}
}

You will need to be pushing the switches as the autonomous code starts.

How do you want it to work, when do you press the switches?

First let’s rewrite this in a way that can be read reasonably…

// ROBOTC Crap, don't worry about it

void pre_auton() { bStopTasksBetweenModes = true; }

task autonomous()
{
    // Variables
    int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0, c7 = 0, c8 = 0;

    // Autonomous selection
    if(SensorValue[auton1] == 1 && SensorValue[set] == 0) c1 = 1;
    if(SensorValue[auton2] == 1 && SensorValue[set] == 0) c3 = 1;
    if(SensorValue[auton3] == 1 && SensorValue[set] == 0) c5 = 1;
    if(SensorValue[auton4] == 1 && SensorValue[set] == 0) c7 = 1;
    if(SensorValue[set] == 1 && SensorValue[auton1] == 1) c2 = 1;
    if(SensorValue[set] == 1 && SensorValue[auton2] == 1) c4 = 1;
    if(SensorValue[set] == 1 && SensorValue[auton3] == 1) c6 = 1;       
    if(SensorValue[set] == 1 && SensorValue[auton4] == 1) c8 = 1;

    // Autonomous code
    while(con1 == 1)
    {
	//auton1
    }
    while(con2 == 1)
    {
	//auton2
    }
    while(con3 == 1)
    {
	//auton3
    }
    while(con4 == 1)
    {
	//auton4
    }
    while(con5 == 1)
    {
	//auton5
    }
    while(con6 == 1)
    {
	//auton6
    }
    while(con7 == 1)
    {
	//auton7
    }
    while(con8 == 1)
    {
	//auton8
    }
}

// User stuff which we can ignore
task usercontrol() {}

Ah that’s much better. Imagine that with syntax highlighting. Just think of all the colors making it easier for my brain to pick out what is a datatype and what is a comment, etc.

Alright now for the issue, it’s this part…

   // Autonomous selection
   if(SensorValue[auton1] == 1 && SensorValue[set] == 0) c1 = 1;
   if(SensorValue[auton2] == 1 && SensorValue[set] == 0) c3 = 1;
   if(SensorValue[auton3] == 1 && SensorValue[set] == 0) c5 = 1;
   if(SensorValue[auton4] == 1 && SensorValue[set] == 0) c7 = 1;
   if(SensorValue[set] == 1 && SensorValue[auton1] == 1) c2 = 1;
   if(SensorValue[set] == 1 && SensorValue[auton2] == 1) c4 = 1;
   if(SensorValue[set] == 1 && SensorValue[auton3] == 1) c6 = 1;       
   if(SensorValue[set] == 1 && SensorValue[auton4] == 1) c8 = 1;

Or more specifically where this part is located. It’s inside autonomous(). Bad idea buddy, because last time I checked teams generally like to setup their robot before the match starts. That’s what the initialize block is for.

See init runs before the field tells the robot to GO, NOW, AUTONOMOUS but autonomous doesn’t run until that signal is sent.

So move the config code into init. That’s part one. Part two is that this code only runs once. Imagine your computer telling you to press F12 to enter BIOS but only waiting for your reply for 1/1000000th of a second. If you were holding the button beforehand it would work, but that’s probably not the way you want it to work. You’ll be prone to missing and when you do you will need to try again, and again and again. Not fun. So let’s fix that.

// ROBOTC Crap, don't worry about it

// Instead of a bunch of variables, lets use an array (and zero it too)
int autonomous[8] = { FALSE };

// Code that runs before the match starts
void pre_auton() {

    // This was already here, so I left it (I assume you want it there)
    bStopTasksBetweenModes = TRUE;

    // Loop until a selection is made
    while(true) {
      // Autonomous selection
      if(SensorValue[auton1] == 1 && SensorValue[set] == 0) { autonomous[0] = TRUE; break; }
      if(SensorValue[auton2] == 1 && SensorValue[set] == 0) { autonomous[2] = TRUE; break; }
      if(SensorValue[auton3] == 1 && SensorValue[set] == 0) { autonomous[4] = TRUE; break; }
      if(SensorValue[auton4] == 1 && SensorValue[set] == 0) { autonomous[6] = TRUE; break; }
      if(SensorValue[auton1] == 1 && SensorValue[set] == 1) { autonomous[1] = TRUE; break; }
      if(SensorValue[auton2] == 1 && SensorValue[set] == 1) { autonomous[3] = TRUE; break; }
      if(SensorValue[auton3] == 1 && SensorValue[set] == 1) { autonomous[5] = TRUE; break; }  
      if(SensorValue[auton4] == 1 && SensorValue[set] == 1) { autonomous[7] = TRUE; break; }
    }
}

task autonomous()
{
    // Autonomous code
    while(con1 == 1)
    {
	//auton1
    }
    while(con2 == 1)
    {
	//auton2
    }
    while(con3 == 1)
    {
	//auton3
    }
    while(con4 == 1)
    {
	//auton4
    }
    while(con5 == 1)
    {
	//auton5
    }
    while(con6 == 1)
    {
	//auton6
    }
    while(con7 == 1)
    {
	//auton7
    }
    while(con8 == 1)
    {
	//auton8
    }
}

// User stuff which we can ignore
task usercontrol() {}

Now this’ll wait for you to make a valid selection before the match starts which is better. I would add a timeout and a default selection in case someone forgets to choose, you wouldn’t want your robot sitting there waiting after the match starts.

But that I wont cover. That being said, those while loops in autonomous() are really really ugly, let’s replace them with function calls.

// ROBOTC Crap, don't worry about it

// Instead of a bunch of variables, lets use an array (and zero it too)
int autonomous[8] = { FALSE };

// Code that runs before the match starts
void pre_auton() {

    // This was already here, so I left it (I assume you want it there)
    bStopTasksBetweenModes = TRUE;

    // Loop until a selection is made
    while(true) {
      // Autonomous selection
      if(SensorValue[auton1] == 1 && SensorValue[set] == 0) { autonomous[0] = TRUE; break; }
      if(SensorValue[auton2] == 1 && SensorValue[set] == 0) { autonomous[2] = TRUE; break; }
      if(SensorValue[auton3] == 1 && SensorValue[set] == 0) { autonomous[4] = TRUE; break; }
      if(SensorValue[auton4] == 1 && SensorValue[set] == 0) { autonomous[6] = TRUE; break; }
      if(SensorValue[auton1] == 1 && SensorValue[set] == 1) { autonomous[1] = TRUE; break; }
      if(SensorValue[auton2] == 1 && SensorValue[set] == 1) { autonomous[3] = TRUE; break; }
      if(SensorValue[auton3] == 1 && SensorValue[set] == 1) { autonomous[5] = TRUE; break; }  
      if(SensorValue[auton4] == 1 && SensorValue[set] == 1) { autonomous[7] = TRUE; break; }
    }
}

task autonomous()
{
    while(TRUE) {
        if(autonomous[0]) autonomous0();
        else if(autonomous[1]) autonomous1();
        else if(autonomous[2]) autonomous2();
        else if(autonomous[3]) autonomous3();
        else if(autonomous[4]) autonomous4();
        else if(autonomous[5]) autonomous5();
        else if(autonomous[6]) autonomous6();
        else if(autonomous[7]) autonomous7();
    }
}

void autonomous0() {}
void autonomous1() {}
void autonomous2() {}
void autonomous3() {}
void autonomous4() {}
void autonomous5() {}
void autonomous6() {}
void autonomous7() {}

// User stuff which we can ignore
task usercontrol() {}

There now each autonomous has it’s own function to live in.

BUT CODY, all that checking for the correct autonomous is wasteful (says the good programmer). Yeha yeah I know, so screw it we’ll use a function pointer to store the routine we want… but we can’t in ROBOTC because ROBOTC doesn’t support function pointers so, that sucks.

Use PROS or ConVEX. :stuck_out_tongue:

There might be a slightly better way to do this, but this is lightyears better than where we started. shruggs -Cody

EDIT: The better way… call the autonomous once and run the loop inside the function call…

task autonomous()
{
    if(autonomous[0]) autonomous0();
    if(autonomous[1]) autonomous1();
    if(autonomous[2]) autonomous2();
    if(autonomous[3]) autonomous3();
    if(autonomous[4]) autonomous4();
    if(autonomous[5]) autonomous5();
    if(autonomous[6]) autonomous6();
    if(autonomous[7]) autonomous7();
}

void autonomous0() {
    while(TRUE) {}
}

void autonomous1() {
    while(TRUE) {}
}

// ... etc ...

// User stuff which we can ignore
task usercontrol() {}

The loop will run until ROBOTC terminates the task (which is when the autonomous timer runs out which works for us nicely).

right brilliant, exactly what i needed :slight_smile: … cheers everyone, and i am going for clicking button at start of autonomous, … :slight_smile:

thanks CODY ! (and everyone else)

You are quite welcome. Actually I’m just realizing something…

// Instead of a bunch of variables, lets use an array (and zero it too)
boolean autonomous[8] = { FALSE };

That can be of boolean type, or alternatively you could use one int and set it to 0-7. It’s a minor difference, but having bool’s will save some memory so why not.

Not sure if ROBOTC uses bool or boolean, always forget. One of them will work. -Cody

cheers, redoing code now … thanks again, will test 2morrow, will let u know how it goes

James pointed out an error in my array size (a good catch I might add), in short I wrote it as autonomous[7] when it should have been [8].

Arrays are indexed from 0, I was thinking 0-7, but (and I knew this) the number in the brackets is not the last index, but the real number of elements created. The autonomous[7] would have created elements from 0-6 (7 elements) you want elements 0-7 (8 elements) so autonomous[8] it is.

I have corrected the code above to reflect this change. -Cody

Booleans are typically 1 byte, whereas an integer is typically 2. Thus, having 8 booleans uses more memory (64 bits vs 16 bits.) The reason booleans don’t (usually) just use 1 bit is because it’s difficult for computers to use just one bit of memory - it’s usually referenced in clumps of 8 which is why we have the convenient term “byte.” It’s a tad like seconds and minutes - seconds are the smallest unit (sort of) and then a minute is just a convenient way to reference 60 of them.

Also, if you were really gonna be that crazy, you would probably use the type “byte” to store the number of the autonomous routine, which would bring you down to 8 bits. The integer solution is also the better solution because then it leaves flexibility to do things like change which routine you’re going to do, whereas having an array like that makes a big mess out of doing things like that.

This is actually true due to the fact that a CPU cannot address anything smaller than one byte, the array I posted will actually be eight bytes. This is still smaller than the integers, but a single unsigned char or byte type can hold a numerical value, 1, 2, etc. and do the job with only one byte of memory.

Even so it’s a really small savings, I wouldn’t worry about it but for correctness sake it’s a good idea to clarify since this is on the forums.

Idk guess I was thinking about readability a tad too much on this one, I’m usually sharper than this and I know all these things.

With pushing the buttons, you need to remember that you will lose about 1 second of autonomous if the ref’s are super strict. At all of the qualifications we did this by holding the buttons down at the start of autonomous so it would start right away, but at worlds, we were told that we could not be touching the robot at the start of the match, and that our hands had to be outside the field wall. Remember this when programming if you score in the final second.

cheers i will consider this … with the pre-auton … when could i activate stuff … when robot is disabled ? or whenever ?

I rewrote mine this summer so that a LCD displays a menu system that can be used to set a global autonomous variable and when autonomous runs, it uses that global variable

This is how I like to write our Autonomous program selection, too. Set everything up before the match and have it just run when the time is right.

so if i set it up in pre-config. when would i press buttons 2 activate ???

You would run through your LCD Menu pre-match, before autonomous starts. You’ll connect the joystick to the Cortex, then to the field controller. The field controller will tell the robot to be in disabled/initialize mode, and that’s when you’ll do your selection. The only potential issue is if you’re running late to a match, but that’s why you should have “default” or the ability to exit the selection process at the beginning of the menu :smiley:

An issue with easyC (and sometimes other languages) is that your initialize will also run in between autonomous and tele-op, so you’ll also want some sort of auto-detect where if autonomous has already run (perhaps change a global variable from 0 to 1), don’t run the LCD Menu selection.