RobotC Programming Problems

Hi everyone,

I have started programming with RobotC recently, and I have run into some problems. Remember, I do not have a lot of experience with the code. :stuck_out_tongue: Some of the problems I have include;
-Too many statements on our LCD, many times the default LCD lines from the UserInclude over ride the lines I have
-IME not moving in “ClawStartTOLoaderRed”
-Two Wheels moving faster than the others, even after we were sure that they are all geared the same
-Not being able to write lines to the LCD before autonomous starts

Please, all criticism welcome :o I just need some help with some errors I am making. I have attached the code.

-Note: I am still using RobotC Version 3. Sometimes when I close the program, it disapears as an icon on my desktop, but if I search my desktop it shows up.
Skyrise States.c (11.8 KB)

I’m not sure about RobotC version 3, and I’m no programming expert, but there are a few things about your code I have questions about.

Is it possible that your Cortex (on powering up) is running your RobotC code ahead of your LCD’s ability to warm up in time to actually process the commands it was given to display anything? Because your LCD pre-autonomous code is not in any kind of refreshing loop, I think your LCD has only one chance to get the data and display it, maybe. So if the LCD isn’t ready, perhaps it just remains blank???


 displayLCDPos(0,0);
 displayLCDCenteredString(1, "Case 1");

I’m not sure about this, but it appears to me that the above bit of code is setting up the LCD “cursor” to write at the top line, first position, but then the next line of code tells it to write on the second line and center it. Could that be causing some kind of problem?


        displayLCDCenteredString(0, "Driver Control");
	displayLCDChar(1,0,RightDriveEncoder);
	displayLCDChar(1,5,LeftDriveEncoder);
	displayLCDChar(1,10,TurntableEncoder);

In the above, it seems to me that if RightDriveEncoder and LeftDriveEncoder and TurntableEncoder are values of more than one character, then you would overflow your LCD. It looks to me like you have the value displays all crammed on a single line.

Finally, you might want to mention which wheels are running incorrectly.

Sorry I’m not much help, but if nothing else I got your post bumped up a little.

No thermionic valves in the LCD as far as I know. The LCD display does not need to “warm up”.

We’ll fix this tomorrow, too late tonight. A few problems including this.


  bStopTasksBetweenModes = false;

and this

task autonomous()
{
switch(AutonValue)
 {
 << SNIP code removed for clarity >>
 }
}

and this.


displayLCDChar(0,7,FromEncoder);

(where FromEncoder is type long)

Thanks for the help so far!

With the motor problem, our front two motors (the two with IMEs) run a lot faster than the two rear ones. We have checked everything we could think of and nothing helps.

As for the LCD, is there a way to stop the UserInclude from hogging the LCD at start up? Where else should I be setting the LCD text to make it read before Autonomous starts?

I really appreciate it, I do not know a lot yet, and I’m still working on the basics.

Are you sure you don’t have speed gears on the front motors? (just checking, seen this before and it’s not pretty when you want them synced)

The rears are on ports 1 & 10 which are two wires right to the Cortex. Could the MC 29 parts be going on you for the back wheels? Ports 1 & 10 can perform better but not really that noticeably so. Could the h-bridge in the cortex be going on you?

Any motors in a power expander?

All of the wheels have turbo gears in them, and we are not using a power expander. As for the wires, I think it would be a little weird for both of the MC 29s on the rear wheels to go. It could be the cortex. We will have to check it all over

Short answers first, then we will go into more detail.

Two main problems
You allow both autonomous and driver control tasks to run at the same time.
You will need to wait at the end of the pre-auton function for the competition to start otherwise the default competition template will write on the LCD.

FromEncoder is a variable, it will not update on it’s own, you need to read the encoder.

This is probably not a programming issue, check gearing etc. as others have said.

Same as issue 1, block at the end of pre-auton.

Some more details.

LCD

The robotic competition template is code that implements a main task and one or two useful functions, nothing special about it. When this task starts it first calls the pre_auton() function and then enters an infinite loop monitoring the internal flags that indicate the enabled/disabled and autonomous/driver states. When disabled it displays a running counter so you know the code is running. The problem you have found is that anything you may write to the LCD in the pre_auton() function is overwritten by this code, there are three ways to deal with this.

  1. Modify the competition template (or a copy of it) so it doesn’t write to the LCD
  2. Use you own competition template code
  3. Stop at the end of pre_auton and only return to the template code when the competition starts. This only works once after power on, disabling the robot after being enabled does not run pre_auton again.

I modified you code to implement scheme 3, the end of pre_auton now looks like this.

    // delay so we can see selection when not in competition mode
    wait1Msec(1000);
    
    // Now we will block here until enabled
    while (bIfiRobotDisabled)
        wait1Msec(10);
}

ROBOTC also has a habit of writing the program name to the LCD every time a task is started and can leave characters where not wanted on the LCD. Usually a good idea to clear the LCD at the beginning of each task.

There are several ways to write numbers onto the LCD. The most simple is to use the function displayLCDNumber, you had tried to use displayLCDChar in several places by mistake. So code like this


displayLCDChar(0,7,FromEncoder);

should have been this


displayLCDNumber(0, 7, FromEncoder, 5);

you were also trying to display encoder values incorrectly in the driver control code;
this


displayLCDChar(1,0,RightDriveEncoder);

should be this


