Wishful Coding

Didn't you ever wish your
computer understood you?

Raspberry Pi autopilot, Part 1 of many

raspilot

There is of course Navio+ and Ardupilot and possibly many others, but what is the fun in that? I’m building my own.

It will be powered by a Raspberry Pi. The extra processing power is nice, but the main reason was that it’s easy to attach a 3G dongle and a camera module. I plan to write the software in Elixir, just because I can.

So far I connected a bunch of breakout boards and poked them for a bit. I have:

I placed the Arduino to the left with PORTD facing down. You’ll see why this is important in a second. The GND and +5V rows line up such that if you insert 3 header pins in the bottom rows, you can plug servos into them.

The Arduino runs at 5V to drive the servos, so a level shifter is needed to talk to the Raspberry Pi, which runs at 3.3V.

I put the level shifter to the right, running the I2C wires through it to the Arduino. I used I2C because I can attach many more sensors to the same 2 wires, and I need the UART for the GPS board.

The main reason for not using a pre-made servo HAT is that I want servo inputs as well as outputs, to support switching back and forth between autonomous and manual control, or even something in between.

For now the plan is to power the Raspberry Pi, servos, and Arduino form the BEC(Battery Elimination Circuit) of the ESC(Electronic Speed Controller). But I might have to use a separate UBEC if it turns out the BEC I have is not powerful enough.

The Arduino Sketch so far is pretty simple. It uses the Wire library to talk to the Raspi, and the Servo library to talk to the servos. The only tricky bit is the pin change interrupt on PORTD to read the input from the receiver.

So I can now read the receiver and move the servos over I2C, as well as talk to all the other sensor boards. More later as I get some software working.

Female League of Legends characters

I've been putting off writing about this for a while. Looking at the whole gamer gate thing, it seems like feminism and gamers don't go together very well.

As of late I've been playing some casual League of Legends with my brother. Besides the usual gamer behaviour, I was also irked by some of the champions.

I understand that it's a fantasy game, so I'm okay with boob plate armour and I don't expect extreme realism, but to be honest some of these champs look like they walked right out of some red light district.

There are a few exceptions, but most are scarcely clad, have huge breasts and hips, and some even do pole dancing and flirting in-game.

In [79]:
from IPython.display import HTML
sexy = ['MissFortune', 'Ashe', 'Leblanc', 'Zyra', 'Evelynn', 'Janna', 'Morgana', 'Nidalee', 'Caitlyn', 'Katarina']
HTML(''.join(['<span></span><img src="img/%s_0.jpg" style="float:left;" />' % name for name in sexy]))
Out[79]:

I had the impression that their in-game roles and stats where also rather stereotypical, most of them being squishy mages.

But I can't go around saying things like that without any data to back it up, so I downloaded champion stats from the Data Dragon and loaded it into Python to do some exploration.

In [80]:
%matplotlib inline

import json
import pandas as pd
import collections

def flatten(d, parent_key='', sep='_'):
    items = []
    for k, v in d.items():
        new_key = parent_key + sep + k if parent_key else k
        if isinstance(v, collections.MutableMapping):
            items.extend(flatten(v, new_key, sep=sep).items())
        elif isinstance(v, collections.MutableSequence):
            for i, li in enumerate(v):
                items.append(("%s%s%d" % (new_key, sep, i), li))
        else:
            items.append((new_key, v))
    return dict(items)

with open("champion.json") as f:
    data = json.load(f)
    
flat = {key: flatten(value) for key, value in data.items()}
df = pd.DataFrame.from_dict(flat, orient="index")

I manually divided the champions into genders, including an 'other' gender so I don't have to argue over the gender of a cat... unless that cat is wearing a bra.

It appears that there is a pretty even divide between men, women, and monsters. Yay.

A funny thing to mention is that even though people sometimes assume every player is a 'he', often people refer to others by the gender of their champion.

