Category Archives: Python

BeagleBone Dynamixel AX12 Interface – Part 2.5

More progress on my Dynamixel to BeagleBone interface experimentation…

I now have enough of the the Dynamixel communication protocol working to both read and write to any address in the servos control table.

This video demonstrates reading the present position from on servo and updating the goal position of a second servo. The video also features a great new USB Logic 16 from saleae I have recently purchased.

Below please find the python code used in the video. It is by no means final or finished. It was just a quick mock-up to test the hardware. It is however a good starting point or reference for others who want to experiment with the same setup.

import serial
import time

UART2_PORT = "/dev/ttyO2"
UART2_BAUD = 115200
UART2_TX = "spi0_d0"
UART2_RX = "spi0_sclk"
UART2_TXMUX = 1
UART2_RXMUX = 33

UART2_TXIO = 117
UART2_RXIO = 49

AX_ID = 2
AX_LENGTH = 3
AX_INSTRUCTION = 4
AX_PARAMETER = 5
AX_WRITE = 3
AX_READ = 2

open("/sys/class/gpio/unexport", "w").write("%d" % UART2_TXIO)
open("/sys/class/gpio/export", "w").write("%d" % UART2_TXIO)
open("/sys/class/gpio/gpio" + str(UART2_TXIO) + "/direction", "w").write("out")

open("/sys/class/gpio/unexport", "w").write("%d" % UART2_RXIO)
open("/sys/class/gpio/export", "w").write("%d" % UART2_RXIO)
open("/sys/class/gpio/gpio" + str(UART2_RXIO) + "/direction", "w").write("out")

open("/sys/kernel/debug/omap_mux/" + UART2_TX, "wb").write("%x" % UART2_TXMUX)
open("/sys/kernel/debug/omap_mux/" + UART2_RX, "wb").write("%x" % UART2_RXMUX)
ax = serial.Serial(UART2_PORT, UART2_BAUD)

def checksum(packet):
        check = 0
        for i in range(AX_ID, (packet[AX_LENGTH] + 3)):
                check += packet[i]
        return 255 - (check % 256)

def settx():
    open("/sys/class/gpio/gpio" + str(UART2_TXIO) + "/value", "w").write("%d" % 1)
        open("/sys/class/gpio/gpio" + str(UART2_RXIO) + "/value", "w").write("%d" % 0)

def setrx():
    open("/sys/class/gpio/gpio" + str(UART2_TXIO) + "/value", "w").write("%d" % 0)
        open("/sys/class/gpio/gpio" + str(UART2_RXIO) + "/value", "w").write("%d" % 1)

def txrx(txp, rxp):
        txlength = txp[AX_LENGTH] + 4
        rxlength = 0

        txp[0] = 0xff
        txp[1] = 0xff
        txp[txlength - 1] = checksum(txp)

        settx()
        for i in range(txlength): ax.write(chr(txp[i]))
        setrx()

        if txp[AX_INSTRUCTION] != 254:
                if txp[AX_INSTRUCTION] == AX_READ: rxlength = txp[AX_PARAMETER + 1] + 6
                else: rxlength = 6

                time.sleep(.02)
                for x in range(ax.inWaiting()): rxp[x] = ord(ax.read())
                for x in range(txlength + 1): rxp.pop(0)

                if rxp[0] != 255 and rxp[1] != 255: return -2
                if rxp[rxlength - 1] != checksum(rxp): return -3

                return 1

        return 1

def readbyte(id, address):
        txpacket = [0]*8
        rxpacket = [0]*30

        txpacket[AX_ID] = id
        txpacket[AX_LENGTH] = 4
        txpacket[AX_INSTRUCTION] = AX_READ
        txpacket[AX_PARAMETER] = address
        txpacket[AX_PARAMETER + 1] = 1

        result = txrx(txpacket, rxpacket)
        value = rxpacket[AX_PARAMETER]
        return result, value

def readword(id, address):
        txpacket = [0]*8
        rxpacket = [0]*30

        txpacket[AX_ID] = id
        txpacket[AX_LENGTH] = 4
        txpacket[AX_INSTRUCTION] = AX_READ
        txpacket[AX_PARAMETER] = address
        txpacket[AX_PARAMETER + 1] = 2

        result = txrx(txpacket, rxpacket)
        value = ((rxpacket[AX_PARAMETER + 1] << 8) + rxpacket[AX_PARAMETER])
        return result, value

