Sunday, November 10, 2013

Week 11/12: IR Sensor

Going off of my previous brainstorming regarding possible sensors, I decided to begin work starting with the IR sensor idea.

POST-COMPLETION EDIT: So it's probably best for my code to speak for itself here (link to both files at the bottom). I'm going to do a breakdown of both the RobotC and Arduino codes, pointing out anything important of note. I should note that the NXT and Arduino are connected as previously described, with the I2C lines feeding into the A4/A5 analog pins on the Arduino. There is an IR sensor signal line feeding in to DIO pin 4 on the Arduino with a 330 Ohm resistor in series.

LIBRARY NOTE: The IR sensor requires a decoding Arduino library written by Ken Shiriff (https://github.com/shirriff/Arduino-IRremote), the instructions to install are included on the github.

NXT Code
This section is fairly straightforward. There is a main execution loop, main(), which continually polls the Arduino using PollIR() to retrieve a 32-bit IR code. Once retrieved the code is displayed on the NXT screen, and a particular tone is played if the code matches pre-determined values (I'm using a random remote control I had lying around. Other remotes will have different codes).

The guts of the PollIR() function are also pretty standard. As detailed in previous posts, a register selection packet is constructed using the I2Cmessage[] structure selecting register 0x01 on the Arduino. The packet is send, a 4-byte reply (IR codes are 4-bytes long) is requested and retrieved using readI2CReply(), and some bitwise reconstruction is performed to get the original code. -1 is used as a reserved code to indicate that no new data is available from the sensor.

Arduino Code
The Arduino is responsible for continually scanning for IR codes, utilizing the newly installed IR photodiode. The <IRremote> library provides the "irrecv" structure, initialized with the line "irrecv.enableIRIn()"; this also prompts the library to begin scanning in the background of the user program. During each execution loop this structure will be evaluated for IR codes, upon detection they will be committed to memory. The Arduino needs to be capable of storing multiple IR signals, recall the NXT is not necessarily polling the Arduino in realtime, and thus there needs to be some mechanism to hold unprocessed codes. I implemented this functionality using a linked-list queue, and the push() pop() functions manage access to this.

The Arduino's Wire library is configured to use address 0x0A, and the I2CHandleDataRequest() and I2CReceive() functions are attached as interrupt handlers to be called when data request or register selection packets are received respectively. Recall that digital sensors maintain register banks; this is emulated with a register_requested state variable, selecting between register 0x01 (Most recent IR Code) or 0x02 (length of IR processing queue).

 Mentioned previously is an idiosyncrasy of the Wire library, the Arduino will only transmit packets using 1-byte payloads. This means that any data must be transmitted as a series of disjoint byte packets. As IR codes are 4 bytes in length, I have a function constructIRArray() to take in a code and create a 4-element byte array for I2C transmission. Once this is transmitted, the RobotC code will perform reconstruction of the IR code.

One consideration to make is that I haven't put in any memory safeties. Here I'm presuming data will be processed in a timely manner, though if for some reason a massive number of IR codes were to accumulate without being polled by the NXT, there could ostensibly be memory errors as the IR queue will never be cleared.


Links to Code

Arduino Code - https://www.dropbox.com/s/ewd55d2vx574665/IR_Arduino.ino

NXT Code -  https://www.dropbox.com/s/8yq10d8isjexdst/IR_NXT_Program.c