Python and PDF

Here is an example of how to merge the first pages of a number of pdf pages into a single file.

I wrote this script, because I needed to print the first page of 200 individual files and I didn’t really want to open each one manually…

 

import os.path, pyPdf
from os import walk
 
output = pyPdf.PdfFileWriter()
original = "c:\\original\\folder\\"
f = []
 
for (dirpath, dirnames, filenames) in walk(original): f.extend(filenames)
 
for eachfile in filenames: 
	ffile = original + "\\" + eachfile
 
	if "pdf" in eachfile:
		pdf = pyPdf.PdfFileReader(open(ffile, "rb"))
		output.addPage(pdf.getPage(0))
	print ffile
 
outputStream = open("c:\\out.pdf", "wb")
output.write(outputStream)
outputStream.close()

Simple File Rename script in Python

import os
indir = 'c:\\datafilepath\\'

for filename in os.listdir(indir):
	if filename.startswith("xyz_"):
		newname = filename.replace("xyz_","abc_")
		try: 
			os.rename(indir + filename, indir + newname)
			print "[NEW]", filename, "-->", newname
		
		except:
			print "[OLD]", filename, "-->", newname

Robot Challenge 009

Not much progress to report. My compass module seems to have died, probably due to the fact I was feeding it 5V instead of the required 3.3V… Never mind, new module ordered.

I’ve added a new level to the robot and now looks neater. Here are a couple of photos:

With a camera (placeholder – not really attached):
DSCF0920_top_20

Without camera:
DSCF0928_no_cam_20

Raspberry Pi Samba Share

My RPi is the brain of my ARK-AV-01 robot. As I currently am in the programming phase, I found myself programming it from the command line. I wanted something easier, with no login/password, so I activated samba with the following samba.conf file:

[global]
workgroup = mygroup
interfaces = wlan
bind interfaces only = yes
server string = Arkadian's ARK-AV-01
security = share
guest account = nobody
log file = /var/log/samba.%m

[Robot]
comment = Robot Control Center
path = /robot/
available = yes
browseable = yes
public = yes
writable = yes
read only = no
guest ok = yes

The above configuration allows you to connect to the /robot/ folder from any windows or linux machine.

I had to also run the following commands

sudo chown nobody /robot

and

sudo chmod 777 /robot -R

to ensure the folder is owned by user nobody and is writable.

then, just restart the samba service:

sudo service samba restart

And now you can mount the folder /robot to your windows or linux machine!
if everything works ok, make sure to add samba to the startup script:

sudo update-rc.d samba defaults

Robot Challenge 008

As promised, here is a video I’ve put together of the RC mode.

Robot Challenge 008 from Arkadian.Eu on Vimeo.

Also as promised, here is the Python code which, when run on a Raspberry Pi, it receives OSC signals from my iPad, interprets them and gets the Arduino board to perform the required action.

This is very rough, and doesn’t not include the code for clockwise and anticlockwise rotation (as I made the addition directly on the raspberry and it’s now out of battery). Clearly, this requires the simpleOSC and pyFirmata libraries to be installed. Most of the code you see here is just a quick mashup, based on examples from the SimpleOSC and pyFirmata libraries. For me the key is that it works! 🙂

import OSC, time, threading, os, serial
 
import pyfirmata
from pyfirmata import *
from boards import BOARDS
 
class ArduinoMega(Board):
	"""
	A board that will set itself up as an Arduino Mega.
	"""
	def __init__(self, *args, **kwargs):
		args = list(args)
		args.append(BOARDS['arduino_mega'])
		super(ArduinoMega, self).__init__(*args, **kwargs)
 
	def __str__(self):
		return 'Arduino Mega %s on %s' % (self.name, self.sp.port)
 
# Adjust that the port match your system:
PORT = '\\.\COM4' 		#On Windows
#PORT = '/dev/ttyACM0' 	#On RPi
 
# Creates a new board 
board = ArduinoMega(PORT)
 
# ##################################################################
def engine(path, tags, args, source):
	print path, "@TAGS", tags, "@ARGS", args, "@SOURCE", source
	file = "Car_Start_2.mp3"
	print "starting engine"
	#os.startfile(file) # 
 
