first commit

This commit is contained in:
Tristan Hearn
2012-08-09 20:33:54 -04:00
commit a44ff2e41d
6 changed files with 627 additions and 0 deletions

19
MIT license.txt Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2012-2013 Tristan A. Hearn <tristanhearn@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

84
README.md Normal file
View File

@@ -0,0 +1,84 @@
# Python Arduino Command API
> &copy; 2012-2013 Tristan A. Hearn <tristanhearn@gmail.com>
> under the MIT License
Based on the Python Arduino Prototyping API by Akash Manohar (https://github.com/HashNuke/Python-Arduino-Prototyping-API/).
The Python Arduino Command API is a light-weight Python package for communicating with Arduino microcontroller boards. It is written
using a custom protocol, similair to Firmata (http://firmata.org/wiki/Main_Page). This allows a user to quickly protoype programs
for Arduino or to simply read and control harware connected to an Arduino from a host computer, without having to reload sketches onto an Arduino board.
Method names within the Python Arduino Command API are designed to be as close as possible to their Arduino programming language counterparts.
## Usage example
#!/usr/bin/env python
#Example 'Blink' program
from arduino import Arduino
import time
board = Arduino('9600')
while True:
board.digitalWrite(13, "LOW")
time.sleep(1)
board.digitalWrite(13, "HIGH")
time.sleep(1)
Python-Arduino-Command-API
For more examples, see arduino/examples.py. This file contains methods which replicate
the functionality of many Arduino demo sketches.
#### Requirements:
* Python 2.3 or higher (Python 3.x not yet tested)
* PySerial
* Arduino compatible microcontroller with at least 14KB of memory
#### To-do list:
* Add simple reset functionality that zeros out all pin values
* Add I2C / TWI function support (Arduino Wire.h commands)
* Add Servo support (Arduino Servo.h commands)
* Add tone() / noTone() squarewave generator support for piezo type speakers
* Make a program which generates 'prototype.ino' with selected Arduino function support, to help reduce memory requirements.
* Multi-serial support for Arduino mega (Serial1.read(), etc)
#### Setup:
1. Load the sketch prototype.ino onto your Arduino board.
2. Import the arduino library into your python script.
## Methods
*Arduino(baud)* - Set up communication with currently connected and powered Arduino.
The device name / COM port will be auto-detected. If there are more than one Arduino boards connected,
the desired COM port can be also be passed:
*Arduino(baud, port = "COM3")*
A time-out for reading from the Arduino can also be specified:
*Arduino(baud, timeout = 2)*
**Digital I/O**
* *Arduino.digitalWrite(pin_number, state)* - turn digital pin on/off
* *Arduino.digitalRead(pin_number)* - read state of a digital pin
* *Arduino.pinMode(pin_number, io_mode)* - set pin I/O mode
* *Arduino.pulseIn(pin_number, state)* - measures a pulse
* *Arduino.pulseIn_set(pin_number, state)* - measures a pulse, with preconditioning
**Analog I/O**
* *Arduino.analogRead(pin_number)* - returns the analog value
* *Arduino.analogWrite(pin_number, value)* - sets the analog value
**Software Serial Functionality**
* *Arduino.SoftwareSerial.begin(ss_rxPin,ss_txPin,ss_device_baud)* - initialize software serial device on
specified pins.
Only one sofware serial device can be used at a time. Existing software serial instance will
be be overwritten by calling this method, both in Python and on the arduino board.
* *Arduino.SoftwareSerial.write(data)* - send data using the arduino 'write' function to the existing software serial connection.
* *Arduino.SoftwareSerial.read()* - returns one byte from the existing software serial connection
**Misc**
* *Arduino.close()* - closes serial connection to the Arduino.

5
arduino/__init__.py Normal file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env python
from arduino import Arduino

265
arduino/arduino.py Normal file
View File

@@ -0,0 +1,265 @@
#!/usr/bin/env python
from serial.tools import list_ports
import serial, time
class SoftwareSerial(object):
"""
Class for Arduino software serial functionality
"""
def __init__(self,board):
self.board=board
self.connected = False
def begin(self,p1,p2,baud):
"""
Create software serial instance on
specified tx,rx pins, at specified baud
"""
cmd_str=''.join(["@ss%",str(p1),"%",str(p2),"%",str(baud),"$!"])
self.board.sr.write(cmd_str)
self.board.sr.flush()
response= self.board.sr.readline().replace("\r\n","")
if response == "ss OK":
self.connected = True
return True
else:
self.connected = False
return False
def write(self,data):
"""
sends data to existing software serial instance
using Arduino's 'write' function
"""
if self.connected:
cmd_str=''.join(["@sw%",str(data),"$!"])
self.board.sr.write(cmd_str)
self.board.sr.flush()
response= self.board.sr.readline().replace("\r\n","")
if response == "ss OK":
return True
else:
return False
def read(self):
"""
returns first bit read from
existing software serial instance
"""
if self.connected:
cmd_str=''.join(["@sr%$!"])
self.board.sr.write(cmd_str)
self.board.sr.flush()
response= self.board.sr.readline().replace("\r\n","")
if response:
return response
else:
return False
class Arduino(object):
def __init__(self,baud,port="",timeout=2):
"""
Initializes serial communication with Arduino.
Attempts to self-select COM port, if not specified.
"""
self.baud = baud
self.timeout = timeout
self.ss_connected=False
self.SoftwareSerial = SoftwareSerial(self)
if port == "":
self.findPort()
self.sr = serial.Serial(self.port, self.baud,timeout =self.timeout)
time.sleep(2)
def findPort(self):
"""
Returns first Arduino found
in system's device list
"""
for pt in list_ports.comports():
if ("FTDIBUS" in pt[-1]) or ("usbserial" in pt[-1]):
self.port = pt[0]
return
def digitalWrite(self,pin,val):
"""
Sends digitalWrite command
to digital pin on Arduino
-------------
inputs:
pin : digital pin number
val : either "HIGH" or "LOW"
"""
if val=="LOW":
pin_ = -pin
else:
pin_ = pin
cmd_str=''.join(["@dw%",str(pin_),"$!"])
try:
self.sr.write(cmd_str)
self.sr.flush()
except:
pass
def analogWrite(self,pin,val):
"""
Sends analogWrite pwm command
to pin on Arduino
-------------
inputs:
pin : pin number
val : integer 0 (off) to 255 (always on)
"""
if val>255:
val=255
elif val<0:
val=0
cmd_str=''.join(["@aw%",str(pin),"%",str(val),"$!"])
try:
self.sr.write(cmd_str)
self.sr.flush()
except:
pass
def analogRead(self,pin):
"""
Returns the value of a specified
analog pin.
inputs:
pin : analog pin number for measurement
returns:
value: integer from 1 to 1023
"""
cmd_str=''.join(["@ar%",str(pin),"$!"])
try:
self.sr.write(cmd_str)
self.sr.flush()
except:
pass
rd = self.sr.readline().replace("\r\n","")
try:
return int(rd)
except:
return 0
def pinMode(self,pin,val):
"""
Sets I/O mode of pin
inputs:
pin: pin number to toggle
val: "INPUT" or "OUTPUT"
"""
if val=="INPUT":
pin_ = -pin
else:
pin_ = pin
cmd_str=''.join(["@pm%",str(pin_),"$!"])
try:
self.sr.write(cmd_str)
self.sr.flush()
except:
pass
def pulseIn(self,pin,val):
"""
Reads a pulse from a pin
inputs:
pin: pin number for pulse measurement
returns:
duration : pulse length measurement
"""
if val=="LOW":
pin_ = -pin
else:
pin_ = pin
cmd_str=''.join(["@pi%",str(pin_),"$!"])
try:
self.sr.write(cmd_str)
self.sr.flush()
except:
pass
rd = self.sr.readline().replace("\r\n","")
try:
return float(rd)
except:
return -1
def pulseIn_set(self,pin,val):
"""
Sets a digital pin value, then reads the response
as a pulse width.
Useful for some ultrasonic rangefinders, etc.
inputs:
pin: pin number for pulse measurement
val: "HIGH" or "LOW". Pulse is measured
when this state is detected
returns:
duration : pulse length measurement
This method will automatically toggle
I/O modes on the pin and precondition the
measurment with a clean LOW/HIGH pulse.
Arduino.pulseIn_set(pin,"HIGH") is
equivalent to the Arduino sketch code:
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(2);
digitalWrite(pin, HIGH);
delayMicroseconds(5);
digitalWrite(pin, LOW);
pinMode(pin, INPUT);
long duration = pulseIn(pin, HIGH);
"""
if val=="LOW":
pin_ = -pin
else:
pin_ = pin
cmd_str=''.join(["@ps%",str(pin_),"$!"])
try:
self.sr.write(cmd_str)
self.sr.flush()
except:
pass
rd = self.sr.readline().replace("\r\n","")
try:
return float(rd)
except:
return -1
def close(self):
self.sr.close()
def digitalRead(self,pin):
"""
Returns the value of a specified
digital pin.
inputs:
pin : digital pin number for measurement
returns:
value: 0 for "LOW", 1 for "HIGH"
"""
cmd_str=''.join(["@dr%",str(pin),"$!"])
try:
self.sr.write(cmd_str)
self.sr.flush()
except:
pass
rd = self.sr.readline().replace("\r\n","")
try:
return 1 - int(rd)
except:
return 0
if __name__=="__main__":
board=Arduino(9600)
while True:
time.sleep(0.01)
val=board.analogRead(5)/4
board.analogWrite(11,val)

76
arduino/examples.py Normal file
View File

@@ -0,0 +1,76 @@
#!/usr/bin/env python
from arduino import Arduino
import time
def Blink(led_pin,baud):
"""
Blinks an LED in 1 sec intervals
"""
board = Arduino(baud)
while True:
board.digitalWrite(led_pin,"LOW")
print board.digitalRead(led_pin) #confirm LOW (0)
time.sleep(1)
board.digitalWrite(led_pin,"HIGH")
print board.digitalRead(led_pin) #confirm HIGH (1)
time.sleep(1)
def softBlink(led_pin,baud):
"""
Fades an LED off and on, using
Arduino's analogWrite (PWM) function
"""
board=Arduino(baud)
i=0
while True:
i+=1
k=i%510
if k%5==0:
if k>255:
k=510-k
board.analogWrite(led_pin,k)
def adjustBrightness(pot_pin,led_pin,baud):
"""
Adjusts brightness of an LED using a
potentiometer
"""
board=Arduino(baud)
while True:
time.sleep(0.01)
val=board.analogRead(pot_pin)/4
print val
board.analogWrite(led_pin,val)
def PingSonar(pw_pin,baud):
"""
Gets distance measurement from Ping)))
ultrasonic rangefinder connected to pw_pin
"""
board = Arduino(baud)
pingPin=pw_pin
while True:
duration = board.pulseIn(pingPin, "HIGH")
inches = duration/72./2.
cent = duration/29./2.
print inches,"inches"
time.sleep(0.1)
def LCD(tx,baud,ssbaud,message):
"""
Prints to two-line LCD connected to
pin tx
"""
board = Arduino(baud)
board.SoftwareSerial.begin(0,tx,ssbaud)
while True:
board.SoftwareSerial.write(" test ")
if __name__=="__main__":
#LCD(5,9600,9600," test ")
adjustBrightness(5,11,9600)
#softBlink(11,9600)

178
prototype/prototype.ino Normal file
View File

@@ -0,0 +1,178 @@
#include <SoftwareSerial.h>
#include <Wire.h>
#include <Servo.h>
SoftwareSerial *sserial = NULL;
boolean connected = false;
int Str2int (String Str_value)
{
char buffer[10]; //max length is three units
Str_value.toCharArray(buffer, 10);
int int_value = atoi(buffer);
return int_value;
}
void split(String results[], int len, String input, char spChar) {
String temp = input;
for (int i=0; i<len; i++) {
int idx = temp.indexOf(spChar);
results[i] = temp.substring(0,idx);
temp = temp.substring(idx+1);
}
}
void DigitalHandler(int mode, String data){
int pin = Str2int(data);
if(mode<=0){ //read
Serial.println(digitalRead(pin));
}else{
if(pin <0){
digitalWrite(-pin,LOW);
}else{
digitalWrite(pin,HIGH);
}
//Serial.println('0');
}
}
void AnalogHandler(int mode, String data){
if(mode<=0){ //read
int pin = Str2int(data);
Serial.println(analogRead(pin));
}else{
String sdata[2];
split(sdata,2,data,'%');
int pin = Str2int(sdata[0]);
int pv = Str2int(sdata[1]);
analogWrite(pin,pv);
}
}
void ConfigurePinHandler(String data){
int pin = Str2int(data);
if(pin <=0){
pinMode(-pin,INPUT);
}else{
pinMode(pin,OUTPUT);
}
}
void SS_set(String data){
delete sserial;
String sdata[3];
split(sdata,3,data,'%');
int rx_ = Str2int(sdata[0]);
int tx_ = Str2int(sdata[1]);
int baud_ = Str2int(sdata[2]);
sserial = new SoftwareSerial(rx_, tx_);
sserial->begin(baud_);
Serial.println("ss OK");
}
void SS_write(String data) {
int len = data.length()+1;
char buffer[len];
data.toCharArray(buffer,len);
Serial.println("ss OK");
sserial->write(buffer);
}
void SS_read(String data) {
char c = sserial->read();
Serial.println(c);
}
void pulseInHandler(String data){
int pin = Str2int(data);
long duration;
if(pin <=0){
pinMode(-pin, INPUT);
duration = pulseIn(-pin, LOW);
}else{
pinMode(pin, INPUT);
duration = pulseIn(pin, HIGH);
}
Serial.println(duration);
}
void pulseInSHandler(String data){
int pin = Str2int(data);
long duration;
if(pin <=0){
pinMode(-pin, OUTPUT);
digitalWrite(-pin, HIGH);
delayMicroseconds(2);
digitalWrite(-pin, LOW);
delayMicroseconds(5);
digitalWrite(-pin, HIGH);
pinMode(-pin, INPUT);
duration = pulseIn(-pin, LOW);
}else{
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(2);
digitalWrite(pin, HIGH);
delayMicroseconds(5);
digitalWrite(pin, LOW);
pinMode(pin, INPUT);
duration = pulseIn(pin, HIGH);
}
Serial.println(duration);
}
void SerialParser(void) {
char readChar[64];
Serial.readBytesUntil(33,readChar,64);
String read_ = String(readChar);
//Serial.println(readChar);
int idx1 = read_.indexOf('%');
int idx2 = read_.indexOf('$');
// separate command from associated data
String cmd = read_.substring(1,idx1);
String data = read_.substring(idx1+1,idx2);
// determine command sent
if (cmd == "dw") {
DigitalHandler(1, data);
}
else if (cmd == "dr") {
DigitalHandler(0, data);
}
else if (cmd == "aw") {
AnalogHandler(1, data);
}
else if (cmd == "ar") {
AnalogHandler(0, data);
}
else if (cmd == "pm") {
ConfigurePinHandler(data);
}
else if (cmd == "ps") {
pulseInSHandler(data);
}
else if (cmd == "pi") {
pulseInHandler(data);
}
else if (cmd == "ss") {
SS_set(data);
}
else if (cmd == "sw") {
SS_write(data);
}
else if (cmd == "sr") {
SS_read(data);
}
}
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
}
void loop() {
SerialParser();
}