1ChannelSound

I realized I didn’t have this posted up- this is the single channel mp3 sound card from mdfly.com combined with a simple audio amp. The amp is quite loud and can be built with parts from Radio Shack. This is what I’m using on my RS3 in the pictures below. I’m using the Attiny 1634 s/w UART to drive this from the client widget. It works quite well, you just send a single byte to the card to set the volume or play one of the sounds. However, you get what you pay for, $10 only gets you one sound at a time.

P1040103

P1040101

P1040102

As the weather prevents me from going outside, I’m back to the internals. Here are a couple of shots of my control system going into my Aristocraft RS3. The power is all in the back end, I have a 5000mah 14.8v lipo pack driving this beast with a Pololu 18v7 motor controller powering the trucks. A very potent drive train. Anyhow, these pics show the brains- the Atmel 1634 board, the Xbee Series 1 and the MDFly mp3 sound card. Not seen is the RFID reader on the fuel tank- I’ll post that up later. Phew, some work and lots of engineering spits and fails but it’s now pretty clean and works well. I did downsize the controls a bit, I’m only driving the motor, the two coupler servos and the sound card. I left the lights on a manual switch and there is a current sensor in there but I’m not looking at it right now. As mentioned, the RFID is also connected and works so I do have the basics of a computer controlled system. The main control boards are also reasonably accessable by taking off just the short hood of the locomotive so tweaking the firmware, sounds and the pololu motor controller won’t require the entire locomotive to be taken apart (which is a BITCH to say the least!)

RS3Finished

Finally have all of the connections wired and (more or less) tested. I’ve added LEDs to the running lights and servos (not shown) to control the couplers. Just need to add about 11oz or so to the fuel tank and put it all back together for final testing. I’ve attached a programming cable to the microcontroller board so I can download new builds or tweak the s/w if required. Phew. This has been quite a bit of development. The control widget itself went through many interations (see controlwidgets.com) as did the power board. I’ve settled on the Pololu 18v7 programmed to only give forward motion with a relay switching between forward and backward. Anyhow, soon we will be doing some real world testing.

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;