Permalink
Browse files

Potentially using an Arduino instead of Velleman

This introduces the pyduino module, and imports it to dalek.py,
where it is currently not used.
  • Loading branch information...
1 parent beb5d67 commit cf9a94953b4165dc63d5f162d8ae310750c01dbd @ColonyTestSuperuser ColonyTestSuperuser committed Oct 5, 2011
Showing with 300 additions and 2 deletions.
  1. +10 −2 dalek.py
  2. +290 −0 pyduino.py
View
@@ -17,6 +17,9 @@
#Velleman board
from pyk8055 import *
+#Arduino - only one of this and Velleman will be used. Probably...
+import pyduino
+
#Buttons on wheel:
#0: X
#1: O
@@ -41,12 +44,17 @@ def handle_file_browser_closed(dlg, guiInput):
if dlg.value: guiInput.value = dlg.value
+def sendSignalVelleman(signalCode):
+ k.WriteAllDigital(signalCode)
+ k.WriteAllDigital(0)
+def sendSignalArduino(signalCode):
+ print signalCode
def sendSignal(signalCode):
#Flashes signal to Veleman
- k.WriteAllDigital(signalCode)
- k.WriteAllDigital(0)
+ sendSignalVelleman(signalCode)
+
def headTrackState(arg):
btn, text = arg
View
@@ -0,0 +1,290 @@
+#! /usr/bin/env python
+
+"""pyduino - A python library to interface with the firmata arduino firmware.
+Copyright (C) 2007 Joe Turner <orphansandoligarchs@gmail.com>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+"""
+
+__version__ = "0.19_dev"
+
+import time
+import serial
+
+# Message command bytes - straight outta Pd_firmware.pde
+DIGITAL_MESSAGE = 0x90 # send data for a digital pin
+ANALOG_MESSAGE = 0xE0 # send data for an analog pin (or PWM)
+
+# PULSE_MESSAGE = 0xA0 # proposed pulseIn/Out message (SysEx)
+# SHIFTOUT_MESSAGE = 0xB0 # proposed shiftOut message (SysEx)
+
+REPORT_ANALOG_PIN = 0xC0 # enable analog input by pin #
+REPORT_DIGITAL_PORTS = 0xD0 # enable digital input by port pair
+START_SYSEX = 0xF0 # start a MIDI SysEx message
+SET_DIGITAL_PIN_MODE = 0xF4 # set a digital pin to INPUT or OUTPUT
+END_SYSEX = 0xF7 # end a MIDI SysEx message
+REPORT_VERSION = 0xF9 # report firmware version
+SYSTEM_RESET = 0xFF # reset from MIDI
+
+# Pin modes
+UNAVAILABLE = -1
+DIGITAL_INPUT = 0
+DIGITAL_OUTPUT = 1
+DIGITAL_PWM = 2
+
+
+PWM_PINS = (9, 10, 11)
+
+class Arduino:
+ """Base class for the arduino board"""
+
+ def __init__(self, port):
+ self.sp = serial.Serial(port, 115200, timeout=0.02)
+ # Allow 2 secs for Diecimila auto-reset to happen
+ time.sleep(2)
+
+ self.analog = []
+ for i in range(6):
+ self.analog.append(AnalogPin(self.sp, i))
+
+ self.digital_ports = []
+ for i in range(2):
+ self.digital_ports.append(DigitalPort(self.sp, i))
+
+ # Don't mess with Rx/Tx
+ self.digital_ports[0].pins[0].mode = UNAVAILABLE
+ self.digital_ports[0].pins[1].mode = UNAVAILABLE
+ # Pins 14 and 15 aren't used
+ self.digital_ports[1].pins[6].mode = UNAVAILABLE
+ self.digital_ports[1].pins[7].mode = UNAVAILABLE
+
+ # Syntactic sugar - don't make the end user mess with ports too much
+ # and keep the api stable-ish
+ self.digital = []
+ self.digital += self.digital_ports[0].pins
+ # Leave out pins 14 and 15 so the length matches the board
+ self.digital += self.digital_ports[1].pins[:6]
+
+ # Obtain firmata version
+ self.firmata_version = None
+ self.sp.write(chr(REPORT_VERSION))
+ self.iterate()
+
+ def __str__(self):
+ return "Arduino: %s"% self.sp.port
+
+ def iterate(self):
+ """Read and handle a command byte from Arduino's serial port"""
+ data = self.sp.read()
+ if data != "":
+ self._process_input(ord(data))
+
+ def _process_input(self, data):
+ """Process a command byte and any additional information bytes"""
+ if data < 0xF0:
+ #Multibyte
+ message = data & 0xF0
+ if message == DIGITAL_MESSAGE:
+ port_number = data & 0x0F
+ #Digital in
+ lsb = ""
+ msb = ""
+ while lsb == "":
+ lsb = self.sp.read()
+ while msb == "":
+ msb = self.sp.read()
+ lsb = ord(lsb)
+ msb = ord(msb)
+ self.digital_ports[port_number].set_value(msb << 7 | lsb)
+ elif message == ANALOG_MESSAGE:
+ pin_number = data & 0x0F
+ #Analog in
+ lsb = ""
+ msb = ""
+ while lsb == "":
+ lsb = self.sp.read()
+ while msb == "":
+ msb = self.sp.read()
+ lsb = ord(lsb)
+ msb = ord(msb)
+ value = float(msb << 7 | lsb) / 1023
+ self.analog[pin_number].set_value(value)
+ elif data == REPORT_VERSION:
+ minor, major = self.sp.read(2)
+ self.firmata_version = (ord(major), ord(minor))
+
+ def get_firmata_version(self):
+ """Return a (major, minor) version tuple for the firmata firmware"""
+ return self.firmata_version
+
+ def exit(self):
+ """Exit the application cleanly"""
+ self.sp.close()
+
+class DigitalPort:
+ """Digital pin on the arduino board"""
+ def __init__(self, sp, port_number):
+ self.sp = sp
+ self.port_number = port_number
+ self.is_active = 0
+
+ self.pins = []
+ for i in range(8):
+ self.pins.append(DigitalPin(sp, self, i))
+
+ def __str__(self):
+ return "Digital Port %i"% self.port_number
+
+ def set_active(self, active):
+ """ Set the port to report values """
+ self.is_active = active
+ message = chr(REPORT_DIGITAL_PORTS + self.port_number)
+ message += chr(active)
+ self.sp.write(message)
+
+ def get_active(self):
+ """Return whether the port is reporting values"""
+ return self.is_active
+
+ def set_value(self, mask):
+ """Record the value of each of the input pins belonging to the port"""
+
+ for pin in self.pins:
+ if pin.mode == DIGITAL_INPUT:
+ pin.set_value((mask & (1 << pin.pin_number)) > 1)
+
+ def write(self):
+ """Set the output pins of the port to the correct state"""
+ mask = 0
+ for pin in self.pins:
+ if pin.mode == DIGITAL_OUTPUT:
+ if pin.value == 1:
+ mask |= 1 << pin.pin_number
+ message = chr(DIGITAL_MESSAGE + self.port_number)
+ message += chr(mask % 128)
+ message += chr(mask >> 7)
+ self.sp.write(message)
+
+class DigitalPin:
+ """Digital pin on the arduino board"""
+
+ def __init__(self, sp, port, pin_number):
+ self.sp = sp
+ self.port = port
+ self.pin_number = pin_number
+ self.value = 0
+ self.mode = DIGITAL_INPUT
+
+ def __str__(self):
+ return "Digital Pin %i"% self.pin_number
+
+ def set_mode(self, mode):
+ """Set the mode of operation for the pin
+
+ Argument:
+ mode, takes a value of: - DIGITAL_INPUT
+ - DIGITAL_OUTPUT
+ - DIGITAL_PWM
+
+ """
+ if (mode == DIGITAL_PWM and
+ self._get_board_pin_number() not in PWM_PINS):
+ error_message = "Digital pin %i does not have PWM capabilities" \
+ % (self._get_board_pin_number())
+ raise IOError, error_message
+ if self.mode == UNAVAILABLE:
+ raise IOError, "Cannot set mode for pin %i" \
+ % (self._get_board_pin_number())
+ self.mode = mode
+ command = chr(SET_DIGITAL_PIN_MODE)
+ command += chr(self._get_board_pin_number())
+ command += chr(mode)
+ self.sp.write(command)
+
+ def get_mode(self):
+ """Return the pin mode, values explained in set_mode()"""
+ return self.mode
+
+ def _get_board_pin_number(self):
+ """Return the number of the pin as written on the board"""
+ return (self.port.port_number * 8) + self.pin_number
+
+ def set_value(self, value):
+ """Record the value of the pin"""
+ self.value = value
+
+ def read(self):
+ """Return the output value of the pin, values explained in write()"""
+ if self.mode == UNAVAILABLE:
+ raise IOError, "Cannot read pin %i"% self._get_board_pin_number()
+ return self.value
+
+ def write(self, value):
+ """Output a voltage from the pin
+
+ Argument:
+ value, takes a boolean if the pin is in output mode, or a float from 0
+ to 1 if the pin is in PWM mode
+
+ """
+ if self.mode == UNAVAILABLE:
+ raise IOError, "Cannot read from pin %i" \
+ % (self._get_board_pin_number())
+ if self.mode == DIGITAL_INPUT:
+ raise IOError, "Digital pin %i is not an output" \
+ % (self._get_board_pin_number())
+ elif value != self.read():
+ self.value = value
+ if self.mode == DIGITAL_OUTPUT:
+ self.port.write()
+ elif self.mode == DIGITAL_PWM:
+ value = int(round(value * 255))
+ message = chr(ANALOG_MESSAGE + self._get_board_pin_number())
+ message += chr(value % 128)
+ message += chr(value >> 7)
+ self.sp.write(message)
+
+
+class AnalogPin:
+ """Analog pin on the arduino board"""
+
+ def __init__(self, sp, pin_number):
+ self.sp = sp
+ self.pin_number = pin_number
+ self.active = 0
+ self.value = -1
+
+ def __str__(self):
+ return "Analog Input %i"% self.pin_number
+
+ def set_active(self, active):
+ """Set the pin to report values"""
+ self.active = active
+ message = chr(REPORT_ANALOG_PIN + self.pin_number)
+ message += chr(active)
+ self.sp.write(message)
+
+ def get_active(self):
+ """Return whether the pin is reporting values"""
+ return self.active
+
+ def set_value(self, value):
+ """Record the value of the pin"""
+ self.value = value
+
+ def read(self):
+ """Return the input in the range 0-1"""
+ return self.value
+

0 comments on commit cf9a949

Please sign in to comment.