displayLCDNumber(1, 0,  SensorValue RightDriveEncoder ] , 5); 

There is also another way to display a number by using a function called sprint to create a string variable in a format you define. The above would look like this using sprintf.

        char  str[32];  // define this only once somewhere

        sprintf( str, "%5d", SensorValue RightDriveEncoder ] );
        displayLCDString(1, 0, str);

IME not moving

The original code is as follows.

void ClawScoreTOLoaderRED()
{
//Start Cycle
OKToMove = 1;
while(OKToMove == 1)
	{
		if(FromEncoder > RedPickUpPoint2 - RedPickUpAccuracy || FromEncoder < RedPickUpPoint2 + RedPickUpAccuracy)
		{
			motor[TurntableMotor] = 0;
			OKToMove = 0;
		}
		else
		{
			Distance = RedPickUpPoint2 - FromEncoder;
			Distance = abs(Distance);
			displayLCDString(0,0, "IME =");
			displayLCDChar(0,7,FromEncoder);
			if(Distance > 500)
			{
				TargetSpeed = 127;
			}
			else
		  {
			TargetSpeed = Distance / 1100 * 127;
				if(TargetSpeed < 23)
				{
				TargetSpeed = 23;
				}
		 	}
		 	motor[TurntableMotor] = TargetSpeed;
		}
	}
}

You compare a variable “FromEncoder” to an upper and lower limit trying to move the turntable. There may be other issues with the logic but the fundamental problem is that none of the variables in the comparison will ever change. I assume you were hoping that FromEncoder would change as the IME moved, sorry, not in the C language. So perhaps this was what you were after.

void ClawScoreTOLoaderRED()
{
    //Start Cycle
    OKToMove = 1;
    while(OKToMove == 1)
        {
        FromEncoder = SensorValue[TurntableEncoder];
        
        if(FromEncoder > RedPickUpPoint2 - RedPickUpAccuracy || FromEncoder < RedPickUpPoint2 + RedPickUpAccuracy)
            {
            motor[TurntableMotor] = 0;
            OKToMove = 0;
            }
        else
            {
            Distance = RedPickUpPoint2 - FromEncoder;
            Distance = abs(Distance);
            displayLCDString(0,0, "IME = ");
            displayLCDNumber(0, 6, FromEncoder, 5);                                           
            //displayLCDChar(0,7,FromEncoder);
            if(Distance > 500)
                {
                TargetSpeed = 127;
                }
            else
                {
                TargetSpeed = Distance / 1100 * 127;
                if(TargetSpeed < 23)
                    {
                    TargetSpeed = 23;
                    }
                }
            motor[TurntableMotor] = TargetSpeed;
            }
        wait1Msec(10);
        }
}

The encoders in the code are a little mis-configured, what in fact is connected? You have defined only one IME as IME_3, IME 1 and 2 are not defined, not sure that will actually work if there is only one. You also have two quad-encoders on the digital ports, are these used?

Anyway, here is some revised code that you can work with on the next phase of debugging.
skyrise_state_rev1.c (14.7 KB)

Thank you so much jpearman for all of the help! I looked it all over and now I know how to do it correctly. I really appreciate the time you spent helping us, because I need our robot to be programmed within the next week. :slight_smile:

Two more questions.

Can I set the sensor values to a Variable, like this? I did not put values to any of these three variables. All I need is a return value from them.

   
SensorValue[TurntableEncoder] = FromEncoder;
SensorValue[LiftEncoder] = LiftQuadEncoder;
SensorValue[CubeIntakeEncoder] = CubeIntakeQuadEncoder;

Also, when our robot initializes, our pneumatic claw starts rapidly firing. I added a statement in pre_auton to try and stop this, but it did not stop the claw right away.


SensorValue[SkyrisePneumatics] = 0;

It stops it after a second or two of firing. I have seen threads in the forums, but never a clear answer. We are most likely adding a valve right before the solenoid to stop this, but I just want to know if it is possible to stop it in code.

Thank you all for the help!

Short answer is no.

The only number you can assign to a sensor is 0.

What are you trying tho achieve?

The problem is with hardware, not software. Usually the solution is to turn off the air before powering up the cortex. After the code has run and set the initial state of the pneumatics then turn on the air. For the long technical answer as to why this happens see these posts
Cortex digital IO ports and the pneumatics driver - post #1
Cortex digital IO ports and the pneumatics driver - post #2

You are very welcome.

I want to try using a Variable to represent the current value of the Encoders. Should I just use SensorValue[encodername] instead?

A variable cannot represent the value of the encoder unless you read that value into the variable. The following would all be correct ways of using an encoder value.

if( SensorValue encoder name ] < 100 )
    motor port1 ] = 100;
int  x;

x = SensorValue encoder name ];
if( x < 100 )
    motor port1 ] = 100;
#define  MY_ENCODER  SensorValue encoder name ]

foo()
{
    if( MY_ENCODER < 100 )
        motor port1 ] = 100;

   // more code
}

With IMEs you should also be using nMotorEncoder rather than SensorValue. You pass the motor port to nMotorEncoder not the sensor name.

nMotorEncoder port1 ]

The advantage is that if the motor is reversed the encoder still counts the correct way. See this post as to why this is (IMHO) important.
Using double negatives

Ok, that helps. I just noticed how you did it in the code, too. Thanks!