This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
user:mgough:car [2010/05/08 13:58] – mgough | user:mgough:car [2010/05/19 15:28] (current) – mgough | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Peripheral Interaction Project ====== | ||
+ | Controlling a Remote Control Car via the Printer Port | ||
+ | {{: | ||
+ | |||
+ | ===== Overview ===== | ||
+ | |||
+ | The goals of this project are the following: | ||
+ | 1) Modify the control board of a remote control car's handset to accept input from the parallel port of a computer. | ||
+ | 2) Control the vehicle using software written in C. | ||
+ | |||
+ | ===== Components ===== | ||
+ | 1) Remote control car and controller that uses the Realtek TX2 transmitter controller chip. | ||
+ | 2) (4) 1k ohm resistors. | ||
+ | 3) (4) MPSA13 NPN transistors or equivalent. | ||
+ | 4) Soldering iron, solder and flux. | ||
+ | 5) Printer port cable. | ||
+ | | ||
+ | |||
+ | ==== Realtek TX2 Transmitter Chip ==== | ||
+ | The first step is to disassemble the handset and remove the motherboard. | ||
+ | |||
+ | The first step I took was to identify the components and obtain their specifications to identify functions. | ||
+ | After disassembling the remote handset, I found that the on board controlling IC was a Realtek TX2 chip. This is apparently a very common chip that is used in many remote control vehicles. | ||
+ | |||
+ | The chip has pins that correspond to the car's basic functionality - such as forward, reverse, left and right. | ||
+ | |||
+ | I will only go over the basic functions of the chip, if you would like more detailed information the specification sheet can be found here: http:// | ||
+ | |||
+ | Here is the basic pinout of the chip with the manufacturers designations. | ||
+ | |||
+ | {{: | ||
+ | |||
+ | Again, it is only the movement and power functions that we will be concerned with in this project. | ||
+ | |||
+ | ==== MPSA13 NPN Transistor ==== | ||
+ | |||
+ | {{: | ||
+ | |||
+ | To enable a function on the motherboard, | ||
+ | |||
+ | I found a bunch of MPSA13 transistors in "the pile" that work well in this application. | ||
+ | |||
+ | The key to making this work is by attaching the emitter pin to the bus ground of the remote mother board, the collector pin to the IC side of the contact, and the base pin to the corresponding data line from the printer port cable. | ||
+ | |||
+ | ===== The Layout ===== | ||
+ | |||
+ | The key to making this work is to plan it all in advance. | ||
+ | |||
+ | First is the circuit layout on the transmitter board. | ||
+ | |||
+ | {{: | ||
+ | |||
+ | This is an overview of my " | ||
+ | |||
+ | The next step of the plan is determining how to integrate the modified transmitter board with the printer port cable. Again, another diagram.. | ||
+ | |||
+ | {{: | ||
+ | |||
+ | We will be using pins 2 through 9 (data bit 0 - 7) for our control functions. | ||
+ | Here's the breakdown | ||
+ | Pin2 - Data-0 - +5vdc | ||
+ | Pin3 - Data-1 - Right Turn Function | ||
+ | Pin4 - Data-2 - Left Turn Function | ||
+ | Pin5 - Data-3 - Forward Function | ||
+ | Pin8 - Data-6 - Reverse Function | ||
+ | Pin25 - Ground | ||
+ | |||
+ | It is critically important to use a continuity tester to identify and mark each wire!! Use masking tape or some other way to identify the pin/port on the transmitter side of the cable. | ||
+ | |||
+ | ===== Making the Modifications ===== | ||
+ | |||
+ | So, the planning phase is over, time to get our hands dirty! | ||
+ | |||
+ | The first thing that I did was solder in the power to the transmitter board, this requires identifying the battery lead connections and performing the following operations: | ||
+ | 1) Solder the wire from Pin2 (+5vdc) to where the positive battery lead is attached to the transmitter board. | ||
+ | 2) Solder the wire from Pin25 (ground) to where the negative battery lead is attached to the transmitter board. | ||
+ | |||
+ | Next step is to attach the transistors to the system. | ||
+ | |||
+ | The key to soldering the transistors in right is to identify the transmitter board ground bus, this can be done easily by following the trace from the negative battery connection to each switch. | ||
+ | |||
+ | Below is my connections, | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ===== Driver Software (no pun intended) ===== | ||
+ | |||
+ | The tough part is over! Now onto making the car drive. | ||
+ | |||
+ | As before, the next step requires some planning. | ||
+ | |||
+ | The bit's values can be described as ... | ||
+ | < | ||
+ | <br> | ||
+ | <pre> | ||
+ | Data 7 | ||
+ | Pin | ||
+ | -- -- -- -- -- -- -- --< | ||
+ | Value 128 64 32 16 8 4 2 1<br> | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | Therefore, if we want to turn the power on the board, we have to supply power to pin 2 (Data-0), this is accomplished by sending a signal to the hex-value 0x01. | ||
+ | |||
+ | To drive forward we require power to pin's 2 and 5 - for this, we have to sum up the values (1 and 8) which is 9, and a hex value of 0x09. | ||
+ | |||
+ | Between functions, you want to clear out the active ports, this is done by sending a signal of 0x00 - it turns off power to all (one ring to rule them all!) | ||
+ | |||
+ | Not too bad eh? Of course, the hex values are easier to determine using a hex calculator or a chart - I use the asciitable - http:// | ||
+ | |||
+ | The first program I created was a basic menu-driven interface in C - You could easily make this more interesting by creating a GUI, but my time is limited :D | ||
+ | |||
+ | You must determine where your printer port " | ||
+ | |||
+ | <file c menu_drive.c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | int goForward(); | ||
+ | int goForwardRight(); | ||
+ | int goForwardLeft(); | ||
+ | int goBackward(); | ||
+ | int goBackwardRight(); | ||
+ | int goBackwardLeft(); | ||
+ | int powerOn(); | ||
+ | int powerOff(); | ||
+ | |||
+ | int addr = 0x378; | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | |||
+ | char choice; | ||
+ | |||
+ | while(choice != ' | ||
+ | { | ||
+ | system(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | printf(" | ||
+ | scanf(" | ||
+ | |||
+ | |||
+ | if(choice == ' | ||
+ | { | ||
+ | powerOn(); | ||
+ | } | ||
+ | if(choice == ' | ||
+ | { | ||
+ | powerOff(); | ||
+ | } | ||
+ | if(choice == ' | ||
+ | { | ||
+ | goForward(); | ||
+ | } | ||
+ | if(choice == ' | ||
+ | { | ||
+ | goForwardRight(); | ||
+ | } | ||
+ | if(choice == ' | ||
+ | { | ||
+ | goForwardLeft(); | ||
+ | } | ||
+ | if(choice == ' | ||
+ | { | ||
+ | goBackward(); | ||
+ | } | ||
+ | if(choice == ' | ||
+ | { | ||
+ | goBackwardRight(); | ||
+ | } | ||
+ | if(choice == ' | ||
+ | { | ||
+ | goBackwardLeft(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | powerOff(); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int powerOn() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | outb(0x01, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int powerOff() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | outb(0x00, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int goForward() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x09, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int goForwardRight() | ||
+ | { | ||
+ | |||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x0B, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int goForwardLeft() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | outb(0x0D, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int goBackward() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x81, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int goBackwardRight() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x83, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int goBackwardLeft() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x85, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | To make things even more interesting I randomized the movement, and threw in some sleep functions to keep people on their toes. | ||
+ | |||
+ | <file c random_drive.c> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | |||
+ | //Prototype functions | ||
+ | int goForward(); | ||
+ | int goForwardRight(); | ||
+ | int goForwardLeft(); | ||
+ | int goBackward(); | ||
+ | int goBackwardRight(); | ||
+ | int goBackwardLeft(); | ||
+ | int powerOn(); | ||
+ | int powerOff(); | ||
+ | |||
+ | //The address where the printer port lives | ||
+ | int addr = 0x378; | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | |||
+ | int x, num, slp; | ||
+ | |||
+ | sleep(3); | ||
+ | srand(clock(NULL)); | ||
+ | |||
+ | for(x = 0; x < 145; x++) | ||
+ | { | ||
+ | |||
+ | num = rand() % 7 + 1; | ||
+ | slp = rand() % 2 + 1; | ||
+ | |||
+ | if(num == 0) | ||
+ | { | ||
+ | goForward(); | ||
+ | } | ||
+ | if(num == 1) | ||
+ | { | ||
+ | goBackward(); | ||
+ | } | ||
+ | if(num == 2) | ||
+ | { | ||
+ | goForwardRight(); | ||
+ | } | ||
+ | if(num == 3) | ||
+ | { | ||
+ | goForwardLeft(); | ||
+ | } | ||
+ | if(num == 5) | ||
+ | { | ||
+ | goBackwardRight(); | ||
+ | } | ||
+ | if(num == 6) | ||
+ | { | ||
+ | goBackwardLeft(); | ||
+ | } | ||
+ | if(num == 7) | ||
+ | { | ||
+ | powerOff(); | ||
+ | } | ||
+ | |||
+ | sleep(slp); | ||
+ | |||
+ | } | ||
+ | |||
+ | powerOff(); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Power on function - not very useful on its own, used to test for address verification | ||
+ | int powerOn() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | outb(0x01, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Power off - function to be called before each new set of instructions to put all outputs low | ||
+ | int powerOff() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | outb(0x00, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Forward function - pin addr 0x09 | ||
+ | int goForward() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x09, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Forward and right - pin addr 0x0B | ||
+ | int goForwardRight() | ||
+ | { | ||
+ | |||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x0B, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Forward and left - pin addr 0x0D | ||
+ | int goForwardLeft() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | outb(0x0D, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Reverse - pin addr 0x81 | ||
+ | int goBackward() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x81, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Reverse and right - pin addr 0x83 | ||
+ | int goBackwardRight() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x83, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | //Reverse and left - pin addr 0x85 | ||
+ | int goBackwardLeft() | ||
+ | { | ||
+ | int result = ioperm(addr, | ||
+ | powerOff(); | ||
+ | outb(0x85, addr); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | </ |