-
Rev 2 Completed
02/18/2016 at 02:21 • 0 commentsRev 2 is now (mostly?) completed. I have added an FTDI Bridge mode, where you can plug the controller into a computer and forward bytes from the wireless interface to USB and vice versa. I'm sure there will be some more adjustments to software in the coming weeks (to better support #Chiindii quadcopter), but hardware is completed (and has been for some time, I have just been lazy in documenting it).
A question you may ask is, what version to make? Rev 1 or Rev 2? The answer is 'it depends'.
Rev 1 is much easier to replicate, and is fully compatible with the official Stubby code.
Rev 2 takes a lot more custom work, custom PCBs, and hacked-together wiring. Furthermore, it is not completely compatible with Stubby (the framed serial protocol that it speaks is the same, but some of the messages being passed are different), plus it is missing some buttons that the real PS2 controller have.
In short, I would suggest making Rev 1 unless you have a good reason to do otherwise (notably, the need for a throttle control or display).
-
Bluetooth link working
09/30/2015 at 16:28 • 0 commentsLast night I put in the Bluetooth radio. I have decided to change to a physical DPDT switch rather than a multiplexer, since the MUX that I have on hand is a DIP version and is too large to fit into the case properly. (If I were designing a board for this, it would be no problem to use a SMD one, but deadbugging a DIP is way too large).
Next step is the XBee radio, and then we are just about done the hardware portion.
-
Stuffing Junk into a Case
09/25/2015 at 15:49 • 0 commentsI did some soldering last night. So far I have the PS2 controller circuit board, the UBBB32u4, the LCD display, and the boost power supply all soldered together and in the enclosure (which can still close). Still outstanding is the sliding pot, the radios, and the multiplexer. I am starting to get a bit nervous about fitting both radios and multiplexer into the enclosure... I suppose that if I need to, I can just put one radio in. I would like to get both if possible, though... oh well, we will see what happens.
Below are some pictures of the project so far (the front buttons are not installed here, as they were drying from a coat of stain that I just put on).
-
Rev 2.0 Schematic
09/23/2015 at 17:53 • 0 commentsYesterday I put the finishing coat of Danish Oil onto the new case, and put the original PS2 controller PCB into the top part of the case. I also finished up the (hopefully) final touches to the schematic. (While I am not planning on making a PCB for this, it is complicated enough that I do want a schematic, even though the implementation will just be on perf board).
The design allows for two radios (XBee and Bluetooth HC-06). Which radio is to be used will be selected by a 3-circuit binary analog multiplexer, which will switch power, Rx, and Tx.
Also included in the schematic is the charge pump which allows me to run the 5v LCD at 3.3v by providing the required negative bias voltage.
Still outstanding is making the supporting circuit on perfboard, updating the software to take advantage of all this, and actually fitting the entire thing together.
Enjoy!
-
New Case WIP
09/17/2015 at 01:51 • 0 commentsI have most of the case designed, and partially completed. It is made from multiple layers of 1/4" wood (various types), with holes cut for the different components. Pictures of what I have so far are below:
-
New Case + Features
08/27/2015 at 15:50 • 0 commentsAfter a long period without changes, I have decided to add some new features to the Universal Controller. I will be adding a display (so that the device being controlled can send messages, debug text, etc); a buzzer for alerts (low battery, etc); and a slide potentiometer for absolute position detection for things like throttle position. I plan on using 2x AA batteries with a boost regulator instead of the 3x AAA batteries + linear regulator that I am using currently.
I am also going to be ditching the plastic case and making a custom enclosure out of wood.
These changes should make the system more usable for some other devices, most notably a quadcopter that is currently in planning phases.
More details to follow once I actually make some progress.
-
Bugfixes after Protocol Change
09/08/2014 at 03:21 • 0 commentsIf you have a Universal Controller, and you have taken the recent protocol changes, please pull the latest code and redeploy. There are a couple of bug fixes which I have just pushed which, while quite simple, can make a large impact on how the thing works.
Bugs fixed include:
- Analog joystick change value mask should be 0xFC, not 0xF7
- MESSAGE_ANNOUNCE_CONTROL_ID should be sent every 2 - 3 seconds, not the ~10 minutes that it was previously (8 bit overflow vs 16 bit overflow actually makes a bit of difference... who'd have thunk it!)
-
Major changes to protocol
09/03/2014 at 02:42 • 0 commentsI had to think long and hard about whether it was a good idea to do this or not. One of the major goals in the Universal Controller was to keep things as simple as possible. Having all messages fit within one byte definitely helped this goal: there was no need for framing, escaping, checksums (I am assuming the link layer, XBee, keeps things sane here), etc.
Unfortunately, life is not simple.
While working on changes for Stubby to allow more fine grained programmatic control from a computer, I started running into limitations with the one byte messages. A major problem was that I had completely used the bit space; I had no spare messages which I could use to inform Stubby which controller was talking to it. Furthermore, I wanted the ability to send debugging information such as battery levels, etc (which is going to especially be needed when I start working on an RC airplane controlled by this Universal Controller... sometime... probably next year, once the Hackaday Prize is completed).
To alleviate this problem, I implemented a relatively simple bi-directional multi-byte protocol. This is included as a library for the AVR, and so can be used by multiple projects (and in fact I am already using this library in both Stubby and the Universal Controller). A single message in this protocol consists of the following sections:
- Start of Frame (1 byte, constant value 0x7e)
- Length (1 byte) (includes command byte but does not include checksum byte)
- Command (1 byte)
- Payload (0 - 254 bytes)
- Checksum
In the library itself, there are a number of commands defined for common things (ACK, EnableDebug, DisableDebug, RequestBattery, SendBattery, etc). These are all in the range 0x00 - 0x0F.
In the Universal Controller implementation, there are other commands defined. These include things like ButtonPush, ButtonRelease, JoystickMove (for allowing the controller to push state to the client) as well as things like SetPollFrequency and SetAnalogFrequency (to allow the client to configure the controller). All of these commands are in the range 0x10 - 0x1F.
So, in order to use the Universal Controller to control Stubby, both must be compiled from the code committed after today (September 2 2014). I sincerely apologize for any inconvenience, especially if you are using it to control other projects. If you have questions about how to implement this protocol support on the client side, please feel free to email me and ask.
Cheers
-
Slight Change to Protocol
04/24/2014 at 01:00 • 0 commentsWe made a few tweaks to the protocol today, in an effort to make things easier to implement on the client side, with fewer special cases. In addition, we created a client.h file in lib/universal_controller/client.h, which provides various #defines to simplify implementing the client side code.
The new protocol is as follows:
Sending button / stick events (from controller to client): Bit order: [TAAVVVVV] (analog stick event) [TN0SBBBB] (button event) Bit 8 (T, MSB): 0 == analog stick message, 1 == digital button message Analog stick message: Bit 7 (A) : 0 == Left stick, 1 == Right Stick Bit 6 (A) : 0 == X axis, 1 == Y axis Bit 5::1(V): Analog stick value: For the Y axis, 0x00 is all the way forward and 0x1F is all the way back; for the X axis, 0x00 is all the way left and 0x1F is all the way right. Digital button message: Bit 7 (N) : 0 == Normal button press / release event, 1 == No Buttons Pressed event. When bit 7 is 1, the remainder of the message is ignored. By convention we fill buts 6::1 with zeros in this state, meaning that the 'No button pressed' message will always be 0xC0. Bit 6 : Unused, set to 0 Bit 5 (S) : 0 = Released, 1 = Pressed Bit 4::1(B): Button number. Use lib/universal_controller/client.h for defines. Receiving client commands (from client to controller): Bit order: [CCXXXXXX] C: Command (see below) X: Command-specific message, left padded with zeros Commands: 00: Enable / Disable Buttons [000AAAAX] A: Button address. Specify a button to modify (0x00 - 0x0F). X: New value. 1 = enabled, 0 = disabled 01: Enable / Disable Analog Sticks [0100000X] X: New value. 1 = enabled, 0 = disabled 10: Set poll frequency (non-changes will be re-sent after this time) [10XXXXXX] X: New poll value, to be shifted 8 bits left and set in OCR1A. For instance, to set OCR1A = 0x0F00 (the default value), you would send the value 001111 (0x0F) as shifting this 8 bits gives 0x0F00. 0x0F (expanded to 0x0F00) results in an idle poll time of about 500ms. 0x3F (expanded to 0x3F00) results in an idle poll time of about 2s. 0x01 (expanded to 0x0100) results in an idle poll time of about 10ms. 0x00 results in completely disabling idle polling (only send change events). 11: Set maximum analog repeat frequency (you can't send analog stick changes faster than this). [11XXXXXX] X: New poll value, to be shifted 2 bits left and set in OCR0A. Analog values cannot be sent until this compare ISR fires. Set this high enough to not be sending un-needed data constantly, but low enough that you can get good response times from the controller. 0x3F (expanded to 0xFC) is the maximum, and results in an analog repeat time of about 32ms. 0x10 (expanded to 0x40) is the default, and results in an analog repeat time of about 8ms. 0x00 results in completely disabling the timer and sends all analog events, no matter how fast.
The client.h file includes the following defines:
//Bit 8: 0 == analog stick message, 1 == digital button message #define CONTROLLER_MESSAGE_TYPE_MASK 0x80 #define CONTROLLER_MESSAGE_TYPE_ANALOG 0x00 #define CONTROLLER_MESSAGE_TYPE_BUTTON 0x80 //Bit 7 (Analog): Left / Right stick #define CONTROLLER_ANALOG_STICK 0x40 #define CONTROLLER_ANALOG_STICK_LEFT 0x00 #define CONTROLLER_ANALOG_STICK_RIGHT 0x40 //Bit 6 (Analog): X / Y axis #define CONTROLLER_ANALOG_AXIS 0x20 #define CONTROLLER_ANALOG_AXIS_X 0x00 #define CONTROLLER_ANALOG_AXIS_Y 0x20 //Bit 5::1 (Analog): Value #define CONTROLLER_ANALOG_VALUE_MASK 0x1F //No Buttons Pressed message #define CONTROLLER_BUTTON_NONE 0xC0 //Bit 5 (Button): Press / Release #define CONTROLLER_BUTTON_PRESS_MASK 0x10 #define CONTROLLER_BUTTON_RELEASE 0x00 #define CONTROLLER_BUTTON_PRESS 0x10 //Bit 4::1 (Button): Button address #define CONTROLLER_BUTTON_VALUE_MASK 0x0F #define CONTROLLER_BUTTON_VALUE_SELECT 0x00 #define CONTROLLER_BUTTON_VALUE_LEFT3 0x01 #define CONTROLLER_BUTTON_VALUE_RIGHT3 0x02 #define CONTROLLER_BUTTON_VALUE_START 0x03 #define CONTROLLER_BUTTON_VALUE_PADUP 0x04 #define CONTROLLER_BUTTON_VALUE_PADRIGHT 0x05 #define CONTROLLER_BUTTON_VALUE_PADDOWN 0x06 #define CONTROLLER_BUTTON_VALUE_PADLEFT 0x07 #define CONTROLLER_BUTTON_VALUE_LEFT2 0x08 #define CONTROLLER_BUTTON_VALUE_RIGHT2 0x09 #define CONTROLLER_BUTTON_VALUE_LEFT1 0x0A #define CONTROLLER_BUTTON_VALUE_RIGHT1 0x0B #define CONTROLLER_BUTTON_VALUE_TRIANGLE 0x0C #define CONTROLLER_BUTTON_VALUE_CIRCLE 0x0D #define CONTROLLER_BUTTON_VALUE_CROSS 0x0E #define CONTROLLER_BUTTON_VALUE_SQUARE 0x0F
This simplifies (at least makes more clear) implementing code. For instance, this is a slightly simplified version of what is currently in use for Stubby, to read the left stick and the X button (assume 'b' is a uint8_t, and is the incoming message over the serial port):
if ((b & CONTROLLER_MESSAGE_TYPE_MASK) == CONTROLLER_MESSAGE_TYPE_ANALOG){ if ((b & CONTROLLER_ANALOG_STICK) == CONTROLLER_ANALOG_STICK_LEFT){ uint8_t value = b & CONTROLLER_ANALOG_VALUE_MASK; if ((b & CONTROLLER_ANALOG_AXIS) == CONTROLLER_ANALOG_AXIS_X){ x_value = value; } else if ((b & CONTROLLER_ANALOG_AXIS) == CONTROLLER_ANALOG_AXIS_Y){ y_value = value; } } } else if ((b & CONTROLLER_MESSAGE_TYPE_MASK) == CONTROLLER_MESSAGE_TYPE_BUTTON){ if ((b & CONTROLLER_BUTTON_PRESS_MASK) == CONTROLLER_BUTTON_PRESS){ cross_button_pressed = 0x01; } }
-
Communicating with a PS2 Controller
04/09/2014 at 22:17 • 0 commentsPS2 controllers are actually pretty easy to interface with; they use SPI mode 3 (CPOL=1 and CPHA=1); while in theory you could use the SPI hardware on an AVR to talk directly to the controller, I chose to just write my own (adapt my own) bit-banging protocol.
There are a few good sites which have protocol details; in our library, we started with Bill Porter's Arduino library, and adapted it to work with raw AVR-GCC rather than requiring Arduino.
Over time, I ended up re-writing much of the code (both because I could, and also to make the timings a bit closer to spec). The PS2 protocol details as described at http://store.curiousinventor.com/guides/PS2/#high_level were invaluable to this project; just because the hardware uses SPI, doesn't mean that it understands what you are sending!
In its current form, our PSX library provides a simple API for communicating with PS2 controllers. It allows for reading of all 16 buttons (everything other than the 'Analog' button, which is a special function), as well as 8 bit values for X and Y axis on both joysticks. It does not handle button pressures or vibration motors, but it would be relatively simple to add support for that if you are interested in it.
For details on the PSX library component, and to download the code, please see
http://digitalcave.ca/resources/avr/psx.jsp