I was lieing in bed this morning when it hit me: Since the prog port is RS-232, and so is a computer, there is a chance you could connect LEGO's old COMM tower with the prog port on the RC or the EDU. You would probably need to make a custom cable, but it might work.
Basically, to control the RCX, you send it IR messages via the IR tower. From there it's a simple matter of programming the two.
The LUGNET thread for sending messages in VB can be found
here.
Here's some FRC code to do it:
Code:
#define SendByte(Byte) {TXREG = Byte; Wait4TXEmpty();}
void SendRCXMessage (char Message)
{
//Header
SendByte(0x55);
SendByte(0xFF);
SendByte(!0xFF);
//Opcode for Message
SendByte(0xF7);
SendByte(!0xF7);
//Message Byte
SendByte(Message);
SendByte(!Message);
//Checksum
SendByte((0xF7 + Message) & 0xFF);
SendByte(!((0xF7 + Message) & 0xFF));
}
The RCX, unfortunately, only has a 1 byte buffer for IR, so I thought of a 1 byte setup to set each motor to a certain speed.
The RCX has outputs A, B, and C. They can be Forward, Backward, or stopped, and have a speed of 1-8. This can be expressed as -8 to 8.
If you just want 2 motors, you can set both in the same byte in the range of -7 to 8. Use the first 4 bits for A and the second 4 for B. In
NQC:
Code:
// A Basic RC Skid-Steer Program (Recieve)
#define mLeft OUT_A
#define mRight OUT_C
#define nOffset 7
#define nBit 16
int Left = 0;
int Right = 0;
task main()
{
start GetMessage;
start RunLeft;
start RunRight;
}
task GetMessage()
{
Left = Message() / nBit - nOffset;
Right = Message() % nBit - nOffset;
}
task RunLeft()
{
while (true)
{
SetPower (mLeft, abs(Left));
if (Left > 0) OnFwd(mLeft);
if (Left < 0) OnRev(mLeft);
if (Left == 0) Off(mLeft);
}
}
task RunRight ()
{
while (true)
{
SetPower(mRight, abs(Right));
if (Right > 0) OnFwd(mRight);
if (Right < 0) OnRev(mRight);
if (Right == 0) Off(mRight);
}
}
(And yes, the RCX does support primitive multi-threading)
In the FRC:
Code:
void Set2RCXMotors(signed char Left, signed char Right)
{
char Temp = 0;
//Check Left value
if (Left > 8)
Left = 8;
if (Left < -7)
Left = -7;
//Check Right value
if (Right > 8)
Left = 8;
if (Right < -7)
Left = -7;
Temp = (Left+7) << 4;
Temp |= Right+7;
SendRCXMessage(Temp);
}
If you want to control all 3 outs directly, then you'll have to specify which one. The first 2 bits are what out, 3 is 0, 4 is direction, 5-7 are power-1, and 8 is "Is on?". So, in a nutshell: MM0D PPPOn.
On the RCX:
Code:
// A Basic RC 3 Motor control
int Left = 0;
int Center = 0;
int Right = 0;
task main()
{
start GetMessage;
start RunLeft;
start RunRight;
start RunCenter;
}
task GetMessage()
{
int Mess;
Mess = Message;
//Left
if ((Mess/64) == 1)
{
if (Mess & 0x10)
{
Left = ((Mess/2) & 8) & ((Mess & 1) != 0) ;
}
else
{
Left = -(((Mess/2) & 8) & ((Mess & 1) != 0));
}
}
//Center
if ((Mess/64) == 2)
{
if (Mess & 0x10)
{
Center = ((Mess/2) & 8) & ((Mess & 1) != 0);
}
else
{
Center = -(((Mess/2) & 8) & ((Mess & 1) != 0));
}
}
//Right
if ((Mess/64) == 3)
{
if (Mess & 0x10)
{
Right = ((Mess/2) & 8) & ((Mess & 1) != 0);
}
else
{
Right = -(((Mess/2) & 8) & ((Mess & 1) != 0)));
}
}
}
task RunLeft()
{
while (true)
{
SetPower (OUT_A, abs(Left));
if (Left > 0) OnFwd(OUT_A);
if (Left < 0) OnRev(OUT_A);
if (Left == 0) Off(OUT_A);
}
}
task RunRight()
{
while (true)
{
SetPower(OUT_C, abs(Right));
if (Right > 0) OnFwd(OUT_C);
if (Right < 0) OnRev(OUT_C);
if (Right == 0) Off(OUT_C);
}
}
task RunCenter()
{
while (true)
{
SetPower (OUT_B, abs(Center));
if (Left > 0) OnFwd(OUT_B);
if (Left < 0) OnRev(OUT_B);
if (Left == 0) Off(OUT_B);
}
}
And on the FRC side:
Code:
void Set3RCXMotors(signed char Left, signed char Center, signed char Right)
{
char Temp = 0;
//Check Left value
if (Left > 8)
Left = 8;
if (Left < -8)
Left = -8;
//Check Center value
if (Center > 8)
Left = 8;
if (Center < -8)
Left = -8;
//Check Right value
if (Right > 8)
Left = 8;
if (Right < -8)
Left = -8;
//Motor
Temp = 0x40;
//Direction
Temp |= ((Left<0)? 0 : 0x10); //Ooooh! A Ternary!
//Power
Temp |= absdif(Left, 1) << 1;
//Is On?
Temp |= (Left != 0) & 1;
SendRCXMessage(Temp);
//Again for the center
//Motor
Temp = 0x80;
//Direction
Temp |= ((Center<0)? 0 : 0x10); //Ooooh! Another Ternary!
//Power
Temp |= absdif(Center, 1) << 1;
//Is On?
Temp |= (Center != 0) & 1;
SendRCXMessage(Temp);
//Again for the right
//Motor
Temp = 0xC0;
//Direction
Temp |= ((Right<0)? 0 : 0x10); //Ooooh! Another Ternary!
//Power
Temp |= absdif(Right, 1) << 1;
//Is On?
Temp |= (Right != 0) & 1;
SendRCXMessage(Temp);
}
There are obviously a few bugs to work out (I wrote this on the fly!), but I think you can get the idea. (My favorite NQC IDE, BrixCC, can be found
Here.) I'll give every one a few hours to chug through that.