Friday, 17 October 2014

Raspberry Pi, Xbox 360 Controller, Python

I was looking for a way of controlling my initio robot by remote and having purchased 3 xbox 360’s in the past (red ring of death :( replacements) I have got a few wireless controllers knocking about!  I decided re-using one of these was the way forward.

I grabbed a £5 xbox USB wireless receiver (you can get them on Amazon UK US) and robbed the code from zephods lego pi car project (http://blog.zephod.com/post/37120089376/lego-xbox-raspberry-pi) but I found it to be really unstable, often resulting in a ‘segmentation’ fault within a few minutes – so I decided to write my own.

Zephod’s code used the screen output of xboxdrv (a linux xbox controller driver) to create events which could be interpreted from python.  I decided on a different route and (after being shown the way by Dave Honess at Pycon) used pygame to interface with xboxdrv and the controller directly.

I originally just hacked together some code to make my solution work but after asking twitter whether anyone else would find it useful I created a generic python module to allow anyone to incorporate an xbox controller into their projects.


The module works by interpreting the pygame events which xboxdrv creates when the xbox controller is used (button pressed, button released, analogue stick moved, trigger pressed, etc) and keeps track of the values of all the buttons, sticks and triggers on the controller.

These values can be read directly from the properties on the class (e.g  xboxController.RTRIGGER) or the values can be passed to your program through the use of call backs i.e. when a button is pressed or a stick moved a function in your program is called and the details about what was changed and what the new value is are passed to it.

Installing and testing the module

If there is demand in the future I will wrap the module into a proper python package, but for the time being its just a separate python file (XboxController.py) which you can add to your python project.

Install xboxdrv
sudo apt-get install xboxdrv
Grab the code from GitHub (github.com/martinohanlon/XboxController) and copy the XboxController.py file to your project:
git clone https://github.com/martinohanlon/XboxController
cp XboxController/XboxContoller.py pathToYourProject
You need to run xboxdrv before you can use the module, run
sudo xboxdrv --silent &
You may get an error asking you to run xboxdrv with the option --detach-kernel-driver, if so run:
sudo xboxdrv --silent --detach-kernel-driver &
You can test the module by running the XboxController.py file
python XboxController.py
When you see the message on the screen saying the controller is running, press a button on your xbox controller.


Using the module

The module is pretty easy to use, but there are a few complex concepts to get your head around such as call backs and threading - first you need to import it into your code:
import XboxController
Then you can create an instance to the XboxController:
xboxCont = XboxController.XboxController(
    controllerCallBack = None,
    joystickNo = 0,
    deadzone = 0.1,
    scale = 1,
    invertYAxis = False)
You can adjust the behaviour of the module by passing different parameters:
  • joystickNo : specify the number of the pygame joystick you want to use, usually 0
  • deadzone : the minimum value which is reported from the analogue sticks, a deadzone is good to reduce sensitivity
  • scale : the scale the analogue sticks will report to, so 1 will mean values are returned between -1 and 1, 0 is always the middle
  • invertYAxis : the Y axis is reported as -1 being up and 1 being down, which is just weird, so this will invert it
  • controllerCallBack : pass the name of a function and the xbox controller will call this function each time the controller changes (i.e. a button is pressed) returning the id of the control (what button, stick or trigger) and the current value
To add a controller call back you would use:
def myCallBack(controlId, value):
    print "Control id = {}, Value = {}".format(controlId, value)

xboxCont = XboxController.XboxController(
    controllerCallBack = myCallBack)
You can also add other call back functions so that when specific buttons, sticks or triggers are pressed or moved it will call a specific function, e.g. to add a function which is called when the start button is pressed / released you would used the code:
def startButtonCallBack(value):
    print "Start button pressed / released"

xboxCont.setupControlCallback(
    self.xboxCont.XboxControls.START,
    startButtonCallBack)
The XboxController runs in its own thread, so you need to tell the controller to start using
xboxCont.start()
Control values can be read directly from the XboxController while it is running, by using the properties of the class e.g. to read the current value of the right trigger you would use:
print xboxCont.RTRIGGER
The XboxController also needs to be stopped at the end of your program using
xboxCont.stop()
For more information about the module, see the code in the the XboxController.py file.

Tuesday, 14 October 2014

Raspberry Pi Initio Robot - Driving Straight

I've been continuing my Raspberry Pi Robot project (see previous post) and the next challenge was to create some functions to allow my robot to be autonomous.

First challenge...  Drive in a straight line!  Not as easy as it seems.  You put both motors onto 100% power forward and it veers slightly to the right (or in my case it does!).  The reason is simple the motors which drive the left and right wheels don't turn at exactly the same rate.

What to do.  Well the Initio robot chasis I have is fitted with wheel encoders which 'tick' when the wheels go round to show how far they have moved, so if I wanted to make the robot go straight I needed to make left and right wheels moved the same distance.

So, I turn both motors on and count the encoder ticks, if the left one is getting ahead I slow it down a bit, unless the right catches up and vice versa!

I created a new python class called NavigationController which is where I will put all of my robots autonomous functions and created a straight function which when passed a power and a distance would drive straight until that distance was reached.  It constantly checks the encoder values for both wheels and adjusts the power of the 2 motors to make sure it goes straight.

Code
You can see all my robot code here https://github.com/martinohanlon/initio

#Navigation class to accurately move initio robot
#Martin O'Hanlon
#www.stuffaboutcode.com

#import modules
import sys
import motorControl
import time
import RPi.GPIO as GPIO
import math
import thread

#states
STATEMOVING = 1
STATESTOPPED = 0

#Constant of Proportionality
# multipler used to convert difference in motor position to power change
KP = 2

#Wheel circumference
#(in mm)
WHEELCIRCUMFERENCEMM = 174.0
#(in encoder ticks)
WHEELCIRCUMFERENCE = 36.0

#Encoder to mm ratio (wheel circumference in mm / wheel circumference to encoder ticks)
ENCODERTOMM = WHEELCIRCUMFERENCEMM / WHEELCIRCUMFERENCE

class NavigationController:
    #initialise - motors is the MotorControl object
    def __init__(self, motors, distanceInMM = False):
        self.motors = motors
        self.state = STATESTOPPED

        #if distanceinMM is set to True all distance are consider to be in millimeters
        # if False all distances are in encoder ticks
        self.distanceInMM = distanceInMM

    #navigation state property
    @property
    def state(self):
        return self.state

    #motors property
    @property
    def motors(self):
        return self.state

    #move the robot in a straight line
    def straight(self, power, distance = None, ownThread = False):
        # if distance is not passed, continues forever and launches a seperate thread
        # if distance is passed, loops until distance is reached
        if distance == None:
            #set a really long distance - this is a 'bit' dirty...  But simple!
            distance = 99999999999
            #call it in its own thread
            ownThread = True
            
        if ownThread:
            #call it in its own thread
            thread.start_new_thread(self._straight,(power, distance))
        else:
            self._straight(power, distance)

    #move the robot in a staight line
    def _straight(self, power, distance):

        #convert distance
        if self.distanceInMM: distance = self._convertMillimetersToTicks(distance)
        
        #if the state is moving, set it to STOP
        if(self.state != STATESTOPPED): self.stop()
        
        #turn on both motors
        self.motors.start(power, power)

        #change state to moving
        self.state = STATEMOVING

        #keep track of the last motor error, so we only change if we need too
        lastMotorError = 0
        
        #loop until the distance is reached or it has been STOPPED, correcting the power so the robot goes straight
        while(self.motors.motorA.currentTicks < distance and self.state == STATEMOVING):
            
            #get the number of ticks of each motor
            #get the error by minusing one from the other
            motorError = self.motors.motorA.currentTicks - self.motors.motorB.currentTicks
            #print("motorError = " + str(motorError))

            #only change if the motorError has changed
            if(motorError != lastMotorError):

                #work out the value to slow the motor down by using the KP
                powerChange = (motorError * KP)
                #print("powerChange = " + str(powerChange))

                #in the unlikely event they are equal!
                if(powerChange == 0):
                    self.motors.start(power, power)
                else:
                    #if its going backward, turn the power change into a negative
                    if power < 0: powerChange * -1
                        
                    #if its a positive number
                    if(motorError > 0):
                        #set motor A to power - 'slow down value'
                        #set motor B to power
                        self.motors.start(power - powerChange, power)
                    #if its a negative number
                    if(motorError < 0):
                        #set motor A to power
                        #set motor B to power - 'slow down value'
                        self.motors.start(power, power - powerChange)

            #update last motor error
            lastMotorError = motorError

        # if they havent already been stopped - stop the motors
        self.stop()

    #stops the robot
    def stop(self):
        self.motors.stop()
        self.state = STATESTOPPED

    def _convertMillimetersToTicks(self, millimeters):
        print ENCODERTOMM
        return int(round(millimeters / ENCODERTOMM,0))

#tests
if __name__ == '__main__':

    try:
        #setup gpio
        GPIO.setmode(GPIO.BOARD)

        #create motor control
        motors = motorControl.MotorController()

        #create navigation control, use True for distances in millimeters
        nav = NavigationController(motors, True)

        #run a straight line just through motor control
        print("straight line, no correction")
        motors.start(100,100)
        time.sleep(10)
        #stop
        print("stop")
        motors.stop()
        #get length
        print("encoder ticks")
        print(motors.motorA.totalTicks)
        print(motors.motorB.totalTicks)

        #time.sleep(10)

        #reset encoder ticks
        motors.motorA.resetTotalTicks()
        motors.motorB.resetTotalTicks()
        
        #run a straight line through nav control
        print("straight line, with correction")
        nav.straight(100, 500)
        #get length
        print("encoder ticks")
        print(motors.motorA.totalTicks)
        print(motors.motorB.totalTicks)

    #Ctrl C
    except KeyboardInterrupt:
        print "User cancelled"

    #Error
    except:
        print "Unexpected error:", sys.exc_info()[0]
        raise

    finally:
        print ("cleanup")
        #cleanup gpio
        GPIO.cleanup()

Next job - turning in an arc!

Monday, 13 October 2014

Minecraft RaspberryJuice and Canarymod


Believe it or not Bukkit is not the only Minecraft server that supports plugins!

I have been maintaining a Bukkit plugin called RaspberryJuice for a little while, which allows you to run the same programs you developed for Minecraft on the Raspberry Pi on the full version of Minecraft.

So to give people a choice and to ensure the longevity of the RaspberryJuice plugin I have migrated it to Canarymod.  Canarymod is another Minecraft server, with an open source API which allows you to interface directly with the server.  This is what RaspberryJuice does, it listens for the command which would normally be sent to the Pi edition of Minecraft and makes the same things happen in Minecraft.

You can get the RaspberryJuice source code plugin for Canarymod from https://github.com/martinohanlon/canaryraspberryjuice.

None of this could have been possible without the work of zhuowei who originally create the RaspberryJuice Bukkit plugin.

I will keep them both versions of the RaspberryJuice plugin's up to date for as long as its viable.

If you want to create your own Canarymod server with RaspberryJuice plugin follow these steps:

Download and install Canarymod
  • Create a folder for Canarymod, anywhere it doesn't matter
  • Head over to http://canarymod.net/releases and download the latest version of Canarymod and save the .jar file to the folder.
  • Rename the downloaded .jar file from canarymod-#.#.#-#.#.#.jar to canarymod.jar
  • Open Notepad, insert the following text:
java -jar CanaryMod.jar
pause
  • Save the file in the folder as start.bat
Run CanaryMod

Double click start.bat

You will be asked to confirm you accept the EULA.  Open the eula.txt file and change eula=false to eula=true and save the file.

Double click start.bat to run the CanaryMod again.

Test Canarymod

The version of Minecraft you use needs to match the version of Canarymod you downloaded.  So if you downloaded Canarymod 1.7.10 you need to set Minecraft to use 1.7.10 as well.  You can do this by picking the correct version from the "Edit Profile" window on the Minecraft Launcher.

Open Minecraft, Multiplayer, Direct Connect, Type "localhost", Join Server

You can stop Canarymod by typing stop in the canarymod command window

Download and Install Raspberry Juice
If everything has gone to plan you should see a message when you start up Canarymod that RaspberryJuice has been enabled.


You can now run your Minecraft: Pi Edition programs on the full version of Minecraft.  Here is a video of the Minecraft Analogue Clock running on Bukkit using Raspberry Juice.



Tuesday, 19 August 2014

Raspberry Pi - Initio Robot & Python Motor Control

When I was at the 2014 Raspberry Jamboree, I was luckily enough to 'acquire' (I won it, I didn't steal it!) a 4tronix initio robot chasis, unfortunately it sat on my shelf for nearly 6 months before I got time to have a go with it.



When I opened up the box I found it also came with a 4tronix PiRoCon robot controller as well - all good!

I wanted to control the robot using Python, so my first stop was the ever useful google, unfortunately other than one simple python example in 4tronix's PiRoCon github repository, the cupboard was bare.  I did however know that Cymplecy (SimpleSi)'s ScratchGPIO code supported the PiRoCon so this code also gave me some inspiration (!).  I have since found out that 4tronix have some downloadable examples on their site, check out the very bottom of this page - doh!

I wired the motor's up as per the instructions on 4tronix's website and the speed sensors as per the instructions on Cymplecy's blog and I set about creating a motor control class, which would allow me to control the speed of the motors and also get data from the speed sensors (encoders).

This is my starting point for more advanced features and automation, but as always start small, grow big.

There is a more 'complete' example in the code below, but you use the motor controller class like this:

import time
import motorControl

#setup gpio
GPIO.setmode(GPIO.BOARD)

#create motor control
motors = motorControl.MotorController()

#go forward - both motors at 100%
motors.start(100)
time.sleep(2)

#go forward in a curve
# - motor A at 100%
# - motor B at 50%
motors.start(100,50)
time.sleep(2)

#go backward at 100%
# - using negative power
motors.start(-100)
time.sleep(2)

#stop
motors.stop()

#cleanup gpio
GPIO.cleanup()

The full Motor Controller code is below and in my initio repository github.com/martinohanlon/initio:

#PiRoCon - 4Tronix Initio - Motor Controller
#Martin O'Hanlon
#www.stuffaboutcode.com

import sys
import time
import RPi.GPIO as GPIO

#motor pins
MOTORAFWRDPIN = 19
MOTORABWRDPIN = 21
MOTORBFWRDPIN = 24
MOTORBBWRDPIN = 26
#encoder pins
MOTORAENCODERPIN = 7
MOTORBENCODERPIN = 11

#motor states
STATEFORWARD = 1
STATESTOPPED = 0
STATEBACKWARD = -1

class MotorController:
    def __init__(self,
                 motorAForwardPin = MOTORAFWRDPIN,
                 motorABackwardPin = MOTORABWRDPIN,
                 motorBForwardPin = MOTORBFWRDPIN,
                 motorBBackwardPin = MOTORBBWRDPIN,
                 motorAEncoderPin = MOTORAENCODERPIN,
                 motorBEncoderPin = MOTORBENCODERPIN,):

        #setup motor classes
        self.motorA = Motor(motorAForwardPin, motorABackwardPin, motorAEncoderPin)
        self.motorB = Motor(motorBForwardPin, motorBBackwardPin, motorBEncoderPin)

    #motor properties
    @property
    def motorA(self):
        return self.motorA

    @property
    def motorB(self):
        return self.motorB

    #start
    def start(self, powerA, powerB = None):
        #if a second power isnt passed in, both motors are set the same
        if powerB == None: powerB = powerA
        self.motorA.start(powerA)
        self.motorB.start(powerB)

    #stop
    def stop(self):
        self.motorA.stop()
        self.motorB.stop()

    #rotate left
    def rotateLeft(self, power):
        self.motorA.start(power * -1)
        self.motorB.start(power)

    #rotate right
    def rotateRight(self, power):
        self.motorA.start(power)
        self.motorB.start(power * -1)

#class for controlling a motor
class Motor:
    def __init__(self, forwardPin, backwardPin, encoderPin):
        #persist values
        self.forwardPin = forwardPin
        self.backwardPin = backwardPin
        self.encoderPin = encoderPin

        #setup GPIO pins
        GPIO.setup(forwardPin, GPIO.OUT)
        GPIO.setup(backwardPin, GPIO.OUT)
        GPIO.setup(encoderPin,GPIO.IN,pull_up_down=GPIO.PUD_DOWN)
        #add encoder pin event
        GPIO.add_event_detect(encoderPin, GPIO.RISING, callback=self._encoderCallback,bouncetime=2)

        #setup pwm
        self.forwardPWM = GPIO.PWM(forwardPin,50)
        self.backwardPWM = GPIO.PWM(backwardPin,50)

        #setup encoder/speed ticks
        self.totalTicks = 0
        self.currentTicks = 0

        self.state = STATESTOPPED

    #motor state property
    @property
    def state(self):
        return self.state

    #start
    def start(self, power):        
        #forward or backward?
        # backward
        if power < 0:
            if self.state != STATEBACKWARD: self.stop()
            self._backward(power)
            self.state = STATEBACKWARD
            
        # forward  
        if power > 0:
            if self.state != STATEFORWARD: self.stop()
            self._forward(power)
            self.state = STATEFORWARD
            
        # stop
        if power == 0:
            self.stop()

    #stop
    def stop(self):
        #stop motor
        self.forwardPWM.stop()
        self.backwardPWM.stop()
        self.state = STATESTOPPED
        #reset ticks
        self.currentTicks = 0

    #private function to calculate the freq for the PWM
    def _calcPowerAndFreq(self, power):
        # make power between 0 and 100
        power = max(0,min(100,abs(power)))
        # make half of freq, minimum of 11
        freq = max(11,abs(power/2))
        return power, freq
    
    #forward
    def _forward(self, power):
        #start forward motor
        power, freq = self._calcPowerAndFreq(power)
        self.forwardPWM.ChangeFrequency(freq)
        self.forwardPWM.start(power)
        
    #backward
    def _backward(self, power):
        #start backward motor
        power, freq = self._calcPowerAndFreq(power)
        self.backwardPWM.ChangeFrequency(freq)
        self.backwardPWM.start(power)

    #encoder callback
    def _encoderCallback(self, pin):
        self.totalTicks += 1
        self.currentTicks += 1

#tests
if __name__ == '__main__':

    try:
        #setup gpio
        GPIO.setmode(GPIO.BOARD)
        
        #create motor control
        motors = MotorController()

        #forward
        print("forward")
        motors.start(100)
        time.sleep(2)
        
        print("encoder ticks")
        print(motors.motorA.totalTicks)
        print(motors.motorB.totalTicks)
        
        #backward 
        print("backward")
        motors.start(-50)
        time.sleep(2)

        #forward curve
        print("forward curve")
        motors.start(100,50)
        time.sleep(2)

        #rotate left
        print("rotate left")
        motors.rotateLeft(50)
        time.sleep(2)

        #rotate right
        print("rotate right")
        motors.rotateRight(50)
        time.sleep(2)
        
        #stop
        print("stop")
        motors.stop()

    #Ctrl C
    except KeyboardInterrupt:
        print "User cancelled"

    #Error
    except:
        print "Unexpected error:", sys.exc_info()[0]
        raise

    finally:
        print ("cleanup")
        #cleanup gpio
        GPIO.cleanup()

Its my first time doing any robotics but so far I have been impressed with the Initio, the build quality and support seem really good - let the robot roll!

Saturday, 19 July 2014

Minecraft Fractal Trees

I have been experimenting with the Minecraft Graphics Turtle I created, its a typical graphics turtle in that you issue it commands such as forward, backward, left, right but you can also tell it to go up and down and go 3d!

I wanted to create something that took advantage of the 3d world available in Minecraft and decided to see if I could make some 3d fractals.  Fractals are repeating patterns which when observed at different scales appear the same - I know that sounds like rubbish, but that's what they are!

These are the 3d fractal tree's I created in Minecraft:



This is what a 2d fractal tree looks like:

I found some python turtle code to create the 2d tree at interactivepython.org/runestone/static/pythonds/Recursion/graphical.html:
import turtle

def tree(branchLen,t):
    if branchLen > 5:
        t.forward(branchLen)
        t.right(20)
        tree(branchLen-15,t)
        t.left(40)
        tree(branchLen-15,t)
        t.right(20)
        t.backward(branchLen)

def main():
    t = turtle.Turtle()
    myWin = turtle.Screen()
    t.left(90)
    t.up()
    t.backward(100)
    t.down()
    t.color("green")
    tree(75,t)
    myWin.exitonclick()

main()

Its recursive, which means that a function calls itself, so in the example above the tree() function calls itself passing a smaller and smaller branch until the branch gets smaller than 5 and the function doesn't call itself any more and exits.  Recursion is the basis of all fractals, its how you get the repeating patterns.

I modded this code to use my Minecraft Graphics Turtle and rather than create 2 branches each time the function is called it creates 4 branches - 2 facing north to south and 2 facing east to west.

#Minecraft Turtle Example
import minecraftturtle
import minecraft
import block

def tree(branchLen,t):
    if branchLen > 6:
        if branchLen > 10:
            t.penblock(block.WOOD)
        else:
            t.penblock(block.LEAVES)

        #for performance
        x,y,z = t.position.x, t.position.y, t.position.z
        #draw branch
        t.forward(branchLen)
        
        t.up(20)
        tree(branchLen-2, t)
        
        t.right(90)
        tree(branchLen-2, t)

        t.left(180)
        tree(branchLen-2, t)

        t.down(40)
        t.right(90)
        tree(branchLen-2, t)

        t.up(20)
        
        #go back
        #t.backward(branchLen)
        #for performance - rather than going back over every line
        t.setposition(x, y, z)

#create connection to minecraft
mc = minecraft.Minecraft.create()

#get players position
pos = mc.player.getPos()

#create minecraft turtle
steve = minecraftturtle.MinecraftTurtle(mc, pos)

#point up
steve.setverticalheading(90)

#set speed
steve.speed(0)

#call the tree fractal
tree(20, steve)

The other change I made was to change the block type so that the shorter branches (the ones at the top) are made of leaves and the ones at the bottom are made of wood.

I created these on the full version of Minecraft using Bukkit and Raspberry Juice, so I could take hi-def pictures but the same code works on the raspberry pi.

If you want to have a go, download the minecraft turtle code from github.com/martinohanlon/minecraft-turtle and run the example_3dfractaltree.py program:

sudo apt-get install git-core
cd ~
git clone https://github.com/martinohanlon/minecraft-turtle.git
cd ~/minecraft-turtle
python example_3dfractaltree.py

I also made a fractal tree made out of random colours, check out example_3dfractaltree_colors.py.



Sunday, 29 June 2014

Raspberry Pi - ADXL345 Accelerometer & Python


A little while ago I got my hands on a Adafuit ADXL345 (a triple axis accelerometer) from pimoroni, you can also get them from Amazon (US, UK) if that's easier, and I finally got around to setting it up.

Pimoroni also provide a really useful python module to interacting with the ADXL345 which you can get from github - https://github.com/pimoroni/adxl345-python.

Connecting it up
Wiring up the accelerometer is pretty easy, there are only 4 connections:

Raspberry Pi -> ADXL345:
  • GND - GND 
  • 3V - 3V3
  • SDA - SDA
  • SCL - SCL

Configure your Pi
The ADXL345 supports both I2C and SPI connections, I used I2C, which requires some configuration on the Pi:

Add the I2C modules to the Pi's configuration:
sudo nano /etc/modules
add the following lines:
i2c-bcm2708
i2c-dev
Remove I2C from the blacklist:
sudo nano /etc/modprobe.d/raspi-blacklist.conf
comment out:
blacklist i2c-bcm2708
so its:
#blacklist i2c-bcm2708
Reboot to make the changes:
sudo shutdown -r now
Install Software
You will need to install some software:
sudo apt-get install python-smbus i2c-tools git-core
Test ADXL345
You can check that your ADXL345 is found on the I2C bus, by running:
sudo i2cdetect -y 1
You should see a device at address 53


Download the ADXL345 pimoroni python library from github:
git clone https://github.com/pimoroni/adxl345-python
Run the example code and test it is working:
cd adxl345-python
sudo python example.py
You should see the G readings from the ADXL345.


If you get 0.000G for all axis then something probably isn't set-up correctly.

Writing your own python program
The adxl345-python project from pimoroni contains a python module for reading data from the ADXL345 perhaps not unsurprisingly called "adxl345.py", inside there is a class called "ADXL345" which is how you to interact with the accelerometer

The program below imports the module, instantiates an ADXL345 object and reads values from the accelerometer as g-forces.
#import the adxl345 module
import adxl345

#create ADXL345 object
accel = adxl345.ADXL345()

#get axes as g
axes = accel.getAxes(True)
# to get axes as ms^2 use
#axes = accel.getAxes(False)

#put the axes into variables
x = axes['x']
y = axes['y']
z = axes['z']

#print axes
print x
print y
print z
Change sensitivity
You can change the sensitivity of the ADXL345 by using the .setRange() method of the class.

The default range is 2g which means that the maximum G the ADXL345 can measure is 2.048, but at a high degree of sensitivity, you can change it so the maximum is 2g, 4g, 8g or 16g but with a lower level of sensitivity using:
accel.setRange(adxl345.RANGE_2G)
accel.setRange(adxl345.RANGE_4G)
accel.setRange(adxl345.RANGE_8G)
accel.setRange(adxl345.RANGE_16G)
Its a great accelerometer and really easy to use in your python projects.

Wednesday, 21 May 2014

Minecraft Graphics Turtle

Spiral built using the Minecraft Turtle
I have had this idea of creating a 3d graphics turtle in Minecraft for a little while so one Sunday morning while I was waiting for the boy to finish a swimming lesson this is what I did.

The Minecraft Graphics Turtle allows you to use the Minecraft world as your drawing studio and unlike most graphics turtle's you aren't confined to 2d space, you can go up and down as well as left and right, and when your master piece is finished, you can walk around it!



The MinecraftTurtle is really easy to install and use, you only need a single python module (minecraftturtle.py), which needs to be copied to the same folder as the minecraft python api (minecraft.py, connection.py, block.py, etc), so if your using a Pi, its usually ~/mcpi/api/python/mcpi.

If you want to get started quickly through, I would download the complete code from my github, as it contains some examples and all the files you need to have go.

Download Minecraft Turtle Code:
sudo apt-get install git-core
cd ~
git clone https://github.com/martinohanlon/minecraft-turtle.git

Try the 'squares' example:
Startup Minecraft and load a game.
cd ~/minecraft-turtle
python example_squares.py

Create your own turtle program:
The turtle is really easy to program, Open IDLE (not IDLE3), create a new file and save it in the ~/minecraft-turtle directory.
import minecraftturtle
import minecraft
import block

#create connection to minecraft
mc = minecraft.Minecraft.create()

#get players position
pos = mc.player.getPos()

#create minecraft turtle at the players position and give it a name
steve = minecraftturtle.MinecraftTurtle(mc, pos)

#tell the turtle to go forward 15 blocks
steve.forward(15)

#tell the turtle to go right 90 degrees
steve.right(90)

#tell the turtle to go up by 45 degress
steve.up(45)

tell the turtle to go forward 25 blocks
steve.forward(25)

Run the program and you should see the turtle draw 2 lines, one straight ahead, the other at a 90 degree angle right and a 45 degree angle up.

The turtle supports lots of other commands:
#create the turtle
#  position is optional, without it gets created at 0,0,0
steve = minecraftturtle.MinecraftTurtle(mc, pos)

#rotate right, left by a number of degrees
steve.right(90)
steve.left(90)

#pitch up, down by a number of degress
steve.up(45)
steve.down(45)

#go forward, backward by a number of blocks
steve.forward(15)
steve.backward(15)

#get the turtles position
turtlePos = steve.position
print turtlePos.x
print turtlePos.y
print turtlePos.z

#set the turtles position
steve.setposition(0,0,0)
steve.setx(0)
steve.sety(0)
steve.setz(0)

#set the turtles headings (angle)
steve.setheading(90)
steve.setverticalheading(90)

#put the pen up/down
steve.penup()
steve.pendown()

#get if the pen is down
print steve.isdown()

#change the block the pen writes with
steve.penblock(block.DIRT.id)

#change the turtles speed (1 - slowest, 10 - fastest, 0 - no animation, it just draws the lines)
steve.speed(10)

#return the turtle to the position it started in
steve.home()

Have a look at the other examples and see what you can create.