def writebyte(id, address, value):
        txpacket = [0]*8
        rxpacket = [0]*30

        txpacket[AX_ID] = id
        txpacket[AX_LENGTH] = 4
        txpacket[AX_INSTRUCTION] = AX_WRITE
        txpacket[AX_PARAMETER] = address
        txpacket[AX_PARAMETER + 1] = value

        return txrx(txpacket, rxpacket)

def writeword(id, address, value):
        txpacket = [0]*9
        rxpacket = [0]*30

        txpacket[AX_ID] = id
        txpacket[AX_LENGTH] = 5
        txpacket[AX_INSTRUCTION] = AX_WRITE
        txpacket[AX_PARAMETER] = address
        txpacket[AX_PARAMETER + 1] = value & 0xff
        txpacket[AX_PARAMETER + 2] = (value & 0xff00) >> 8

        return txrx(txpacket, rxpacket)

value = 0
writebyte(0x01, 0x18, 0)

while 1:
        result, value = readword(0x01, 36)
        if result == 1:
                #print value
                writeword(0x02, 30, value)
                #time.sleep(.1)

open("/sys/class/gpio/unexport", "w").write("%d" % UART2_TXIO)
open("/sys/class/gpio/unexport", "w").write("%d" % UART2_RXIO)

Using Python and wxPython to Display A Motion JPEG From the TRENDnet Wireless Internet Camera

import httplib
import base64
import StringIO
import threading
import time
import wx

class Trendnet():

    def __init__(self, ip='1.1.1.1', username='admin', password='admin'):
        self.IP = ip
        self.Username = username
        self.Password = password
        self.Connected = False

    def Connect(self):
        if self.Connected == False:
            try:
                print 'Atempting to connect to camera', self.IP, self.Username, self.Password
                h = httplib.HTTP(self.IP)
                h.putrequest('GET','/cgi/mjpg/mjpeg.cgi')
                h.putheader('Authorization', 'Basic %s' % base64.encodestring('%s:%s' % (self.Username, self.Password))[:-1])
                h.endheaders()
                errcode, errmsg, headers = h.getreply()
                self.File = h.getfile()
                print 'Connected!'
                self.Connected = True
            except:
        print 'Unable to connect!'
        self.Connected = False

def Disconnect(self):
    self.Connected = False
    print 'Camera Disconnected!'

def Update(self):
    if self.Connected:
        s = self.File.readline()    # '--myboundry'
        s = self.File.readline()    # 'Content-Length: #####'
        framesize = int(s[16:])
        s = self.File.read(framesize)  # jpeg data
        while s[0] != chr(0xff):
            s = s[1:]
        return StringIO.StringIO(s)

class CameraPanel(wx.Panel):

    def __init__(self, parent, camera):
        wx.Panel.__init__(self, parent, id=wx.ID_ANY, style=wx.SIMPLE_BORDER)
        self.Camera = camera
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

    def OnEraseBackground(self, event):
        pass

    def OnPaint(self, event):
        dc = wx.BufferedPaintDC(self)
        if self.Camera.Connected == True:
            try:
                stream = self.Camera.Update()
                if stream != None:
                    img = wx.ImageFromStream(stream)
                    bmp = wx.BitmapFromImage(img)
                    dc.DrawBitmap(bmp, 0, 0, True)
            except:
                pass
        else:
            dc.SetBrush(wx.WHITE_BRUSH)
            dc.DrawRectangle(-1, -1, 620, 480)

if __name__ == '__main__':

    def CamThread():
        while True:
            campanel.Refresh()
            time.sleep(.01)
    
    app = wx.App(0)
    wx.Log_SetActiveTarget(wx.LogStderr())
    frame = wx.Frame(parent=None, id=wx.ID_ANY, title='UpCam.py', style=wx.DEFAULT_FRAME_STYLE & ~wx.RESIZE_BORDER)
    camera = Trendnet('192.168.1.102')
    camera.Connect()
    campanel = CameraPanel(frame, camera)
    campanel.SetSize((620,480))

    sizer = wx.BoxSizer(wx.VERTICAL)
    sizer.Add(campanel, 1, wx.EXPAND|wx.ALL, 5)
    frame.SetSizer(sizer)
    frame.Fit()
    frame.Show(True)

    thread = threading.Thread(target=CamThread)
    thread.start()

    app.MainLoop()

