Toybrain Returns Again

Posted: April 22nd, 2015 | Author: | Filed under: Robotics, ToyBrain | Comments Off on Toybrain Returns Again

I found a motor driver chip that looks promising. It does not support easy (solderless) swapping of the motor drivers, but I’ve also had a bit of a shift in my use case. I’m still looking to lobotomise and re-animate children’s toys, but I’m doing it for swarm robotics on the cheap, so being small outweighs replacing the motor driver chips.

The IC is the TI DRV8830. It is a 1A single-channel MOSFET H-bridge with an I2C interface and automatic current limiting. The automatic current limiting makes it very hard to blow the driver by overloading it, so I don’t have to worry about replacing the drivers as much.


Giving up on the Shark Joystick

Posted: April 5th, 2015 | Author: | Filed under: Reverse Engineering, Robotics | Comments Off on Giving up on the Shark Joystick

I’m going to hang on to the parts, but instead of reverse engineering the joystick control scheme for my Dynamic Controls Shark joystick, I’m going to replace the motor driver and everything related to it.

The main reason to give up on this is that it’s not the project I’m doing. The project is “build a mobility platform for fire art” not “reverse engineer a joystick”. Hacking the joystick would have helped with the real project, but it’s also a time sink. For $60, I can get a “100A” motor driver from China. It’s probably not good for 100A, but it will probably work well enough to let me get on with the rest of the project.

I had hoped that the existing motor driver was able to be easily converted to use my own control IC, but it has a very-fine-pitch surface mount part that appears to be custom silicon, so I can’t easily drop in a programmable replacement. THe custom chip is probably partly to blame for why I couldn’t interface to it, since only Dynamic Controls knows how they implemented the UART. I did figure out where the H-bridge drive lines were, so if I felt like it, I could probably drive it, but the difficulty would probably be on par with making my own driver, and the results would be messier.


Shark Interface Still Not Working

Posted: February 26th, 2015 | Author: | Filed under: Electronics, Programming, Reverse Engineering, Robotics | Comments Off on Shark Interface Still Not Working

Apparently, having figured out how the Shark joystick sends its information isn’t quite enough to get it working with the motor driver. I wrote software to send the same information that the joystick would usually send, but didn’t get a response. Then I assumed that the way the data lines both go high before serial signalling commences might have been some sort of init signal, so I have an Arduino configured to send the same information, and I still don’t get a response.

It’s entirely possible that I don’t have the bit timing exactly right for the serial link, so I’m now working on bitbanging the serial in a more adaptable way, so I can test different bit lengths.

I’m going to keep plugging away at it for a bit, but I also have a plan B: lobotomize the motor driver. Assuming it uses an ATMega8 like the controller, I can pull the control IC and replace it with one flashed with the Arduino bootloader, and then use rosserial_arduino to control it from ROS. That does mean I’d want to log what the controller does before pulling it, so I have a rough idea what signals go where, but it would vastly simplify controlling the system.


Playatech started charging for their plans

Posted: January 14th, 2015 | Author: | Filed under: Bad Ideas, Linux, Scripting | Comments Off on Playatech started charging for their plans

Unfortunately for burners, you can no longer download Playatech’s plans for their furniture without paying them first. They used to offer the plans as free downloads, and then asked that you donate some small amount if you used them.

Unfortunately for Playatech, they left all the PDFs in a world-readable directory. The command line below gets the index of that directory, finds all the lines with “pdf” in them, gets the file names out using cut, and then downloads each file.

for file in `wget -qO- http://playatech.com/wp-content/uploads/2013/05/ | grep pdf | cut -d ‘>’ -f 2 | cut -d ‘”‘ -f 2`; do wget http://playatech.com/wp-content/uploads/2013/05/$file; done


Further Hacking on the Shark

Posted: December 13th, 2014 | Author: | Filed under: Reverse Engineering, Robotics | Comments Off on Further Hacking on the Shark

