powerboard

Main power board I’m working on for my Aristocraft RS-3. I removed all the old radio R/C gear and the nimh batteries and am replacing it with a new control widget, this board, the pololu motor controller (on the right) and a big 5000mah lipo. Should be interesting.

hhd-A
hhd-B

Here is my latest stand-alone hand-held-throttle design. It’s based on my control widget thing and I (finally) have it all working.

All the circuits and keyboard are mounted on a 3D printed faceplate with a 3D printed back enclosure. It still needs some structural work, screws to hold the face plate on and I need to mount the power switch too, not sure where that should go.

There is some hard-coded stuff in the handheld software but it does work quite well. I also have a slight design gotcha on my USB interface into this thing but I’ll get that solved soon.

pir-widget

I’m really enjoying my widget PCB design. Simple, cheap, easy bake oven for SOIC, program in C, add an Xbee for wireless real-time control, how cool is that? Here I have one hooked up to a parallax IR motion sensor. With a bit of C code it controls the servo based on the input from the motion sensor. Think railroad crossing signals- that crossing arm that comes dowm and blocks the traffic, right?

Anyhow, great fun and a good project to post over to controlwidgets.com

I’m looking at a $9 retail for board and components. Software will be free and open source. Of course :)

I’m going down much the same road with my new widgets as I did with the Wixels- depending on the software loaded and the application, a Widget can be a client or controller. A client can be a locomotive, turnout or any other device that is controlled via servos or discrete outputs. The controler can be a hand-held interface and/or a computer. In my case this is my Raspberry Pi, configured as a web server/web sockets host.

To that end, I coded up a quick Xbee interface for the Raspberry Pi in python that works with the datagrams in my set of train/control widgets. It’s extremely minimalistic (of course) but allows you to send standard ‘AT’ commands to the Xbee and also send advanced API datapackets. This code assumes that you have an Xbee module configured with X-CTU. I’m using the Parallax Xbee USB board to do this. You will need to set the interface baud rate of the Xbee to 38400 baud and place the Xbee in API mode. Once configured, move the Parallax board to the Raspberry Pi and that’s it. Destination Xbee modules (configured as above) will receive this data (based on it’s destination address of course) and pass this out the serial port to the host. In this case, the host is (will be) my train widget boards. Once they are available that is, perhaps early March (I hope)

Anyhow, you can now control Train Widgets with the following code or adapt it to your own xbee design. XbeeTransmitDataFrame is the primary control interface. All servo, sound and sensor data uses this fixed length datagram. It’s compact and fast and offers 65K of possible command codes (I’ve implemented 3 so far).

xbeeSendDataQuery is used to do a standard ‘AT’ command using the API mode. For example, you can pass ‘M’ and ‘Y’ to this method and it will return the 16 bit node address of the Xbee. Any of the other AT commands can be used as well but you will have to get the data using serial.read() and know where in the packet the return value and how long it is.

xbeeTransmitDataFrame is used to send the 16 byte packets I’ve made up for my implementation. You can see how these are constructed from the C structures below.


import serial

class xbeeController:
    def __init__(self):
        usbPort = '/dev/ttyUSB0'
        self.sp = serial.Serial(usbPort, 38400)

    def xbeeReturnResult(self, datalength):
        return(self.sp.read(datalength))

    def xbeeDataQuery(self, cmdh, cmdl):
        frame = []
        c0 = ord(cmdl)
        c1 = ord(cmdh)
        frame.append(0x7e)	# header
	frame.append(0)	        # our data is always fixed size
	frame.append(4)         # this is all data except header, length and checksum
	frame.append(0x08)      # AT COMMAND - send Query to Xbee module
	frame.append(0x52)	# frame ID for ack- 0 = disable
	frame.append(c1)	# Command high character
	frame.append(c0)	# low character
	frame.append(0)	        # zero checksum location

	cks = 0;
	for i in range(3,7):	# compute checksum
	    cks = cks + frame[i]

	i = (255-cks) & 0x00ff
	frame[7] = i	        # and put it in the message

	for i in range(0,8):	# send it out the serial port to the xbee
            self.sp.write(chr(frame[i]))
	
    def xbeeTransmitDataFrame(self, dest, data):
        frame = []
        frame.append(0x7e)	# header
	frame.append(0)	        # our data is always fixed size
	frame.append(21)        # this is all data except header, length and checksum
	frame.append(0x01)      # TRANSMIT REQUEST - send Query to Xbee module
	frame.append(0)	        # frame ID for ack- 0 = disable
	frame.append( (dest>>8) & 0x00ff) # Destination address
	frame.append( (dest & 0xff))
        frame.append(0)         # disable ack for fastest transmission

        for i in data:          # move data to transmit buffer
            frame.append(i)
        frame.append(0)         # checksum position

	cks = 0;
	for i in range(3,25):	# compute checksum
	   cks += frame[i]

	i = (255-cks) & 0x00ff
        frame[24] = i

	for i in range(0,25):	# send it out the serial port to the xbee
            self.sp.write(chr(frame[i]))


This is the xbee header information that is in the Widgets. This defines the three control packets I’m sending with the Xbee. These are the 16 bit fixed length packets that ride in the transport area of the above datagram. By keeping them small, I’m getting a 7ms packet transmit time which is very fast.


#define CONTROLLER   0x0000				// XbeeCTRLPacket{}
#define RFIDCOMMAND  0x0010				// XbeeRFIDPacket{}
#define SOUNDCOMMAND 0x0011				// XbeeSOUNDPacket{}
	
typedef struct
{
	uint16_t destinationAddress;		// Xbee destination address for this client
	uint16_t sourceAddress;				// This node's address
	uint16_t commandID;					// 16 bit command ID
	uint16_t Sound0;					// 16 Bits of Sound Triggers
	uint16_t Sound1;
	uint16_t Sound2;
	uint16_t Sound3;
	uint16_t Sound4;
} XbeeSOUNDPacket;
	

typedef struct
{
	uint16_t destinationAddress;		// Xbee destination address for this client
	uint16_t sourceAddress;				// This node's address
	uint16_t commandID;					// 16 bit command ID
	uint16_t RFID0;						// 12 bytes of ascii RFID info
	uint16_t RFID1;
	uint16_t RFID2;
	uint16_t RFID3;
	uint16_t misc1;
} XbeeRFIDPacket;

typedef struct
{
	uint16_t destinationAddress;		// Xbee destination address for this client
	uint16_t sourceAddress;				// This node's address
	uint16_t commandID;					// 16 bit command ID
	uint16_t Servo0;					// Servo 0
	uint16_t Servo1;
	uint16_t Servo2;
	uint16_t Discrete;
	uint16_t misc1;
} XbeeCTRLPacket;