9DOF IMU Development For Dynamixel Based Robots – Part 1

I recently purchased the 9 Degrees of Freedom – Razor IMU from Sparkfun Electronics

My intentions with this device is to use it as a platform to start the development of an IMU that communicates on the Dynamixel AX (and/or RX /EX) buss for easy use in Dynamixel based robots.

For starters I wanted to make sure the unit was working as expected with its pre programmed firmware. I wrote a little wxpython app that displays the values of the IMU’s three sensors in a nice little GUI.

Nice little GUI with nice output.

Here is the python code that makes it go:

#!/usr/bin/python

import serial
import threading
import math
import wx

class IMU_GUI(wx.Frame):

TIMER_ID = wx.NewId()

def __init__(self):
wx.Frame.__init__(self, None, -1, "9DOF IMU Testing", style=wx.DEFAULT_FRAME_STYLE)

self.ax = wx.StaticText(self, -1, "ax: ?", size=(100,20))
self.ay = wx.StaticText(self, -1, "ay: ?", size=(100,20))
self.az = wx.StaticText(self, -1, "az: ?", size=(100,20))

self.p = wx.StaticText(self, -1, "p: ?", size=(100,20))
self.r = wx.StaticText(self, -1, "r: ?", size=(100,20))
self.t = wx.StaticText(self, -1, "t: ?", size=(100,20))

self.gx = wx.StaticText(self, -1, "gx: ?", size=(100,20))
self.gy = wx.StaticText(self, -1, "gy: ?", size=(100,20))
self.gz = wx.StaticText(self, -1, "gz: ?", size=(100,20))

self.mx = wx.StaticText(self, -1, "mx: ?", size=(100,20))
self.my = wx.StaticText(self, -1, "my: ?", size=(100,20))
self.mz = wx.StaticText(self, -1, "mz: ?", size=(100,20))

self.serial = serial.Serial("/dev/ttyUSB0", 57600)

self.data = []

self.thread = threading.Thread(target=self.listen)
self.thread.start()

self.timer = wx.Timer(self, self.TIMER_ID)
self.timer.Start(10)
wx.EVT_TIMER(self, self.TIMER_ID, self.onTimer)

sizer = wx.GridBagSizer(0, 0)

sizer.Add(self.ax, pos=(0,0), flag=wx.ALL, border=5)
sizer.Add(self.ay, pos=(0,1), flag=wx.ALL, border=5)
sizer.Add(self.az, pos=(0,2), flag=wx.ALL, border=5)

sizer.Add(self.gx, pos=(1,0), flag=wx.ALL, border=5)
sizer.Add(self.gy, pos=(1,1), flag=wx.ALL, border=5)
sizer.Add(self.gz, pos=(1,2), flag=wx.ALL, border=5)

sizer.Add(self.mx, pos=(2,0), flag=wx.ALL, border=5)
sizer.Add(self.my, pos=(2,1), flag=wx.ALL, border=5)
sizer.Add(self.mz, pos=(2,2), flag=wx.ALL, border=5)

sizer.Add(self.p, pos=(3,0), flag=wx.ALL, border=5)
sizer.Add(self.r, pos=(3,1), flag=wx.ALL, border=5)
sizer.Add(self.t, pos=(3,2), flag=wx.ALL, border=5)

self.SetSizerAndFit(sizer)

self.Show(True)

self.serial.write("4")

def onTimer(self, event):

try:

if len(self.data) != 9:
return

self.ax.SetLabel("ax: " + self.data[0][1:])
self.ay.SetLabel("ay: " + self.data[1])
self.az.SetLabel("az: " + self.data[2])
self.gx.SetLabel("gx: " + self.data[3])
self.gy.SetLabel("gy: " + self.data[4])
self.gz.SetLabel("gz: " + self.data[5])
self.mx.SetLabel("mx: " + self.data[6])
self.my.SetLabel("my: " + self.data[7])
self.mz.SetLabel("mz: " + self.data[8][:-1])