# ##################################################################
def rcMode(path, tags, args, source):
	print path, "@TAGS", tags, "@ARGS", args, "@SOURCE", source
	print "Switching to RC mode"
	#os.startfile(file)
# ##################################################################
def autoMode(path, tags, args, source):
	print path, "@TAGS", tags, "@ARGS", args, "@SOURCE", source
	print "Switching to AUTO mode"
	#os.startfile(file)
# ##################################################################
def questMode(path, tags, args, source):
	print path, "@TAGS", tags, "@ARGS", args, "@SOURCE", source
	print "Switching to QUEST mode"
	#os.startfile(file)	
 
# LIGHTS SECTION
# ##################################################################
PIN2 = board.get_pin('d:2:p')
def lightR(path, tags, args, source):
	PIN2.write(1 - args[0])
	print path, "@TAGS", tags, "@ARGS", args, "@SOURCE", source	
# ##################################################################
# ##################################################################
PIN3 = board.get_pin('d:3:p')
def lightG(path, tags, args, source):
	PIN3.write(1- args[0])
	print path, "@TAGS", tags, "@ARGS", args, "@SOURCE", source	
# ##################################################################
# ##################################################################
PIN4 = board.get_pin('d:4:p')
def lightB(path, tags, args, source):
	PIN4.write(1-args[0])
	print path, "@TAGS", tags, "@ARGS", args, "@SOURCE", source	
# ##################################################################
# ##################################################################
PIN13 = board.get_pin('d:13:p')
def lightFloor(path, tags, args, source):
	PIN13.write(1 - args[0])
	print path, "@TAGS", tags, "@ARGS", args, "@SOURCE", source	
# ##################################################################
 
 
# MOTOR SECTION
# ##################################################################
PINA = board.get_pin('d:8:s')
PINB = board.get_pin('d:9:s')
PINC = board.get_pin('d:10:s')
PIND = board.get_pin('d:11:s')
 
def motor(aa,bb,cc,dd):
	print aa, bb, cc, dd
 
	if aa==1: PINA.write(20)
	if aa==-1: PINA.write(138)
	if aa==0: PINA.write(91)
 
	if bb==1: PINB.write(20)
	if bb==-1: PINB.write(138)
	if bb==0: PINB.write(91)
 
 
	if cc==1: PINC.write(20)
	if cc==-1: PINC.write(138)
	if cc==0: PINC.write(91)
 
	if dd==1: PIND.write(20)
	if dd==-1: PIND.write(138)
	if dd==0: PIND.write(91)
 
def xmotor(path, tags, args, source):
	direction = path.split("/")[2]
	print "PIN", path.split("/")[2], "@TAGS", 
	print tags, "@ARGS", args, "@SOURCE", source	
 
	if args[0]==0: 
		motor(0,0,0,0)
	else:
		if direction == "nn" 	: motor(1,0,-1,0)
		if direction == "ne"	: motor(1,1,-1,-1)
		if direction == "ee"	: motor(0,1,0,-1)
		if direction == "se"	: motor(-1,1,1,-1)
		if direction == "ss"	: motor(-1,0,1,0)
		if direction == "sw"	: motor(-1,-1,1,1)
		if direction == "ww"	: motor(0,-1,0,1)
		if direction == "nw"	: motor(1,-1,-1,1)
		if direction == "freeze": motor(0,0,0,0)
# ##################################################################	
# ##################################################################
 
def user_callback(path, tags, args, source):
	user = ''.join(path.split("/"))
	print "cb-->",  path, "@TAGS", tags, 
	print "@ARGS", args, "@SOURCE", source
 
def quit_callback(path, tags, args, source):
	#pass
	# don't do this at home (or it'll quit blender)
	global run
	run = False
 
# tupple with ip, port
receive_address = "192.168.0.47", 7110  
 
# OSC Server. there are three different types of server. 
#s = OSC.OSCServer(receive_address) # basic
s = OSC.ThreadingOSCServer(receive_address) # threading
##s = OSC.ForkingOSCServer(receive_address) # forking
 
s.addDefaultHandlers()
 
s.addMsgHandler( "/1/start", engine)
 
