Open Jacob-Brink opened 6 years ago
The error you received is caused by it not finding the ev3dev motor devices. This library has been deprecated and will not work with newer versions of ev3dev. Please use ev3dev-lang-python instead for interacting with EV3 components.
The RCX communication components should still work, but your RCX does have to be flashed with firmware before it will respond. You can flash the official firmware firm0332.lgo
from your EV3 using the tool nqc
which is available in the debian repositories. There are instructions for using nqc
on Raspberry Pi (very similar to EV3) here, though you won't have to compile it yourself from what I remember.
The steps you end up taking should be similar to these (untested code):
# Install nqc and zip tools
sudo apt-get install nqc unzip
# Grab firmware
wget http://pbrick.info/wp-content/uploads/2013/10/firm0332.zip
# Extract firmware
unzip firm0332.zip
# Flash firmware to RCX
nqc -Susb:/dev/usb/legousbtower0 -firmware firm0332.lgo
Got it to work. Do I have to flash the firmware every time i reboot rcx? Also, I looked at the documentation for the tower ir protocol, the two links you gave that one person about mr. alligator. I did not understand the protocol. Where should I go to understand that the code 2185 translates to 0x21 0x80 0x1 0x4? How are you supposed to figure out that the last number is translates to a sum of 1 and 4 but the others aren't? Is there like, for instance, some tutorial online that I should read through before I can understand this stuff? Thx!
You will have to flash the firmware every time the RCX loses power. This means you can turn the RCX off and back on without it losing the firmware, but if you were to remove the batteries or disconnect the AC adapter (depending on how you power your RCX) then it would lose the firmware and you would have to flash it again.
I don't recall using any significant resources other than Mr. Alligator's RCX Internals website and a large helping of trial and error. The format of a packet is described on this page as follows:
At the packet level, all packets look like this:
0x55 0xff 0x00 D1 ~D1 D2 ~D2 ... Dn ~Dn C ~C
where D1...Dn are the message body, and C = D1 + D2 + ... Dn.
This is using the character ~
in reference to the bitwise NOT operator, meaning to flip all the 1s and 0s of that byte. The checksum C
is the all of the instructions added together following overflow rules for a single byte (effectively Sum(Instructions) % 0x100
or Sum(Instructions) & 0xFF
)
Before I go any further in my explanation it would be good to take a look at what the instruction 2185
really means. The first byte 0x21
corresponds to the Set motor on/off instruction. That instruction reads in one more byte after it, specified on that page as "byte code" which is a bit field. A bit field is a binary value where the RCX treats specific 1
s and 0
s as separate instructions.
The bit field we give it is 0x85
which translates like this:
10000101 = 0x85
| | |
| | +- 0x1 - Modify motor A
| |
| +- 0x4 - Modify motor C
|
+- 0x80 - Turn on the specified motors
You can skip all the dealing with binary yourself if you use the bit values given on Mr. Alligator's page and combine them with binary OR. Using |
as OR, 0x80 | 0x4 | 0x1 == 0x85
.
Now to go back to packet structure. Using the naming conventions from Mr. Alligator's page 0x21
will be D1
and 0x85
will be D2
.
Our packet will begin by prefixing with the header 0x55 0xFF 0x00
. Then we add D1 == 0x21
) and its inverse ~D1 == ~0x21 == 0xDE
) to get this:
0x55 0xFF 0x00 0x21 0xDE
Next we add D2 == 0x85
and its inverse ~D2 == ~0x85 == 0x7A
to get this:
0x55 0xFF 0x00 0x21 0xDE 0x85 0xDE
Finally we add the checksum C
as 0x25 + 0x85 == 0xAA
(which if it was greater than 0xFF
would be cut to the last two hex digits by means of modulus 0x100
or binary AND 0xFF
) and its inverse ~C == ~0xAA == 0x55
0x55 0xFF 0x00 0x21 0xDE 0x85 0xDE 0xAA 0x55
This is our complete packet. There are two nuances to this that I did not yet touch on, however.
The first is that the RCX expects you to flip the 4th bit (binary 1000
being decimal 8
) on every other instruction you send, so if you sent this instruction again you'd want to use 0x21^8 == 0x29
instead. My python should handle this automatically.
The second is that there exists some kind of a cool-down period after sending a packet that, frankly, my code does not handle well. I added a parameter to my send
function called pad
that adds nulls to the end of the packet that are pretty much just there to waste time without meaning anything. If you have trouble sending multiple packets in quick succession try adding a dozen or two nulls to the end of your packet.
Finally, this description may be incomplete or slightly wrong as I'm going largely off memory and reading my old code. Please let me know if any part is unclear or would benefit from expansion. Good luck with your RCX studies!
Oh. The hex number is really just a translation of the bits and bytes. I played around with some hex converters to binary, and I think I grasp the concept now: people use hexadecimal base 16 instead of base 10, cuz binary base 2 can easily be derived from base 16. That makes a lot more sense, thx!
After following the instructions given in rcx.py, I ran python rcx.py and it says remote.py cant find device. I checked /dev/usb/legotower0 and it exists. Also, what firmware should I be using?![ev3_rcx_problems](https://user-images.githubusercontent.com/29411599/42737913-fc69c3fc-8848-11e8-82a4-0d5bb966699b.png)
Okay, so now I have edited the rcx.py to use os.open and os.write which removes the errors, but the rcx is not responding to any of the codes. tower.send('2185') does not turn on the motors as is stated in the docs.