ax = int(self.data[0][1:])
ay = int(self.data[1])
az = int(self.data[2])

#print ax, ay, az

p = math.atan2(ax,math.sqrt(math.pow(ay,2)+math.pow(az,2))) * (180/3.14)
r = math.atan2(ay,math.sqrt(math.pow(ax,2)+math.pow(az,2))) * (180/3.14)
t = math.atan2(math.sqrt(math.pow(ax,2)+math.pow(ay,2)),az) * (180/3.14)

#print p, r, t

self.p.SetLabel("p: " + str(p)[:10])
self.r.SetLabel("r: " + str(r)[:10])
self.t.SetLabel("t: " + str(t)[:10])

except:
pass

def listen(self):

while True:
if self.serial.inWaiting() != 0:
line = ""
done = False
while not done:
c = self.serial.read()
#print ord(c)
if ord(c) == 13 or ord(c) == 10:
done = True
else:
line += c
#print line

data = line.split(",")
if len(data) == 9:
self.data = data

if __name__ == "__main__":
app = wx.App(0)
frame = IMU_GUI()
app.MainLoop()

More to come!

Python Hermite Curve Calculation And Display

A Hermite curve defines a unique path between two points based off of two control tangents.

I put together a little python program to play around with the calculation of Hermite curves to make sure I understood them before attempting to use it in other applications.

import wx
import time
import threading

class point():
def __init__(self, x=0, y=0, z=0):
self.x = x
self.y = y
self.z = z

def curve(p1, p2, t1, t2, time):
t = time
b0 = 2*t*t*t - 3*t*t + 1
b1 = -2*t*t*t + 3*t*t
b2 = t*t*t - 2*t*t + t
b3 = t*t*t - t*t
x = b0*p1.x + b1*p2.x + b2*t1.x + b3*t2.x
y = b0*p1.y + b1*p2.y + b2*t1.y + b3*t2.y
z = b0*p1.z + b1*p2.z + b2*t1.z + b3*t2.z
return point(x,y,z)

class CurveFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title='HermiteCurve.py', style=wx.DEFAULT_FRAME_STYLE & ~wx.RESIZE_BORDER)

# Initilize curve data.
self.p1 = point()
self.p2 = point()
self.t1 = point()
self.t2 = point()
self.data = list()

# Create wx panel to draw the curve on.
self.CurvePanel = CurvePanel(self)

# Control Panel
self.ControlPanel = wx.Panel(self)

# Controls for curve data.
self.p1x = wx.Slider(self.ControlPanel, -1, 0, -200, 200, size=(200,-1), style=wx.SL_LABELS)
self.p2x = wx.Slider(self.ControlPanel, -1, 0, -200, 200, size=(200,-1), style=wx.SL_LABELS)
self.t1x = wx.Slider(self.ControlPanel, -1, 0, -5000, 5000, size=(200,-1), style=wx.SL_LABELS)
self.t2x = wx.Slider(self.ControlPanel, -1, 0, -5000, 5000, size=(200,-1), style=wx.SL_LABELS)

# Size it up!
controlsizer = wx.GridBagSizer(0,0)
controlsizer.Add(wx.StaticText(self.ControlPanel, label='Point 1 Value:'), (1,0), flag=wx.ALL, border=5)
controlsizer.Add(self.p1x, (2,0), flag=wx.ALL, border=5)
controlsizer.Add(wx.StaticText(self.ControlPanel, label='Point 2 Value:'), (3,0), flag=wx.ALL, border=5)
controlsizer.Add(self.p2x, (4,0), flag=wx.ALL, border=5)
controlsizer.Add(wx.StaticText(self.ControlPanel, label='Tangent 1 Magnitude:'), (5,0), flag=wx.ALL, border=5)
controlsizer.Add(self.t1x, (6,0), flag=wx.ALL, border=5)
controlsizer.Add(wx.StaticText(self.ControlPanel, label='Tangent 2 Magnitude:'), (7,0), flag=wx.ALL, border=5)
controlsizer.Add(self.t2x, (8,0), flag=wx.ALL, border=5)
self.ControlPanel.SetSizerAndFit(controlsizer)