In my previous post, I described how the messages being passed between the joystick and motor driver of my wheelchair appeared to be a differential serial signal at 40,000 bits per second. The data appears to be call and response pairs. Messages from the joystick start with a ‘`’ character, messages from the motor controller start with an ‘a’.
Each message usually has 8 fields with a numerical value in them, and messages end with ’15’.

Tonight, I recorded the signal as I swept the joystick in a clockwise circle, starting at 12:00/full speed forward. Then I graphed the values of each of the fields.

Joystick messages

Fields one and two in messages from the joystick are the forward/backward and left/right axis of the joystick, respectively. The center position is around 128, full forward/left is 255, full backwards/right is 128, so dead center/off should be around 128 + (255-128)/2 or 191.

Field 4 is a very noisy signal between 191 and 128. It appears to peak with field 1 and bottom out with field 1, so it may be the raw magnetic joystick sensor value for that axis.

Field 8 is a very noisy signal between 128 and 255, with clear diagonal slopes at the maximum and minimum of field 1. It may also be related to the raw joystick signal.

Fields 3, 5, 6, and 7 are 191, 128, 132, and 128 all of the time. The joystick has four non-power-button buttons and a power button, and these fields are used to report their values.

Pressing the speed buttons raises and lowers field 3, from a maximum of 255 to a minimum of 128, in 4 steps. There exists a mode that changes the speed in finer steps, but as configured, this is the way my system works. When the speed is lower than half-speed, field 4 has the range of 191 to 128. When the speed is higher than half-speed, field 4’s range is 191 to 255.

Field 5 is 128 when the horn button is not pressed, and 130 when it is pressed.

Field 6 is 132 when the joystick is on and running, and raises to 140

Field 7 is 128 when the joystick is in motion mode, and 129 when it is in seat mode. In seat mode, forward and backward motion of the joystick results in up and down motion of the seat height actuator. The joystick does report left and right motion as well in chairlift mode, but it doesn’t have any effect.

Field 9 is 15, for end-of-message.

Motor driver messages

Fields 7 and 8 are mirror images of each other. Field 7’s minimum appears to be 128, and its maximum is 144. Field 8 maxes out at 236 and has a minimum of 220, so it appears to be 364-field 7. I’m not sure what this field’s value indicates, but it appears to vary with the joystick position, so it may be some sort of current monitor or motor speed monitoring signal.

Field 1 goes from 128 to 146 as the system powers on, and stays there unless the chairlift is used. It appears to transition sharply to 178 when the chairlift moves up, and back when the chairlift moves down, so it is probably connected to the magnetic reed switch that senses the chairlift position.

Field 2 drops from 192 to 128 as the system powers on, and stays there. Fields 3, 5, and 6 are 128 all the time.

Field 6 goes from 128 to 129 the message after the joystick enters chairlift mode, so it is probably an acknowledgement to the joystick that chairlift mode was entered.

Field 4 goes from 128 to 160 as the system powers on, and stays there most of the time. It returns to 128 whenever the chairlift is not moving, so it may be related to breaking or motor activation. Before field 4 goes to 160, the joystick does not send any position commands, so the fields from 1 to 6 may be state signals that the motor driver sends to the joystick.

Field 9 is usually the end-of-packet field, but there are regular messages from the motor driver that are of the form

a '146' '128' '128' '160' '128' '128' '135' '229' '26' '133' '167' '185' '15'

rather than the more usual

a '146' '128' '128' '160' '128' '128' '135' '229' '15'
.

The additional values do not appear to change. The longer messages occur every 49th message, regularly, and starting with the second message from the motor driver, so I do not think that they are glitches.


Reverse Engineering the Dynamic Controls Shark Joystick

Posted: December 10th, 2014 | Author: | Filed under: Electronics, Reverse Engineering, Robotics | Comments Off on Reverse Engineering the Dynamic Controls Shark Joystick

No, not a joystick that lets you drive a shark. It’s a joystick for a mobility scooter or powerchair, as is used by people with disabilities.

There are a lot of resources on the internet that claim that the joystick uses CAN-Bus. This is because the signal is differential (there’s a “high” and “low” data line, and they are inversions of each other). However, I don’t think that this is the case. The microcontroller used in the joystick is the ATMega8, which doesn’t have a CAN controller. There are no CAN controllers or tranceivers in the joystick. On top of that, my friend Seth‘s Saleae logic analyzer can’t make head nor tails of the protocol using the normal CAN analysis modes.

So if it’s not CAN, what is it? There is an LM339 in the joystick, and another one in the motor control unit. These are quad differential comparators, and would be pretty handy if you wanted to hack your own differential serial lines, for noise immunity.

The asynchronous serial decoder of the logic analyzer did manage to decode the serial bit stream at 40000bps.

If the joystick data lines are unplugged and it is powered up, the only output is

t '129' '137' '134' '128' '133' '138' '166' '130' '196' '15'

repeated every 20ms (19.96937, actually, but who’s counting?).

If the joystick is plugged in, the startup does this:

t '129' '137' '134' '128' '133' '138' '166' '130' '196' '15'
'5' '130' '248' '15'
` '192' '191' '192' '141' '128' '140' '128' '199' '15'
a '128' '128' '128' '128' '128' '128' '128' '158' '15'
` '192' '191' '192' '141' '128' '140' '128' '199' '15'
a '128' '192' '128' '128' '128' '128' '128' '222' '26' '133' '167' '185' '15'
` '192' '191' '192' '141' '128' '140' '128' '199' '15'
a '128' '192' '128' '128' '128' '128' '128' '222' '15'
` '192' '191' '192' '141' '128' '140' '128' '199' '15'

I wrote a little script that parses the CSV output of the logic analyzer software and just prints a newline after each ’15’.

The main thing to notice about this is that the same initialization value is sent, but then it falls into a sort of call and response, with every other line starting with ‘a’ or ‘`’.

