Sunday, 5 January 2014

An AirPi - Useful in a Powercut

In March 2013 I built a Raspberry Pi AirPi and I've had it up and running ever since.  The system has proved to be very reliable; I reckon it's only stopped working 2 or 3 times since I set it up.  The Python scripts are setup to run when the Pi starts so the AirPi will automatically start up if there's a power cut or glitch.

I do this by putting scripts in the /etc/init.d folder.  Here's an example:

#Used this as a guide http://myraspberrypiexperience.blogspot.co.uk/2012/08/star
t-vnc-automatically.html
#Run this under the Pi username
export USER='pi'
eval cd ~$USER

#Run the Airpi
su $USER -c 'sudo python /home/pi/Meteoros/pdw_upload_v3.py &'

#End stuff
exit 0

We've had some pretty wet and windy weather in the UK over the Christmas period (it's still poor as I write early in the new year) which has resulted in long power cuts all over the country.  We suffered a power cut at my house for 26 hours from roughly 1300 on 23/12/2013 to 1500 on 24/12/2013.  

Here's my AirPi barometric pressure chart for the period:


On the graph you can see the pressure suddenly drop; the weather conditions that coincided with this were high winds and heavy rain.  This caused trees to be blown over which caused a power cut to the place I live in which you can see on the graph as the horizontal line from the 23rd to the 24th.  A power cut means no power to the RasPi and no ADSL router, hence there are no measurements for this period.

The AirPi came in useful as we were due as a family to travel to my in-laws on the 24th for Christmas.  It's a reasonably long drive so we were due to leave at 0830ish on the 24th.  With the power out we decided to stay put as we didn't know what state the house would be in when the power came back on (i.e. freezer defrosted, lights left on).  However by 1200 the power was still off and with a long drive ahead of us we decided to give a key to neighbour, switch off everything we could, chuck out a load of food from the freezer and then crack on with the drive.

In the end the drive went well and we arrived before 1600.  Then, just after 1600 I got a Twitter direct message from my Raspberry Pi, (more on that later), which let me know that it was up and running again.  Shortly after I got a text from my neighbour to tell me that all was well with the house.

The next question was whether the heating would come on properly after the power cut; it would be a bad thing not to have this on during winter.  My AirPi gave me the answer as I could see the temperature in the house going up and down twice a day.  (I could monitor this remotely via Xixely).


It was interesting to look at the temperature profile, (chart for the 25th shown below):

The heating came on in the early hours of the morning and then early in the afternoon which matched the twice a day timer program I had set.  It heated up to roughly the expected temperature  (the thermostat was in another room and set to 19 Celsius).  It was good to see that the room heated up quicker than it cooled down which shows that the insulation must be doing some good.  What was interesting was the the heating was coming on several hours earlier than expected.  What I assumed (and later proved) was that when the power came on at 1600, the clock on the heating controller must have resumed at the time it held when the power went off(1300).  Hence the clock was running roughly 3 hours fast. 

It's also interesting to compare the fairly regular temperature profile while we were away (two peaks a day, a longer one in the afternoon) with one when we were at home the next week:

The "at home" peak is a lot more messy as we control the heating manually, tinker with the main thermostat and TRVs, open doors and windows etc.

I mentioned earlier that the thing that prompted me that the power was back on was a tweet from the Raspberry Pi. I have the Pi GET a temperature measurement from Xively and send it to me as a Twitter direct message (which I can pick up on my Android handset).  The fact that I get one of these every hour just tells me that the Pi is still up and working and it's also good for inter-geek boasting!

I used this utterly excellent document from the Raspberry Pi Foundation to tell me how to tweet from the Pi using Python (see page 115).  The code is below (secret values edited out) but in simple terms, every hour it picks up the latest temperature reading from Xively and posts it as a Twitter direct message.  It uses the twitter Python module.  Here's a screenshot:


#Using Twitter to communicate COSM values
#Example URL is http://api.cosm.com/v2/feeds/XXXXX.csv?datastreams=0
#This returns the last value for datastream 0
import os
from twitter import *
import time
from datetime import datetime
from httplib import HTTP