sizer = wx.GridBagSizer(0,0)
sizer.Add(self.CurvePanel, (0,0), flag=wx.ALL, border=5)
sizer.Add(self.ControlPanel, (0,1), flag=wx.ALL, border=5)
self.SetSizerAndFit(sizer)

# Show the frame.
self.Show(True)

# Thread to update.
self.thread = threading.Thread(target=self.Update)
self.thread.start()

def Update(self):
while(True):
self.p1.x = self.p1x.GetValue()
self.p2.x = self.p2x.GetValue()
self.t1.x = self.t1x.GetValue()
self.t2.x = self.t2x.GetValue()
self.CalcCurve()
self.Draw()
time.sleep(.1)

def CalcCurve(self):
time = 0
self.data = list()
while time < 1.01:
p = curve(self.p1, self.p2, self.t1, self.t2, time)
self.data.append(time)
self.data.append(p.x)
self.data.append(p.y)
self.data.append(p.z)
time = time + .01

def Draw(self):
# Redraw the curve panel.
self.CurvePanel.Refresh()

class CurvePanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, id=wx.ID_ANY, size=(600,500), style=wx.SIMPLE_BORDER)
self.parent = parent
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

def OnEraseBackground(self, event):
pass

def OnPaint(self, event):
dc = wx.BufferedPaintDC(self)
self.Draw(dc)

def Draw(self, dc):
dc.SetBrush(wx.WHITE_BRUSH)
dc.DrawRectangle(-1, -1, self.Size.width, self.Size.height)

data = self.parent.data
d = self.parent.data

width = self.GetSize()[0]
height = self.GetSize()[1]
padding = 20

# Scale the data to the graph size panel's size.
for x in range(len(data)/4):
d[4*x+0] = (width-2*padding) * data[4*x+0] + padding
d[4*x+1] = -1 * data[4*x+1] + (height/2)

# Draw the graph axis.
dc.DrawLine(padding, height/2, width-padding, height/2)
dc.DrawLine(padding, padding, padding, height-padding)

# Draw the data.
dc.SetPen(wx.Pen(wx.BLUE, 2))
for x in range(len(data)/4):
try:
x1 = d[4*x]
y1 = d[4*x+1]
x2 = d[4*(x+1)]
y2 = d[4*(x+1)+1]
dc.DrawLine(x1,y1,x2,y2)
except:
pass

if __name__ =='__main__':
app = wx.App(0)
frame = CurveFrame(None)
app.MainLoop()

Download HermiteCurve.py code here.

Logitech Dual Action USB Gamepad Interface Using Python

You can get a list of all input device files on your machine by using the command ‘ls /dev/input’. My Logitech gamepad is showing up as ‘js0′.

Using the cat command on the gamepad’s device file ‘cat /dev/input/js0′ and then pressing some buttons on the game pad spews out a bunch of garbage in the terminal. This lets me know the gamepad is working but I am going to have to do a bit of programming to make some sense of all this gibberish.

Using python we can open and read the device pipe as if it were a normal file and print it in a slightly more readable format.

import sys


# Open the js0 device as if it were a file in read mode.
pipe = open('/dev/input/js0', 'r')

# Loop forever.
while 1:

# For each character read from the /dev/input/js0 pipe...
for char in pipe.read(1):

# write to the standard output the string representation of 'char'.
sys.stdout.write(repr(char))

# Flush the stdout pipe.
sys.stdout.flush()

By observing the output of the simple python program I notice that each event on the gamepad (button down, button up, axis movement) produces 8 bytes of data. I then went on to modify the program to assemble the incoming data into eight byte messages and print each message to the screen.

# Open the js0 device as if it were a file in read mode.

pipe = open('/dev/input/js0', 'r')

# Create an empty list to store read characters.
msg = []

# Loop forever.
while 1:

# For each character read from the /dev/input/js0 pipe...
for char in pipe.read(1):

# append the integer representation of the unicode character read to the msg list.
msg += [ord(char)]

# If the length of the msg list is 8...
if len(msg) == 8:

# Print the msg list.
print msg

# Reset msg as an empty list.
msg = []