My guess is that these are communications passing back and forth between the joystick and the motor controller. I logged 20 seconds of the wheelchair sitting still and then counted all the unique messages that passed between the joystick and the motor controller.

Assuming that the above startup sequence is call and response, the message starting with ‘t’ and the ones starting with ‘`’ are the joystick, and the ones starting with ‘a’ are from the motor driver.

I sorted the commands out and counted the unique messages. They break down like this:


1 ` '191' '190' '192' '189' '128' '132' '128' '161' '15'
1 ` '191' '191' '192' '186' '128' '132' '128' '163' '15'
1 ` '192' '191' '192' '128' '128' '140' '128' '212' '15'
1 ` '192' '191' '192' '130' '128' '132' '128' '218' '15'
1 '5' '130' '248' '15'
1 a '128' '192' '128' '128' '128' '128' '128' '222' '26' '133' '167' '185' '15'
1 t '129' '137' '134' '128' '133' '138' '166' '130' '196' '15'
2 ` '191' '190' '192' '174' '128' '132' '128' '176' '15'
3 ` '191' '191' '192' '184' '128' '140' '128' '157' '15'
10 a '128' '192' '128' '128' '128' '128' '128' '222' '15'
14 ` '192' '190' '192' '135' '128' '132' '128' '214' '15'
20 a '146' '128' '128' '128' '128' '128' '128' '140' '26' '133' '167' '185' '15'
21 a '128' '128' '128' '128' '128' '128' '128' '158' '15'
22 ` '192' '191' '192' '129' '128' '132' '128' '219' '15'
34 ` '191' '191' '192' '176' '128' '132' '128' '173' '15'
37 ` '192' '191' '192' '128' '128' '132' '128' '220' '15'
40 ` '191' '190' '192' '190' '128' '132' '128' '160' '15'
57 ` '191' '190' '192' '182' '128' '132' '128' '168' '15'
70 ` '191' '191' '192' '185' '128' '132' '128' '164' '15'
139 ` '191' '190' '192' '183' '128' '132' '128' '167' '15'
290 ` '191' '191' '192' '184' '128' '132' '128' '165' '15'
294 ` '191' '190' '192' '191' '128' '132' '128' '159' '15'
954 a '146' '128' '128' '128' '128' '128' '128' '140' '15'

Most of the unique messages are from the joystick, and almost all of the messages sent back are the one at the bottom, with 954 occurances.

Let’s compare the messages from the motor controller. Bear in mind that nothing is moving at this point.


1 '5' '130' '248' '15'
1 a '128' '192' '128' '128' '128' '128' '128' '222' '26' '133' '167' '185' '15'
10 a '128' '192' '128' '128' '128' '128' '128' '222' '15'
20 a '146' '128' '128' '128' '128' '128' '128' '140' '26' '133' '167' '185' '15'
21 a '128' '128' '128' '128' '128' '128' '128' '158' '15'
954 a '146' '128' '128' '128' '128' '128' '128' '140' '15'

The first one is the startup acknowledgement. It never occurs again.

The next one and the one that occurs 20 times look similar, in that they both have four extra numbers in them. The first, second, and eighth values are the only ones that vary between them.

The one that occurs ten times mtches the one that occurs 21 times, except for the second and eighth fields, and doesn’t have the extended part.

The third through seventh fields are always ‘128’.

The first and second fields are always ‘128’, ‘146’, or ‘192’. The eighth field is always ‘222’, ‘140’, or ‘158’. The nineth field is either 26 or the end of transmission marker ’15’.

So what does all this mean?

I suspect that at least one of the values has something to do with the battery. The battery connects to the motor driver, but there is a battery level display on the joystick, so the motor driver must communicate some battery level information to the joystick.

The messages from the joystick have a similar pattern.


1 ` '191' '190' '192' '189' '128' '132' '128' '161' '15'
1 ` '191' '191' '192' '186' '128' '132' '128' '163' '15'
1 ` '192' '191' '192' '128' '128' '140' '128' '212' '15'
1 ` '192' '191' '192' '130' '128' '132' '128' '218' '15'
2 ` '191' '190' '192' '174' '128' '132' '128' '176' '15'
3 ` '191' '191' '192' '184' '128' '140' '128' '157' '15
14 ` '192' '190' '192' '135' '128' '132' '128' '214' '15'
22 ` '192' '191' '192' '129' '128' '132' '128' '219' '15'
34 ` '191' '191' '192' '176' '128' '132' '128' '173' '15'
37 ` '192' '191' '192' '128' '128' '132' '128' '220' '15'
40 ` '191' '190' '192' '190' '128' '132' '128' '160' '15'
57 ` '191' '190' '192' '182' '128' '132' '128' '168' '15'
70 ` '191' '191' '192' '185' '128' '132' '128' '164' '15'
139 ` '191' '190' '192' '183' '128' '132' '128' '167' '15'
290 ` '191' '191' '192' '184' '128' '132' '128' '165' '15'
294 ` '191' '190' '192' '191' '128' '132' '128' '159' '15'

The first and second values vary, but only slightly. The third value does not vary. the fourth value varies over the range 128-191. The fifth value does not vary. The sixth value varies, the seventh does not, the eighth does.

The joystick is a 4-axis device, with three buttons and a pair of binary inputs. My hope is that the values reported are something like the four joystick axes and the buttons, but the numbers don’t quite line up, as there are more buttons (5, three buttons plus two input jacks) than values left over after subtracting the joystick axes. Unless the jacks are in parallel with the buttons, that’s not what’s going on.

Recording from the data lines while the joystick is held in the forward position gives these unique lines:


1 ` '128' '191' '192' '134' '128' '132' '128' '150' '15'
1 ` '128' '192' '192' '130' '128' '132' '128' '153' '15'
1 ` '128' '192' '192' '132' '128' '132' '128' '151' '15'
1 ` '128' '193' '192' '131' '128' '132' '128' '151' '15'
1 ` '129' '191' '192' '165' '128' '132' '128' '246' '15'
1 ` '131' '191' '192' '170' '128' '132' '128' '239' '15'
1 ` '133' '191' '192' '176' '128' '132' '128' '231' '15'
1 ` '135' '190' '192' '191' '128' '132' '128' '215' '15'
1 ` '137' '190' '192' '190' '128' '132' '128' '214' '15'
1 ` '140' '190' '192' '135' '128' '132' '128' '138' '15'
1 ` '142' '191' '192' '130' '128' '132' '128' '140' '15'
1 ` '144' '191' '192' '156' '128' '132' '128' '240' '15'
1 ` '146' '191' '192' '156' '128' '132' '128' '238' '15'
1 ` '148' '191' '192' '149' '128' '132' '128' '243' '15'
1 ` '150' '191' '192' '150' '128' '132' '128' '240' '15'
1 ` '152' '191' '192' '164' '128' '132' '128' '224' '15'
1 ` '154' '191' '192' '186' '128' '132' '128' '200' '15'
1 ` '157' '191' '192' '153' '128' '132' '128' '230' '15'
1 ` '160' '191' '192' '136' '128' '132' '128' '244' '15'
1 ` '163' '191' '192' '145' '128' '132' '128' '232' '15'
1 ` '166' '191' '192' '153' '128' '132' '128' '221' '15'
1 ` '169' '191' '192' '161' '128' '132' '128' '210' '15'
1 ` '172' '191' '192' '145' '128' '132' '128' '223' '15'
1 ` '174' '191' '192' '179' '128' '132' '128' '187' '15'
1 ` '177' '191' '192' '139' '128' '132' '128' '224' '15'
1 ` '179' '191' '192' '139' '128' '132' '128' '222' '15'
1 ` '180' '191' '192' '188' '128' '132' '128' '172' '15'
1 ` '182' '191' '192' '181' '128' '132' '128' '177' '15'
1 ` '184' '191' '192' '172' '128' '132' '128' '184' '15'
1 ` '186' '191' '192' '172' '128' '132' '128' '182' '15'
1 ` '188' '191' '192' '140' '128' '132' '128' '212' '15'
1 ` '189' '191' '192' '156' '128' '132' '128' '195' '15'
1 ` '190' '191' '192' '132' '128' '132' '128' '218' '15'
1 ` '190' '191' '192' '147' '128' '132' '128' '203' '15'
1 ` '190' '191' '192' '163' '128' '132' '128' '187' '15'
1 ` '190' '191' '192' '171' '128' '132' '128' '179' '15'
1 ` '190' '191' '192' '172' '128' '132' '128' '178' '15'
1 ` '190' '191' '192' '181' '128' '132' '128' '169' '15'
1 ` '190' '191' '192' '190' '128' '132' '128' '160' '15'
1 ` '191' '191' '192' '141' '128' '132' '128' '208' '15'
1 ` '191' '191' '192' '173' '128' '132' '128' '176' '15'
1 ` '192' '191' '192' '133' '128' '140' '128' '207' '15'
1 ` '192' '191' '192' '135' '128' '132' '128' '213' '15'
1 ` '192' '191' '192' '150' '128' '132' '128' '198' '15'
1 '5' '130' '248' '15'
1 a '128' '192' '128' '128' '128' '128' '128' '222' '26' '133' '167' '185' '15'
1 a '146' '128' '128' '160' '128' '128' '134' '230' '26' '133' '167' '185' '15'
1 a '146' '128' '128' '160' '128' '128' '141' '223' '26' '133' '167' '185' '15'
1 a '146' '128' '128' '160' '128' '128' '145' '219' '26' '133' '167' '185' '15'
1 a '146' '128' '128' '160' '128' '129' '142' '222' '15'
1 a '146' '128' '128' '160' '132' '128' '135' '229' '15'
1 a '146' '128' '128' '176' '128' '128' '145' '219' '15'
1 a '146' '128' '132' '160' '128' '128' '146' '218' '15'
1 a '146' '129' '128' '160' '128' '128' '141' '223' '15'
1 a '146' '132' '128' '160' '128' '128' '143' '221' '15'
1 a '146' '132' '128' '160' '130' '128' '146' '218' '15'
1 t '129' '137' '134' '128' '133' '138' '166' '130' '196' '15'
2 ` '128' '191' '192' '133' '128' '132' '128' '151' '15'
2 ` '128' '191' '192' '135' '128' '132' '128' '149' '15'
2 ` '128' '192' '192' '134' '128' '132' '128' '149' '15'
2 ` '128' '194' '192' '130' '128' '132' '128' '151' '15'
2 ` '191' '191' '192' '188' '128' '132' '128' '161' '15'
2 ` '192' '191' '192' '131' '128' '132' '128' '217' '15'
2 ` '192' '191' '192' '140' '128' '132' '128' '208' '15'
2 a '146' '128' '128' '160' '128' '128' '146' '218' '26' '133' '167' '185' '15'
3 ` '128' '191' '192' '131' '128' '132' '128' '153' '15'
3 ` '192' '191' '192' '143' '128' '132' '128' '205' '15'
3 a '146' '128' '128' '128' '128' '128' '128' '140' '26' '133' '167' '185' '15'
4 a '146' '128' '128' '160' '128' '128' '130' '234' '15'
4 a '146' '128' '128' '160' '128' '128' '131' '233' '15'
4 a '146' '128' '128' '160' '128' '128' '136' '228' '15'
5 ` '128' '191' '192' '132' '128' '132' '128' '152' '15'
5 ` '128' '192' '192' '128' '128' '132' '128' '155' '15'
5 a '146' '128' '128' '160' '128' '128' '129' '235' '15'
5 a '146' '128' '128' '160' '128' '128' '133' '231' '15'
5 a '146' '128' '128' '160' '128' '128' '134' '230' '15'
5 a '146' '128' '128' '160' '128' '128' '138' '226' '15'
6 ` '128' '193' '192' '130' '128' '132' '128' '152' '15'
6 ` '192' '191' '192' '134' '128' '132' '128' '214' '15'
6 a '146' '128' '128' '160' '128' '128' '132' '232' '15'
6 a '146' '128' '128' '160' '128' '128' '137' '227' '15'
7 a '146' '128' '128' '160' '128' '128' '139' '225' '15'
7 a '146' '128' '128' '160' '128' '128' '141' '223' '15'
8 a '146' '128' '128' '160' '128' '128' '140' '224' '15'
9 ` '128' '193' '192' '129' '128' '132' '128' '153' '15'
9 ` '128' '193' '192' '132' '128' '132' '128' '150' '15'
9 ` '192' '191' '192' '141' '128' '140' '128' '199' '15'
9 a '146' '128' '128' '160' '128' '128' '145' '219' '15'
10 a '128' '192' '128' '128' '128' '128' '128' '222' '15'
10 a '146' '128' '128' '160' '128' '128' '135' '229' '15'
10 a '146' '128' '128' '160' '128' '128' '142' '222' '15'
10 a '146' '128' '128' '160' '128' '128' '143' '221' '15'
12 ` '128' '192' '192' '135' '128' '132' '128' '148' '15'
12 ` '128' '193' '192' '133' '128' '132' '128' '149' '15'
12 a '146' '128' '128' '160' '128' '128' '128' '236' '15'
12 a '146' '128' '128' '160' '128' '128' '144' '220' '15'
15 ` '128' '193' '192' '128' '128' '132' '128' '154' '15'
20 ` '128' '193' '192' '134' '128' '132' '128' '148' '15'
21 a '128' '128' '128' '128' '128' '128' '128' '158' '15'
24 ` '128' '194' '192' '129' '128' '132' '128' '152' '15'
25 ` '192' '191' '192' '141' '128' '132' '128' '207' '15'
26 ` '192' '191' '192' '142' '128' '132' '128' '206' '15'
30 ` '192' '191' '192' '133' '128' '132' '128' '215' '15'
33 ` '192' '191' '192' '132' '128' '132' '128' '216' '15'
63 ` '128' '194' '192' '128' '128' '132' '128' '153' '15'
64 ` '128' '193' '192' '135' '128' '132' '128' '147' '15'
126 a '146' '128' '128' '128' '128' '128' '128' '140' '15'
135 a '146' '128' '128' '160' '128' '128' '146' '218' '15'

