ROBOTC V4.XX evaluation

I’m starting this thread to post the results of the evaluation of ROBOTC V4.xx (currently V4.05) that I hope to do over the next several days. I’ve had a bit of a poke around in the new version and the jury is still out on whether it’s a useful upgrade when used with the cortex. I’m not going to be looking at the VEX IQ implementation here, that will be the subject of another post in a couple of weeks.

I’m afraid, as usual, figuring out the new functionality is a bit of a scavenger hunt. I see some exciting new functions available in the function library, but no documentation on how to use them or what they do. This first post is a bit lightweight but this is what I see so far.

[ATTACH]7818[/ATTACH]

shiftOut(dataPin, clockPin, bBitOrderLSBFirst, nValue, nDelay);

This has actually been around for a while although I’m not sure if it worked before. This allows serial data to be clocked out using the digital IO pins on the cortex. The pins both need to be set as digital outputs, use is something like this.

shiftOut( dgtl1, dgtl2, true, 0x55, 10);

The delay seems to be some type of loop variable and does not correspond to uS or anything else that makes sense. This function has been tested and does work.

shiftIn(dataPin, clockPin, bBitOrderLSBFirst, nValue, nDelay);

This should be a companion function to the above but I’m unable to get it to work. The received data, which seems to use the old style ROBOTC syntax of passing a variable by reference, rather than the more standard C way of passing a pointer, always contains the value 255 no matter what I do to the data input pin.

What would have been nice would have been a “shiftOutIn” function that did both at the same time, this would have allowed sensors with an SPI interface to be used in VEXU, although I suspect the underlying code is just bit banging so not very efficient.

[ATTACH]7817[/ATTACH]

sendI2CMsg(sendMsg, nReplySize);
readI2CReply(replyBytes, nBytesToRead);

These looked promising, figured that we had access to the I2C port for sensors other than the IMEs, alas, they don’t work. I should really say that I’ve been unable to make them work, despite having some clue as to what I’m doing. Even getting them to compile was a struggle as the way they are defined is again “old style” with the sendMsg (whatever that is, does it contain an address? A message length? ) apparently wanting a constant.

bUseVexI2CEncoderVelocity

I assume, but have not confirmed, that this uses velocity data coming from the IMEs in perhaps the PID calculations. It should be a boolean but currently want’s an integer assigned, presumably “1”.

[ATTACH]7819[/ATTACH]

mtrPid_Period]
mtrPid_Deadband]
mtrPid_kD]
mtrPid_kI]
mtrPid_kP];

Read/write variables to access and change some of the PID control parameters, use in the same way as the motor] variable.

mtrPid_ErrorD]
mtrPid_ErrorI]
mtrPid_ErrorP]
mtrPid_StartEncoder]

Read only variables related to the PID control.

motorPWMLevel];

Another read only variable that was in the RobotCIntrinsics file but not shown in the function library. This gives the actual pwm values being sent to the motor when under PID control.

moveMotorTarget(nMotor, nEncoderCountTarget, nMaxSpeedToUse, bHoldAtEnd);
setMotorTarget(nMotor, nEncoderCountTarget, nMaxSpeedToUse, bHoldAtEnd);

These function allow positional control of the motor, one is absolute, the other relative. They could be used to drive to a position or control an arm/lift system.

getMotorTargetCompleted(nMotor);

A function to determine if the above positional control has finished.

waitUntilMotorStop(nMotorIndex)

A macro using the above function, it implements this.

do{
    sleep(100);
    while(!getMotorTargetCompleted(nMotorIndex))
        sleep(1);
    } while(false)

slaveMotor(nSlaveMotor, nMasterMotor);

This allows a non-encoded motor to be slaved to an encoded motor, I did not try this yet.

getMotorSlewSpeed(nMotor);

The PID code implements slew control (somewhat, more on this in another post), this function allows you to get the rate of change per period, unfortunately there is no function to set rate of change per period, only the motors and sensors dialog.

getEncoderAndTimeStamp(nMotor, nEncoder, nTimeStamp);
getEncoderForMotor(nMotorIndex);
getMotorEncoder(nMotor);
mapEncoderToMotor(nMotorIndex, nSensorIndex);
resetMotorEncoder(nMotor);

Various encoder related function most of which I did not try yet.

I will talk about the PID control in another post, however, suffice to say at this point there are a couple of serious drawbacks. The most significant is that it does not allow responsive manual control, that is, when trying to control motors during the driver control period it makes it really hard to control the robot. The second drawback is that there is no way (that I can find) to turn PID off or on in code, if you configure motors to use it you are stuck using it throughout the program.

I went back and took a look at the 3.61 beta from last year, it has some more PID functionality that has been removed in this version. These variables have now gone, I don’t know why because they were useful.

mtrPid_PowerLimit]
mtrPid_SlewUp]
mtrPid_SlewDown]
mtrPid_PowerSlew]

[ATTACH]7820[/ATTACH]

I didn’t dig into any of these yet, looks like they are something to do with simplified standard control of a clawbot or something like that (they are intrinsics unlike the natural language stuff).

That’s it for this post, next time I will look at the PID setup menus.
SensorI2C_functions_v4.05.jpg
Sensors_functions_v4.05.jpg
motor_functions_v4.05.jpg
drive_functions_v4.05.jpg

A couple of ROBOTC functions were renamed in V4.05.

StartTask becomes startTask
StopTask becomes stopTask

The capitalization was removed, I understand this was because they were inconsistent with other function names but it now creates many warnings that tend to obscure other useful warnings. For example, Vex_Competition_Includes.c was not revised and includes over 20 calls to StopTask.