By observing the data in this format I am able to determine a few things:

  • Bytes 0, 1, 2,and 3 appear to count up as messages stream in. This could possibly be useful to determine the order or time relationship between messages.
  • Bytes 4 and 5 are the value of the message.
  • Byte 6 seems to serves two functions.
    • When the device pipe is first opened we receive messages that indicate how many buttons and how many joystick axis are on the gamepad. If the byte is 129 this represents a button or if it is 130 it represent a joystick axis.
    • After these initial messages if the byte is 1 it represents a button event or if its 2 it represents a axis event.
  • Byte 7 identifies the button or axis number that triggered the message.

Using this information I modified the program again to output messages based on the gamepad events.

# Open the js0 device as if it were a file in read mode.

pipe = open('/dev/input/js0', 'r')

# Create an empty list to store read characters.
msg = []

# Loop forever.
while 1:

# For each character read from the /dev/input/js0 pipe...
for char in pipe.read(1):

# append the integer representation of the unicode character read to the msg list.
msg += [ord(char)]

# If the length of the msg list is 8...
if len(msg) == 8:

# Button event if 6th byte is 1
if msg[6] == 1:
if msg[4] == 1:
print 'button', msg[7], 'down'
else:
print 'button', msg[7], 'up'

# Axis event if 6th byte is 2
elif msg[6] == 2:
print 'axis', msg[7], msg[5]

# Reset msg as an empty list.
msg = []

From here I am just a hop, skip, and a jump away from wrapping this into a class and saving the state of the buttons and axis into some sort of easily used data structures. I will be posting a follow up post when I get this concept into a usable format.

Fractal Terrain Generation Using The Diamond-Square Algorithm

Continuing on with my experimentation with the fractal mountain range and Mandelbrot set I have set my eyes on generating a 3d fractal landscape with ambitions of moving onto a fractal planet.

 I have been tinkering with the Pyglet python library. Pyglet is a wrapper for the OpenGL (Open Graphics Library).

Shown below is my attempts at visualizing the result of a terrain generated from the diamod-square algorithm

First attempt. Has some obvious algorithm errors.
 Second attempt with a revised algorithm.

You can download the python code here.

Generating A Fractal Mountain Range

I stumbled across this page about generating random fractal terrain. I went ahead and made a simple wxpython app to put the ideas I learned into practice. Below is the result and source code.



import wx
import math
import random

class Point():
def __init__(self, x, y):
self.X = x
self.Y = y

def RandY(self, displacement):
self.Y = self.Y + (random.uniform(-1,1) * displacement)

class Line():
def __init__(self, p1, p2):
self.P1 = p1
self.P2 = p2

def FindMid(self):
p = Point((self.P1.X + self.P2.X) / 2.0, (self.P1.Y + self.P2.Y) / 2.0)
return p

def Draw(self, dc):
dc.SetPen(wx.Pen(wx.BLACK))
dc.DrawLine(self.P1.X, self.P1.Y, self.P2.X, self.P2.Y)
dc.DrawLine(self.P1.X, self.P1.Y, self.P1.X, 700)
dc.DrawLine(self.P2.X, self.P2.Y, self.P2.X, 700)

def Fractal(line, number, rand, dc):
if number == 0:
line.Draw(dc)
else:
p = line.FindMid()
p.RandY(rand)
rand = rand/2
Fractal(Line(line.P1, p), number-1, rand, dc)
Fractal(Line(p, line.P2), number-1, rand, dc)

class Mountain2D(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title='Fractial Mountain!', style=wx.DEFAULT_FRAME_STYLE & ~wx.RESIZE_BORDER)

self.DrawingPanel = DrawingPanel(self)

sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.DrawingPanel, 1, wx.EXPAND|wx.ALL, 5)
self.SetSizer(sizer)
self.Fit()
self.Show(True)

class DrawingPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, id=wx.ID_ANY, size=(600,500), style=wx.SIMPLE_BORDER)

self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

def OnEraseBackground(self, event):
pass

def OnPaint(self, event):
dc = wx.BufferedPaintDC(self)
self.Draw(dc)

def Draw(self, dc):
dc.SetBrush(wx.WHITE_BRUSH)
dc.DrawRectangle(-1, -1, self.Size.width, self.Size.height)

# Draw the sky
scale = 255.0 / self.Size.height
for i in range(0,self.Size.height):
dc.SetPen(wx.Pen(wx.Colour(0, 255 - int(scale * i), 255 - int(scale * i))))
dc.DrawLine(0, i, self.Size.width, i)