Breaking out the motor driver packets gives:


1 a '128' '192' '128' '128' '128' '128' '128' '222' '26' '133' '167' '185' '15'
1 a '146' '128' '128' '160' '128' '128' '134' '230' '26' '133' '167' '185' '15'
1 a '146' '128' '128' '160' '128' '128' '141' '223' '26' '133' '167' '185' '15'
1 a '146' '128' '128' '160' '128' '128' '145' '219' '26' '133' '167' '185' '15'
1 a '146' '128' '128' '160' '128' '129' '142' '222' '15'
1 a '146' '128' '128' '160' '132' '128' '135' '229' '15'
1 a '146' '128' '128' '176' '128' '128' '145' '219' '15'
1 a '146' '128' '132' '160' '128' '128' '146' '218' '15'
1 a '146' '129' '128' '160' '128' '128' '141' '223' '15'
1 a '146' '132' '128' '160' '128' '128' '143' '221' '15'
1 a '146' '132' '128' '160' '130' '128' '146' '218' '15'
2 a '146' '128' '128' '160' '128' '128' '146' '218' '26' '133' '167' '185' '15'
3 a '146' '128' '128' '128' '128' '128' '128' '140' '26' '133' '167' '185' '15'
4 a '146' '128' '128' '160' '128' '128' '130' '234' '15'
4 a '146' '128' '128' '160' '128' '128' '131' '233' '15'
4 a '146' '128' '128' '160' '128' '128' '136' '228' '15'
5 a '146' '128' '128' '160' '128' '128' '129' '235' '15'
5 a '146' '128' '128' '160' '128' '128' '133' '231' '15'
5 a '146' '128' '128' '160' '128' '128' '134' '230' '15'
5 a '146' '128' '128' '160' '128' '128' '138' '226' '15'
6 a '146' '128' '128' '160' '128' '128' '132' '232' '15'
6 a '146' '128' '128' '160' '128' '128' '137' '227' '15'
7 a '146' '128' '128' '160' '128' '128' '139' '225' '15'
7 a '146' '128' '128' '160' '128' '128' '141' '223' '15'
8 a '146' '128' '128' '160' '128' '128' '140' '224' '15'
9 a '146' '128' '128' '160' '128' '128' '145' '219' '15'
10 a '128' '192' '128' '128' '128' '128' '128' '222' '15'
10 a '146' '128' '128' '160' '128' '128' '135' '229' '15'
10 a '146' '128' '128' '160' '128' '128' '142' '222' '15'
10 a '146' '128' '128' '160' '128' '128' '143' '221' '15'
12 a '146' '128' '128' '160' '128' '128' '128' '236' '15'
12 a '146' '128' '128' '160' '128' '128' '144' '220' '15'
21 a '128' '128' '128' '128' '128' '128' '128' '158' '15'
126 a '146' '128' '128' '128' '128' '128' '128' '140' '15'
135 a '146' '128' '128' '160' '128' '128' '146' '218' '15'