I was hoping to write a glowing review of the new PID features in ROBOTC, unfortunately I’m finding it so buggy that my best advice is stay with 3.61 (or 3.62 I suppose, I didn’t ever upgrade to that version). I spent the better part of today working with 4.05, for these tests I’m using a standard clawbot that has three IMEs added, one on each of the drive motors and one on the claw. It’s the robot where I presented small improvements to the standard design in this thread. I’m using this robot rather than a more complex one as probably closer to the test systems that CMU uses and I would expect the standard PID constants to be tuned for something like this.

The first problem in porting the code for this test is the startTask call that I mentioned in the previous post. When this is used with an optional priority it gives an error instead of a warning, this means all calls have to be revised and are now incompatible with 3.61, what a pain, don’t know why they had to change it at this stage.

So everything basically works in the code after this change, however, the first big (and it’s really big) problem I find is the following.

Problem 1.
If VEXnet doesn’t connect in the first couple of tries, the IMEs don’t work.

This problem has been driving me crazy all day (along with VEXnet keys that sometimes work, sometimes don’t). It appears that if VEXnet connects first try, the IMEs return valid counts, if VEXnet takes a few tries to connect the IMEs always return 0. The leds on the IMEs are always indicating good initialization, they do not get reset at any stage but the IMEs don’t work. I reverted back to 3.61 and duplicated (using an intermittent VEXnet key) the multiple VEXnet retry situation but the IMEs always work in that version. Whatever this bug is it pretty much makes 4.05 useless for any robot that has IMEs installed (which would be all of mine and the team I coach).

Edit:
Just to add to this, when going into this mode it’s the I2C bus that’s screwed up, constant slow speed negotiation (500Hz clock) every 125mS, the same thing that happens perhaps 4 times at the beginning of a “normal” startup.

Problem 2.
Using setMotorTarget can pretty much send the robot anywhere except where you want it.

Well that’s a bit harsh, I haven’t figured out exactly what is happening, the first time setMotorTarget is used it seems to work, for example, I have two drive motors (one has the reversed flag set), power up the robot and send both motors to count 2000 and it works. However, drive the robot a little, reset the encoders and then use setMotorTarget with 2000 on both motors and usually the robot spins in circles. It’s something to do with negative IME counts on the reversed motor and also raw encoder counts rather than user encoder counts. Anyway, it’s pretty useless at the moment in the way I expected to be able to use it.

moveMotorTarget on the other hand (the relative version) does seem to work.

Problem 3.
Downloading code using PID after the robot was powered with non-PID code then requires a reboot

I guess not the end of the world but really annoying, especially when you are trying to compare motor control without PID to control with PID.

Problem 4.
There’s no way to enable or disable PID for a given motor, there’s no way to change slew rate for a motor

User controlled driving with PID enabled for the drive works, but the robot is quite unresponsive. Changing the slew rate so user input gets to the motor quicker helps, but the PID limits top speed (it has to leave some headroom so it can send more power to a motor) and driving generally feels “relaxed”.

As there is no way to disable PID after using it during autonomous, this is (at least for me) a show stopper on a competition robot.

I did try and see if there was any improvement using PID on the drive in some typical autonomous code. I tried a simple “drive forwards” and then “drive backwards” routine both with PID disabled and then with PID enabled. There is some small improvement but in both cases after moving forwards and then backwards several times, either version could drift off.

Anyway, for now problem 1 is the show stopper for anyone using IMEs, hopefully this can be addressed soon.

ROBOTC V4.06 was posted today, it addresses most of my issues with PID that I mentioned earlier in this thread. I will write an eval and give some explanation sometime next week.

http://www.robotc.net/blog/2013/12/13/robotc-vex-4-06/#more-4597

Will the PID instructions page be updated any time soon? Several elements have the exact same descriptions. (EncdrTrgtRel, EncdrTrgtAbs, Overshoots, Near Trgt, Slew Rate)

http://www.robotc.net/wiki/VEX_PID_Control

I also do not see a way of capping the integral value. Is that available in the integrated PID?

How does coordinating motors as slaves work?

Can the PID library be used with a potentiometer instead of the IME?

Yes, they need to update the instructions, there are mistakes and it’s based on last years beta so some things have changed.

I don’t think that’s available.

I have not tested this since last year, I believe it just sends the same power to the linked motor as the master motor, I will take a look over the holidays.

I don’t think so.

The built in PID really does not replace what competition teams have been using in the past. I believe it’s more for classroom use where students were frustrated with simple robots that wouldn’t drive in a straight line. I do see potential for using it during autonomous on a drive but there are still a few implementation details that need sorting out.

Edit:

I had a quick look at linking motors, pretty much works as expected, same pwm value (with reversed flag taken into account) is sent to the slave motors. Works even if PID is turned off, this example code slaves two motors to a master motor, all three move together.

#pragma config(I2C_Usage, I2C1, i2cSensors)
#pragma config(Sensor, I2C_1,  ,        sensorQuadEncoderOnI2CPort,    , AutoAssign)
#pragma config(Motor,  port1,           motorA,        tmotorVex393_HBridge, PIDControl, reversed, encoderPort, I2C_1)
#pragma config(Motor,  port9,           motorC,        tmotorVex393_MC29, openLoop)
#pragma config(Motor,  port10,          motorB,        tmotorVex393_HBridge, openLoop)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

task main()
{
    slaveMotor( motorB, motorA );
    slaveMotor( motorC, motorA );
        
    while(1)
        {
        if( abs(vexRT Ch1 ]) > 10 )
            motor motorA ] = vexRT Ch1 ];
        else
            motor motorA ] = 0;

        wait1Msec(10);
        }
}