# Draw some stars
for i in range(0,150):
dc.SetPen(wx.Pen(wx.Colour(255, 255, 255)))
dc.SetBrush(wx.Brush(wx.Colour(255, 255, 255), wx.SOLID))
dc.DrawCircle(random.uniform(0, self.Size.width), random.uniform(-1,self.Size.height / 1.5), random.uniform(1, 3))

P1 = Point(self.Size.width * 0.0, self.Size.height * 0.60)
P2 = Point(self.Size.width * 1.0, self.Size.height * 0.60)

LINE = Line(P1, P2)

Fractal(LINE, 10, 200, dc)

if __name__ == '__main__':
app = wx.App(0)
frame = Mountain2D(None)
app.MainLoop()

Using Python To Draw The Mandelbrot Set

I recently watched a documentary on the discovery of the Mandelbrot Set on youtube and it sparked my curiosity. I went ahead and made a little python app that draws the famous Mandelbrot set in a wxpython window. You can see the result of my work and the source code below. It is by no means useful or elegant code but it was a fun exercise!

import wx


class MandelbrotFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title='Mandelbrot!', style=wx.DEFAULT_FRAME_STYLE & ~wx.RESIZE_BORDER)

self.DrawingPanel = DrawingPanel(self)

sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.DrawingPanel, 1, wx.EXPAND|wx.ALL, 5)
self.SetSizer(sizer)
self.Fit()
self.Show(True)

class DrawingPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, id=wx.ID_ANY, size=(600,500), style=wx.SIMPLE_BORDER)

self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)

def OnEraseBackground(self, event):
pass

def OnPaint(self, event):
dc = wx.BufferedPaintDC(self)
self.Draw(dc)

def Draw(self, dc):
dc.SetBrush(wx.WHITE_BRUSH)
dc.DrawRectangle(-1,-1,600,500)

for x in range(0, 600):
real = -2 + x * ((1 - -2.0) / 600.0)
for y in range(0, 500):
img = 1.2 - y * ((1.2 - -1.2) / 500.0)
c = complex(real, img)
z = 0
for i in range(0, 30):
z = z**2 + c
if abs(z) > 2:
break

if abs(z) >= 2:
dc.SetPen(wx.Pen(wx.Colour(0, 8.5*i, 8.5*i)))
dc.DrawPoint(x, y)
else:
dc.SetPen(wx.Pen(wx.Colour(0, 5, 5)))
dc.DrawPoint(x, y)

if __name__ == '__main__':
print 'Mandelbrot starting...'
app = wx.App(0)
frame = MandelbrotFrame(None)
app.MainLoop()

Gold Rush Serial Data Packet Control

Over the last week I have been able to get wireless control working with my AVR micro. Communication to the AVR is being done by sending wireless serial data packets using xbee modules.
At the moment my packets consist of two header bytes (0xff) to designate the start of a new packet. The header is then followed with 4 bytes to hold the values of 2 joystick (horizontal and vertical axis). The packet is then ended with a checksum.

I have created a simple python and wxpython app to simulate the control of two joysticks using some slider widgets. This app simply reads the value of the 4 sliders, forms a data packet and writes it out serially to a xbee module connected to my PC around 30 times a second.

MechController.py demo window.

On the micro side I have a second xbee module connected to one of the atmega644′s usarts. The micro is adding every byte it receives on this usart to a ring buffer. Then, when called, a function is able to search this buffer for a full data packet, pull out the joystick data and flush the buffer.

Here is a little video I took to demonstrate it all working. Off camera I am changing the values on the top two sliders in my python app. These two sliders represent the vertical and horizontal axis of a single joystick. In turn the value of each slider determines the walking direction of the robot.

AVR Wireless Serial Communication

Progress continues with my AVR microcontroller board…
Today I was able to get some simple wireless serial communication tests working.

I followed this great tutorial post on AVR Freaks on creating interrupt driven USART echo program. I then took it a step farther and had each side of the serial link (PC and micro) echo the last character received pulse one.

All in all the test were not very interesting but they do lay groundwork for the development of a control packet structure for driving Gold Rush around.