Now it seems that every value varies at least once. I’m not sure yet what to make of this, but I feel like I’m on the right track.


Flickr Downloadr that really works

Posted: December 6th, 2014 | Author: | Filed under: B work, Linux, Scripting | Comments Off on Flickr Downloadr that really works

Not my work. Get it here.

It does exactly what it says on the tin. This is letting me close a years-old open loop I had, which is that Flickr had a lot of my photos, but sucked so bad that I didn’t want to reward them with money in order to get my photos back.

As soon as the download is done, that Flickr account is toast.


Un-Ubuntuing Ubuntu, Again

Posted: December 5th, 2014 | Author: | Filed under: B work, Linux | Comments Off on Un-Ubuntuing Ubuntu, Again

Ubuntu makes no secret of the fact that they will choose something that looks good but doesn’t work over something that works. That’s pretty much the entire point of this blog post. Because xscreensaver uses an older X widget kit than light-locker, and so looks “antiquated”, they switched to light-locker for 14.04. Light-locker doesn’t atually work well, and causes many, many, many laptops to not return from suspend mode without a hard reset.

If you’d rather use software that works, you have to change some settings and remove a bunch of stuff. I removed light-locker, light-locker-settings, and gnome-screensaver. I also installed xscreensaver.

In order to lock on lid close, I started xfce4-settings-editor, selected xfce4-power-manager, and set/checked both lock-screen-suspend-hibernate and logind-handle-lid-swtich.

