G33kDude / pyev3

A thin python wrapper library for ev3dev following the official API specification
MIT License
17 stars 7 forks source link

Says Device Not Found #6

Open Jacob-Brink opened 6 years ago

Jacob-Brink commented 6 years ago

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

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.

G33kDude commented 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
Jacob-Brink commented 6 years ago

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!

G33kDude commented 6 years ago

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 1s and 0s 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!

Jacob-Brink commented 6 years ago

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!