#The URL we will use
COSMURL = "api.cosm.com"
FullCOSMURL = "http://api.cosm.com/v2/feeds/104017.csv?datastreams=0"
KeyToUse = <Deleted>

#Make a HTTP request to COSM to get a string
def GetCOSM():
  try:
    #Now do the HTTP magic - Connect to the server
    h = HTTP(COSMURL)

    #Do a get
    h.putrequest('GET',FullCOSMURL)

    # setup the API Key
    h.putheader('X-ApiKey',KeyToUse)

    # we're done with the headers....
    h.endheaders()

    #Get the response
    errcode, errmsg, headers = h.getreply()
    response = h.getfile()
    data = response.read()
    h.close()
    print data
    return data
  #Catch an exception
  except Exception, err:
    #Write a log with the error
    print "Got us an exception: " + str(err)

#MAIN BODY OF CODE
#Go in to a loop sending direct messages
while True:
  #Using the @mrjamesbond account to send tweets
  #Went to https://dev.twitter.com/apps/new to set this up
  CONSUMER_KEY = <Deleted>
  CONSUMER_SECRET = <Deleted>

  # get full pathname of .twitterdemo_oauth file in the
  # home directory of the current user
  oauth_filename = os.path.join(os.path.expanduser('~'),'.twitterdemo_oauth')

  # get twitter account login info
  if not os.path.exists(oauth_filename):
    oauth_dance('Raspberry Pi Twitter Demo', CONSUMER_KEY, CONSUMER_SECRET, oauth_filename)
  (oauth_token, oauth_token_secret) = read_token_file(oauth_filename)

  # log in to Twitter
  auth = OAuth(oauth_token, oauth_token_secret, CONSUMER_KEY, CONSUMER_SECRET)
  twitter = Twitter(auth=auth)
  try:
   #Send a direct message
   MessageToSend = "AirPi Temperature Reading " + GetCOSM()
   #print MessageToSend
   twitter.direct_messages.new(user="pauldavidweeks",text=MessageToSend)

   # Tweet a new status update
   #twitter.statuses.update(status=MessageToSend)

   # Display all my tweets
   #for tweet in twitter.statuses.user_timeline():
     #print('Created at',tweet['created_at'])
     #print(tweet['text'])
     #print('-'*80)
  except:
    print "Got a Twitter error"

  time.sleep(3600) 



Thursday, 21 November 2013

Raspberry Pi Powered Lego Car 2.0

Want to take a Raspberry Pi, some Lego motors and a Wii Controller and build a remote control car?  Well read on as this page will tell you how to do it!!

Last year my daughters and I built a Lego car that, with the addition of a Raspberry Pi, some motors and a motor controller we could control using an Android mobile phone.

Having bought a Bluetooth dongle for another project (hopefully more about that in a later post), a random meander around the internet showed me I could link the Raspberry Pi to a Wii remote control (Wiimote) and do "stuff".  Hence I had the idea to control the Lego car with a Wii remote plus the Wii steering wheel you buy for things like Mario Kart Wii.

Here's a video of the final car.  Read on below to see how I made it.



The basic building blocks:
-Lego motors + Raspberry Pi + Motor controller.  Lots of detail on the post I wrote last year.
-A Bluetooth dongle, bought from modmypi.
-Details on how to integrate a Wiimote to a Linux machine using cwiid.  There's a great example of using it on the Cambridge University website.

Feedback I had from my daughters last year was that the old school Lego car we used was too slow (because it was heavy) and too difficult to steer.  Hence I decided to build a new, much smaller and lighter car with a different steering mechanism.

From a steering perspective, what was wrong last year was that the rack and pinion steering was simply too cumbersome.  To turn right you steered right.  Then to straighten up you had to steer left just enough to straighten up the wheels.  At this time you generally were not moving the car forward or back because it was too confusing.  All-in-all it was all too finicky so I decide to use a tank track style steering mechanism because this meant that you could send a simple "steer-right" or "steer left" command and it would only turn for the period you issue the command.