I currently get two login prompts when I unsuspend, one from xscreensaver and one from something else. I suspect the second one is logind, so I can get rid of the xscreensaver one by making xscreensaver not do screen locking.


Lessons learned by being The Worst Game Developer

Posted: October 27th, 2014 | Author: | Filed under: Art, Programming, Video Games | Comments Off on Lessons learned by being The Worst Game Developer

I’m writing a video game. It is called Pebble, and in Pebble, there is a pebble. You contemplate the pebble. I haven’t decided if there is going to be music or not, but there will be a pebble, in a featureless grey expanse, and you can contemplate it.

Just thinking about writing this game has brought me some interesting realizations. I doubt I’m the first one to have them, but it was neat to see how they all fit together.

The first realization is just a recap of things I already knew about developing software: “You’re going to throw the first one away” and “Do the simplest thing that could possibly work”.

When I first came up with the idea for Pebble, it was as a tech demo for Tree, which is similar (There is a tree, you contemplate it), but more complicated, in that a tree is larger. I was going to use level-of-detail (LoD) rendering to support real-time generative zoom from birds-eye to bugs-eye views, store seeds so that the generated versions didn’t change between runs, etc. I read a bunch of papers on the topics, and saw that it was all very complex. I also hadn’t written anything, despite having read a lot of papers and learned a bit.