In [81]:
df['gender'].value_counts().plot(kind='pie')
Out[81]:
<matplotlib.axes._subplots.AxesSubplot at 0x10d450978>

Next I looked at the average stats of the champions. Here we start to see that women in League of Legends have on average less defence and more magic than men and monsters. This makes sense, given the amount of armour they are wearing.

Women also had a slightly higher difficulty than the other genders but the difference was negligible. I removed that data to save you from bad jokes.

In [82]:
(df.groupby('gender')
 [['info_defense', 'info_attack', 'info_magic']]
 .mean()
 .plot(kind='bar')
 .legend(loc='upper center', bbox_to_anchor=(0.5, 1.2), ncol=5))
Out[82]:
<matplotlib.legend.Legend at 0x10c753ba8>

Next up are the roles champions have in-game.

There are over twice as many male tanks compared to female tanks, but both are dwarfed by the monster tanks. Fighters are also dominated by men and monsters.

On the other hand, mages and supports are primarily female. A small surprise is the large number of markswomen(ranged physical attackers).

Assassins seem to be the most equal role.

In [83]:
primary = df[['tags_0', 'gender']]
primary.columns = ['role', 'gender']
secondary = df[['tags_1', 'gender']]
secondary.columns = ['role', 'gender']
roles = pd.concat((primary, secondary))
roles.groupby(['role', 'gender']).gender.count().unstack().plot(kind='barh')
Out[83]:
<matplotlib.axes._subplots.AxesSubplot at 0x10d6fb438>

That is it for now. It was fun to experiment with Pandas and IPython notebooks. You can see the source at Github.

ADNS-9800 hookup guide

Ever since I made my wooden mouse using this ADNS-9800 breakout, I’ve been getting emails and comments asking for help connecting the ADNS-9800 to a Teensy and programming it.

So this is my attempt at writing down all stuff you need to know. I promise it’s not hard if you know anything about Arduino and programming. If you don’t, you might want to reconsider your mouse-building plans.

It seems to be a bit confusing to some people how to connect the wires. On the breakout is a 2x4 header with labels, and the author has helpfully provided a list of what they do. (with a few minor additions of mine)

  • MI = MISO (Master In, Slave Out) (DIN on Teensy 3)
  • MO = MOSI (Master Out, Slave In) (DOUT on Teensy 3)
  • SS/SC = Slave Select / Chip Select
  • SC/SCK/SLCK = SPI Clock
  • MOT = Motion indicator (active-low interrupt line)
  • AG = Analog Ground (connect to common ground near power supply)
  • DG = Digital Ground (connect to common ground near power supply)
  • VI = Voltage in, up to +6V (See note about voltage)

Next you find the pinout for your Teensy and match up the labels.

Teensy pinout

It should be noted that slave select and the motion pin can be connected to any GPIO at all. Although a pin with an interrupt is preferred for the motion pin.

Another important fact is that the Teensy 3 runs at 3.3v while the Teensy 2 runs at 5v. From the author:

If you are using Arduino or another similar microcontroller that has a native 5V core voltage, you’ll need to activate 5V mode by cutting the tiny traces between the three sets of exposed pads on the 3.3V side of the board and adding three solder bridges to the exposed pads on the 5V side of the board.

Next up, you install Teensyduino, read the example code or the code for my mouse and adapt it for your needs.

You’ll see there is one file with a binary blob that is the firmware for the sensor. This is loaded at startup by the other file containing the main program.

At the top you’ll find a list of all the registers, the meaning of which can be found in the datasheet.

Then the SPI is initialised and perform_startup is called to start the sensor. Finally a FALLING interrupt is attached to the MOT pin. This triggers when the sensor has moved. When this happens you pull low the CS and read the motion registers with adns_burst_motion.

At the bottom of my code are a bunch of functions named adns_*. They are mostly copied from the example code and can be used to to read/write registers on the sensor.

Good luck!