Using cwiid is very easy:
-Install on a Pi using the command sudo apt-get install python-cwiid.
-Import the library with import cwiid and create an object to access Wiimote actions using wm = cwiid.Wiimote() 
-Report button presses with wm.rpt_mode = cwiid.RPT_BTN and check the actual state with statements like if (wm.state['buttons'] & cwiid.BTN_1):
-Report the accelerometer state with wm.rpt_mode =  cwiid.RPT_ACC and get the actual state with  print(wm.state['acc'])

The accelerometer state is a tuple with 3 values.  When holding the Wiimote in the Wii steering wheel, it's the second value that varies if you steer left and right.  So doing:

wm.rpt_mode = cwiid.RPT_ACC
AccVar =  wm.state['acc']
...means that you can assess the left write position of the wheel by assessing AccVar[1].  With he Wiimote horizontal the value was 120.  It increased as I "steered" left and decreased as I "steered" right.  Hence I decided to set the steer left threshold as > 130 and the steer right threshold as < 110 which was roughly equal to the 10 o clock and 2 o clock positions.

So after playing with cwiid, button pressing and accelerometer reading I set about building the car. Here's a few more images:






I can't publish a full "how-to-build" guide as I made it up as I went along!  However here's a few highlights:
-Built on two levels; motors, tracks + wheels and Pi battery on the bottom layer, the Pi, motor controller board and motor battery on the top level.
-Two motors mounted at 90 degrees to the direction that the tank track turns.  I used a pair of cogs that allow motion to be transferred through 90 degrees.  These connected to a cog of equal size that drove the tank track.  I experimented with software PWM but found that with this gearing and the weight of the car I could simple switch the motors off and on and the car would move.  (I've left some of the PWM in the full code listing below so use it if you wish).
-Some tank tracks mounted on large cogs.  The tank tracks came from a Lego pneumatic excavator that I owned as a child. I did try various wheel arrangements but found it would only work with the tracks.
-On the top level, a careful arrangement of Raspberry Pi, motor controller board and motor battery.  For the battery I used an 7.2V, 5000mAh battery from an old camcorder.  This gives much more "play time" than the old PP3 re-chargeable I previously used.
-Various odds and ends to keep everything in place and stop the wires from falling out or snagging in the tracks.

Control of the tracks via the motors was very easy.  There is basically 5 ways to drive the motors:
-Left hand motor (LHM) clockwise, right hand motor (RHM) antiwise = Go forward.
-LHM anticlockwise, RHM clockwise = Go backward.
-LHM and RHM clockwise = Turn left.
-LHM and RHM anti-clockwise = Turn right.
-Motors off, stopped (!).

The code is basically a state machine that assesses which buttons are pressed and how the Wiimote is tilted, (e.g. button 1 pressed and Wiimote value between 110 and 120 means the state is ForwardNoSteer).  If the state does not change then no action is taken, if the state changes then the motors are command to move appropriately.

Full code listing below.  Next steps: do something with the Raspberry Pi camera and control the car with Scratch!


#Mostly used code from these two sites
#https://code.google.com/p/raspberry-gpio-python/wiki/PWM
#http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/robot/wiimote/

import cwiid 
import time
import os
import RPi.GPIO as GPIO   #The GPIO module

#A routine to control the pins
def ControlThePins(TheState):
  print "Controlling them pins:c" + TheState 
  #First just turn them all off - then we work out what to do
  GPIO.output(11,False)
  GPIO.output(13,False)
  GPIO.output(19,False)
  GPIO.output(21,False)

  #Just work through the different motor states, setting the pins accordingly
  if TheState == GoForward:
    GPIO.output(11,True)
    GPIO.output(13,False)
    GPIO.output(19,True)
    GPIO.output(21,False)
  elif TheState == GoBackward:
    GPIO.output(11,False)
    GPIO.output(13,True)
    GPIO.output(19,False)
    GPIO.output(21,True)
  elif TheState == SteerLeft:
    GPIO.output(11,True)
    GPIO.output(13,False)
    GPIO.output(19,False)
    GPIO.output(21,True)
  elif TheState == SteerRight:
    GPIO.output(11,False)
    GPIO.output(13,True)
    GPIO.output(19,True)
    GPIO.output(21,False)
  elif TheState == StopIt:
    #Do nothing as we stopped all pins first thing
    pass

  #Just return
  return

#This is a PWM routine.  
def ControlMyPins(Num11,Num13,Num19,Num21):
  print "PWM Control of pins using " + Num11 + "-" + Num13 + "-" + Num19 + "-" + Num21

  if Num11 == "1":
    #Speed the motor up
    for dc in range(0, 101, 5):
      PIN11.ChangeDutyCycle(dc)
      time.sleep(0.03)
  else:
      #Stop PWM
      PIN11.start(0)  

  if Num13 == "1":
    #Speed the motor up
    for dc in range(0, 101, 5):
      PIN13.ChangeDutyCycle(dc)
      time.sleep(0.03)
  else:
    #Stop PWM
    PIN13.start(0)  

  #And return
  return

#######################
#Main part of the code#
#######################

#Set up the GPIO pins
#Get rid of warnings
GPIO.setwarnings(False)

#Set the GPIO mode
GPIO.setmode(GPIO.BOARD)

#Set the pins to be outputs
GPIO.setup(11,GPIO.OUT)
GPIO.setup(13,GPIO.OUT)
GPIO.setup(19,GPIO.OUT)
GPIO.setup(21,GPIO.OUT)

#Set the pins to be PWM pins 
#PIN11 = GPIO.PWM(11, 100)  # channel=11 frequency=50Hz
#PIN11.start(0)
#PIN13 = GPIO.PWM(13, 100)
#PIN13.start(0)
#PIN19 = GPIO.PWM(19, 100)
#PIN19.start(0)
#PIN21 = GPIO.PWM(21, 100)
#PIN21.start(0)

#Now we start defining some constants to use.  We have three concepts:
#1)The motor command.  Stating Forward, Backward, Left, Right, Stop
#2)The sensor position and whether a button is pressed
#3)The system state, e.g. Sys1Level, Sys1Right etc
#We determine sensor position, see if the system state has changed and if so send a new motor command

#Motor commands
GoForward = "Forward"
GoBackward = "Backward"
SteerRight = "Right"
SteerLeft = "Left"
StopIt = "Stop"

#Constants for the system state and then an assignment
ForwardNoSteer = "FNS"
ForwardSteerLeft = "FSL"
ForwardSteerRight = "FSR"
BackwardNoSteer = "BNS"
BackwardSteerLeft = "BSL"
BackwardSteerRight = "BSR"
SystemStopped = "SS"
SystemState = SystemStopped

#Now left and right
#You get a 3 tuple and the middle value is what you need.
#Horizontal is 120.  Going right decreases the value so < 110 is steer right.  Going left increases the value so > 130 is steer left
SteerRightValue = 110
SteerLeftValue = 130

#Make the Bluetooth dongle discoverable
os.system("sudo hciconfig hci0 piscan")

#connecting to the Wiimote. This allows several attempts 
# as first few often fail. 
print 'Press 1+2 on your Wiimote now...' 

wm = None 
i=2 
while not wm: 
  try: 
    wm=cwiid.Wiimote() 
  except RuntimeError: 
    if (i>10): 
      print "Giving up connecting"
      quit() 
      break 
    print "Error opening wiimote connection" 
    print "attempt " + str(i) 
    i +=1 
    #Pause for a bit
    time.sleep(0.5)

#Got here, tell the user
print "Success - we have connected!"

#set Wiimote to report button presses and accelerometer state 
wm.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_ACC 

#Wait a bit
time.sleep(1)

#Do a celebratory LED KITT style sweep
LoopVar = 0
while LoopVar < 3: 
  #turn on leds to show connected 
  wm.led = 1
  time.sleep(0.1)
  wm.led = 2
  time.sleep(0.1)
  wm.led = 4
  time.sleep(0.1)
  wm.led = 8
  time.sleep(0.1)
  #Set up for next loop 
  LoopVar +=1  

#Turn off the LEDs now
wm.led = 0

#Wait a bit
time.sleep(0.5)

#Count in binary on the LEDs
#for i in range(16):
  #wm.led = i
  #time.sleep(0.5)

#Do a rumble
wm.rumble = True
time.sleep(0.5)
wm.rumble = False

#Now start checking for button presses
print "Ready to receive button presses and accelerometer input"

#Loop for ever detecting

try:
  while True:
    #Set up a button object to check
    buttons = wm.state['buttons']

    #We assess whether the Wiimote is level, left or right by assessing the accelerometer
    AccVar = wm.state['acc']
    
    #Check all the different possible states of button, accelerometer and system state.  First button 1 pressed and steering left
    if (buttons & cwiid.BTN_1) and (int(AccVar[1]) > SteerLeftValue) and (SystemState != ForwardSteerLeft):
      #Tell the user
      print "Forward Steer Left"

      #Change the state to be this now
      SystemState = ForwardSteerLeft
        
      #Set the motor state
      ControlThePins(SteerLeft)
    elif (buttons & cwiid.BTN_1) and (int(AccVar[1]) < SteerRightValue) and (SystemState != ForwardSteerRight):   #Button 1 pressed and steering right
      #Tell the user
      print "Forward Steer Right"

      #Change the state to be this now
      SystemState = ForwardSteerRight

      #Set the motor state
      ControlThePins(SteerRight)
    elif (buttons & cwiid.BTN_1) and ((int(AccVar[1]) >= SteerRightValue) and (int(AccVar[1]) <= SteerLeftValue)) and (SystemState != ForwardNoSteer):   #Button 1 pressed.  Acclerometer in the middle  
      #Tell the user
      print "Go forward"

      #Change the state to be this now
      SystemState = ForwardNoSteer

      #Set the motor state
      ControlThePins(GoForward)
    elif (buttons & cwiid.BTN_2) and (int(AccVar[1]) > SteerLeftValue) and (SystemState != BackwardSteerLeft):    #Backward and steering left
      #Tell the user
      print "Backward Steer Left"

      #Change the state to be this now
      SystemState = BackwardSteerLeft

      #Set the motor state
      ControlThePins(SteerLeft)
    elif (buttons & cwiid.BTN_2) and (int(AccVar[1]) < SteerRightValue) and (SystemState != BackwardSteerRight):   #Button 2 pressed and steering right
      #Tell the user
      print "Backward Steer Right"

      #Change the state to be this now
      SystemState = BackwardSteerRight

      #Set the motor state
      ControlThePins(SteerRight)
    elif (buttons & cwiid.BTN_2) and ((int(AccVar[1]) >= SteerRightValue) and (int(AccVar[1]) <= SteerLeftValue)) and (SystemState != BackwardNoSteer):   #Button 2 pressed.  Acclerometer in the middle  
      #Tell the user
      print "Go backward"

      #Change the state to be this now
      SystemState = BackwardNoSteer

      #Set the motor state
      ControlThePins(GoBackward)
    #No button pressed so we reach this else statement, see if it's because of a change of state  
    elif (not(buttons & cwiid.BTN_1)) and (not(buttons & cwiid.BTN_2)) and (SystemState != SystemStopped):  
      #Tell the user
      print "No buttons pressed"
         
      #Change the state to be this now
      SystemState = SystemStopped
          
      #Change the motor state to be off
      ControlThePins(StopIt)
      
    #Chill for a bit
    time.sleep(0.1)
except KeyboardInterrupt:
    pass

print "Good night"

#End of the code - turn off pins then exit
ControlThePins(StopIt)  





Sunday, 27 October 2013

Raspberry Pi Camera - Injury Diagnosis

When I'm not doing Dad Geekery, one of my other hobbies is keeping fit by running, cycling and swimming.  For a while I've been trying to think of a way to combine the two.  The arrival of a Raspberry Pi camera module over the summer gave me an idea....

Over the past couple of years I've been suffering from frequent left calf muscle injuries.  Basically when I run I get a sore left calf and occasionally I get a minor muscle tear.  Earlier in the year I bit the bullet and went to see a physio about it.  The advice from the physio was:

  • I needed to rest it to let it heal, and
  • The reason I get calf injuries is because my left leg is weaker then my right leg, (in fact the whole of the left side of my body is a relative weakling).

So the recommendation from the physio was to rest and then also to do a lot of left side strengthening, (e.g. knee bends, hopping up and down steps, doing interesting things with elastic resistance bands).

The "weak left side" diagnosis rings true through some other observations:
  • When I swim breast stroke I'm told my left leg kicks much less strongly than my right leg,
  • When I cycle and get tired, my left knee drops inwards and knocks against the cross bar,
  • When I went to buy new running trainers from a running specialist they did video analysis as I ran on a treadmill.  This showed my left foot landing and then rolling inwards too much which puts stress on my knee and calf muscle.

So when two things happened at once in a week during August 2013 (calf going ping again and the arrival of my RasPi camera module) I decided to do some scientific analysis.  The plan was to use my RasPi camera module to analyse me doing some physical jerks, do a period of strengthening and then repeat the analysis.

So first I needed to have a decent setup for the camera module. Using the magic of Lego I built this rig:


So the Lego keeps it all stable and with a hinged Lego piece (hidden by the ribbon cable on the image) allowing me to adjust the camera position up and down.

I then set this up outside on my patio so as to be able to record video of myself doing various exercises.  Here's the setup, (essential use of my old Lego case to keep it off the ground):



Using this command I could record a short video:
  
raspivid -t 10000 -o video1.h264

I could then turn this into an MP4 using this command:

MP4Box -fps 30 -add video1.h264 video1.mp4

(I had to install the MP4Box application to do this).

Here's a video of me jumping on the spot:


Now I think just by watching the video you can see my left foot being placed out wider than my right foot and my knee dropping outwards.

Transferring the video to a PC and using Quicktime, I could advance the video frame by frame.  I select the frame where my foot was planted and just about to spring up, so to my mind the point where there is maximum stress on my leg.  I did a print screen, pasted the image to Word and then drew straight lines from the middle of my knee downwards.  Here's the image I got:


So the line on my right leg goes down pretty straight from the middle of my knee to my heel.  On my left leg my knee is really turned outwards. More evidence of my dodgy left side.

Here's the equivalent for me running on the spot.  First the video:


...and then a split screen image:


Same again, this time for me skipping.  Video first:



...the the split screen image:


So overall, some excellent evidence of my weakling left side and how it impacts various exercises.

Over the course of August I embarked on a series of strengthening exercises to build up my left side.  I did a bit more strengthening in September / early October but at that time was more focused on training for a 10K run and then a multi-stage bike ride I was doing in middle of October.  The 10K race then the bike ride passed with no more injury and no evidence of my right knee knocking the cross bar.  

I ran this morning and, whilst I didn't get injured again I felt a bit of a niggle in my left calf.  It was cold day, the route was hilly and I'm a little paranoid about it; all things that might have contributed to the niggle.

So I decided to re do the analysis.  First the jumping:




...with the image:

The running video:

<Insert this when YouTube stops being so dumb>

...with the image:


...and finally the skipping video:


...with the skipping image:

Now I did two things differently in October when compared to August.  Firstly I had the camera aligned differently so you can't see my feet and secondly I only took 5s of video footage. A bit daft that!

My observation is that things are straighter now than they were back in August.  The straight line from my left knee runs down the middle of my calf.

So my strengthening exercises are working and I have tangible proof of this.  Thanks Raspberry Pi camera board!  However I'm not 100% sure everything is super straight so I will come back to this in a couple of months and re-run the exercise.





















Friday, 26 April 2013

Blue Raspberry Pi

There was much excitement in the Geek household yesterday when my limited edition Blue Raspberry Pi arrived.


The Raspberry Pi Foundation produced 1000 of these to celebrate the first year of production of the Raspberry Pi.

RS ran a competition on Twitter, the winning prize being a Blue Pi.  To enter the competition, all you had to do was Tweet @RSElectronics with the hashtag #bluepi and a description of what you'd do with a blue Pi.  Here was my entry:

So easy to enter, I didn't even have to enclose a stamped, addressed envelope*.  I only went and won!  I was chuffed to bits.

The observant Geek dad blog fan will observe that I've already made a Scratch controlled Raspberry Pi disco.  The reality is that, following the mantra that "a pessimist is never disappointed",  I didn't think I'd be lucky enough to win a blue Pi. Hence I want out and bought another Pi to use, (my first Pi being busy running my environment monitor). But I did!!

* Showing my age.