Eventually, I realized that if I had to load everything I needed to know into my head to write this game, first, I wouldn’t get around to writing it, and second, my head would explode.

Instead of either of those things, I’m writing the simplest bit of code that will draw something on my screen. The first version will draw a polygon, the second version will rotate it, and the third version will texture it. I’m going to have two code streams, one written using openFrameworks and one written using Polycode, so I can decide which of those libraries I’d rather use.

Once both libraries are through three versions, I’ll have the simplest thing that could possibly work, and I’ll throw the other one away.

Another revelation I had is that I don’t really know what pebbles look like. I mean, I have a general idea, but to render a pebble, a general idea doesn’t cut it. It doesn’t capture the variety of surface types that different kinds of weathering can cause, the colors of all the different rocks, and so forth. The reality of pebbles is way more complicated than the idea of pebbles

My girlfriend and I went out on a beach on Cape Cod, Massachusetts, and looked at pebbles. Cape Cod is a terminal moraine, so the rocks there were pushed by glaciers from everywhere north of Cape Cod, and there are loads of different kinds of pebbles there.

This has two effects on my thinking about the design of Pebble, and of video games in general. The first is that the stone surface generation algorithim should be the simplest thing that could possibly work. The second is that AAA games in their current form are doomed.

AAA games have a huge amount of their budget dedicated to resources, such as the textures and designs of the characters. Because the current marketing push in video games is visual, each game is supposed to have better and better graphics than those before it, or people will mock it and it will loose sales. However, this is an infinite pit. Any game world is a map, a less-detailed reperesentation that conveys an impression of a more detailed real world. With real maps, the real world is assumed to also exist, but in games it doesn’t. You run around in Libery City in Grand Theft Auto, but “you” don’t “run” “around”. By pressing buttons, you cause the appearance of motion in a simulated person within a simulated, restricted world. The better the simulation gets, the more resources it requires. In real-world NYC, if you go to Battery Park, you can pick up gravel and throw it in the harbor. In the analogous unplaces in GTA, the ground is a perfect solid, smooth and impenetrable. In order to create a more perfect simulation, there would have to be simulated pebbles, and someone would have to create them.