s.addMsgHandler( "/1/rc", rcMode) 	
s.addMsgHandler( "/1/auto", autoMode)
s.addMsgHandler( "/1/quest", questMode)
 
s.addMsgHandler( "/1/nn", xmotor)
s.addMsgHandler( "/1/ne", xmotor)
s.addMsgHandler( "/1/ee", xmotor)
s.addMsgHandler( "/1/se", xmotor)
s.addMsgHandler( "/1/ss", xmotor)
s.addMsgHandler( "/1/sw", xmotor)
s.addMsgHandler( "/1/ww", xmotor)
s.addMsgHandler( "/1/nw", xmotor)
s.addMsgHandler( "/1/freeze", xmotor)
 
s.addMsgHandler( "/2/red", lightR)
s.addMsgHandler( "/2/green", lightG)
s.addMsgHandler( "/2/blue", lightB)
 
s.addMsgHandler( "/2/grey", lightFloor)
 
s.addMsgHandler( "/ping", user_callback )
s.addMsgHandler( "/quit", quit_callback )
 
# define a message-handler function for the server to call.
def printing_handler(addr, tags, stuff, source):
	print "---"
	print "received new osc msg from %s" % OSC.getUrlStr(source)
	print "with addr : %s" % addr
	print "typetags %s" % tags
	print "data %s" % stuff
	print "---"
 
s.addMsgHandler("/print", printing_handler) # adding our function
 
 
# just checking which handlers we have added
print "Registered Callback-functions are :"
for addr in s.getOSCAddressSpace(): print addr
 
# Start OSCServer
print "\nStarting OSCServer. Use ctrl-C to quit."
st = threading.Thread( target = s.serve_forever )
st.start()
 
try :
	while 1 : pass
 
except KeyboardInterrupt :
	print "\nClosing OSCServer."
	s.close()
	print "Waiting for Server-thread to finish"
	st.join() ##!!!
	print "Done"

Lines 150-173 are linked to my touchOSC template. For instance “nn” stands for North, “ne” for North East etc…
The TouchOSC editor allows you to give your buttons friendly names. The created template itself, while suffixed with a “.touchosc”, is simply a zipped xml file (in case you want to really fine-tune it!). The editor does a great job – pity it doesn’t work with Android…

Lines 116-124 control the wheels. Basically, 1 is clockwise, -1 is acti-clockwise and 0 is break. The list in motor(1,0,-1,0) includes a value for each one of my four motors. The two rotation functions missing here, simply have motor(1,1,1,1) and motor(-1,-1,-1,-1).

The engine function (line 28) will be playing an mp3 with the sound of a car engine starting, when the virtual engine key is turned. It works fine on Windows and it should be quite easy to get it to work on RPi too.

Robot Challenge 007

I had a productive couple of days. Arkadian AV-1 is now operational as a remote control vehicle.

Arduino
I’m using the StandardFirmata library on the Arduino Mega 2560, with no modifications whatsoever. It was by far the easiest way to get RaspberryPi to control the 4 motors, receive feedback from the 4 sensors (on order from Sparkfun, should be here soon) and have the ability to switch on and off the lights on the robot.

RaspberryPi
The RaspberryPi is loaded with Ladyada’s RPi distro, as it had the latest python library and a few other things that I’m planning on using later on. I have added the PyFirmata library (to control the Arduino) and the OSC library (as described previously) to receive instructions from the OSC pad.

TouchOSC
I have been using TouchOSC to create the remote control interface. My original plan was to use the Nexus tablet to control the robot. The problem is that TouchOSC is a bit behind when it comes to Android. The app is available to buy, but you cannot upload your own templates, which makes it pretty useless. I’ll be using an iPad for now, but I hope they get the android version sorted soon.

Here is my latest layout (first page):
OSC_Control_Panel_004

The two buttons under the “Quest”, are for clockwise and anti-clockwise rotation.

Vehicle is very responsive and drives really well. Orientation gets a bit tricky for the human brain if the rotation buttons are not used, but for the “Quest Mode” this will really be ideal.

I’ll post the code, photos and a video tomorrow.

Next week, I’ll finish off the sensors (proximity and compass), tidy up the cables and put everything in a more permanent position. My code needs a bit of tidying up too; it’s really a mess right now (but, hey, it works!).