All of these resources, the pebbles, clothes, guns, car tires, trees, buildings, and so forth in a video game are made by people. These people get paid, and so the more detail you want in a game, the more resources you need, and so the more people you have to pay. Taking longer to make the game doesn’t work, as the technology is constantly shifting, so “more people” is pretty much the only going solution at this point. Even licensing IP from other companies is just an abstraction of getting more people to work on the project.

As a result, the drive is now to make games more and more expensive to make, in order to get finer and finer quality of details that add nothing to the narrative, but make the finished package prettier. However, people are not going to pay hundreds of dollars for a game (except possibly that version of MechWarror that came with a big robot control console), so either the game market has to grow without bound, or the industry has to start putting an upper bound on how much they can invest in making a game.

In a way, I’m hoping Pebble is a signpost on the path of excessive detail, a huge amount of clever rendering algorithims and generative textures in pursuit of the perfect simulation of the experience of contemplating a small stone. Whether the signpost says “Welcome!” or “Abandon Hope All Ye Who Enter Here” is an exercise for the reader.


Well THAT’S messy

Posted: October 7th, 2014 | Author: | Filed under: Linux, Scripting | Comments Off on Well THAT’S messy

for file in ../connections_2014-10-7-1*; do conn="-c ../connections_"`echo $file | cut -d "_" -f 2`; types="-t ../neuron_types_"`echo $file | cut -d "_" -f 2`; locs="-l ../locations_"`echo $file | cut -d "_" -f 2`; ./pickle_to_json.py $conn $types $locs; done

For all the connection files that were generated today, create three variables called “conn”, “types”, and “locs” that have a command line switch path in them generated from a fixed prefix and a cut from the connection file name. Then invoke the script “pickle_to_json.py” with those variables as arguments.

Effectively, the connection, neuron type, and location files are all related by their date, so this makes a single JSON file out of the multiple files. I just didn’t want to run pickle_to_json.py a bunch of times by hand, as that seemed error-prone.