...
Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Step A Sketch code


Arduino Listing:

// pins for motor 1
const byte M1_A = 8;
const byte M1_B = 7;
const byte M1_C = 6;
const byte M1_D = 5;
// pins for motor 2
const byte M2_A = 4;
const byte M2_B = 3;
const byte M2_C = 2;
const byte M2_D = A1; // (note: analog pin used as digital)
// pins for input. (note: analog pins used as digital)
const byte I_LEFT  = A2;
const byte I_UP    = A3;
const byte I_DOWN  = A4;
const byte I_RIGHT = A5;
// pin sequence for stepping motor1 and motor2
const byte M1PINS[] = {M1_A,M1_B,M1_C,M1_D};
const byte M2PINS[] = {M2_A,M2_B,M2_C,M2_D};

// each step needs to be a pulse a few ms wide, or motor doesn't step.
byte stepDwell = 10;
// pause a few ms between repeating input triggers
byte iPause = 20;
// track the current pin index in the step sequence
byte m1Pin = 0;
byte m2Pin = 0;
// holds the command code, sent over serial
char commandValue = '\0';
// holds the data, sent over serial
int dataValue = 0;

//
void setup() {
    Serial.begin(9600);
    // setup pins for output
    pinMode(M1_A, OUTPUT);
    pinMode(M1_B, OUTPUT);
    pinMode(M1_C, OUTPUT);
    pinMode(M1_D, OUTPUT);
    pinMode(M2_A, OUTPUT);
    pinMode(M2_B, OUTPUT);
    pinMode(M2_C, OUTPUT);
    pinMode(M2_D, OUTPUT);
    // setup pins for input
    pinMode(I_LEFT,  INPUT);
    pinMode(I_UP,    INPUT);
    pinMode(I_DOWN,  INPUT);
    pinMode(I_RIGHT, INPUT);
}

//
void loop() {
    // priority is for commands coming over serial
    if (Serial.available()) {
        char incomingChar = Serial.read();
        if ('\n' == incomingChar) { // eol recvd, so process command and value collected so far
            processCommand(commandValue, dataValue);
            Serial.print("(");Serial.print(commandValue);Serial.print(dataValue);
            Serial.println(") ok >");// reply back to calling device
            commandValue = '\0'; // reset
            dataValue = 0; // reset
        } else if (isDigit(incomingChar)) {
            dataValue = (dataValue * 10) + (incomingChar - '0'); // accumulate the data value
        } else { // non-digit, so consider as a command code
            commandValue = incomingChar; // set the current command
        }

    } else { // if no serial commands to be processed, check for direct inputs and button presses
        if (digitalRead(I_LEFT) == HIGH)
            step(I_LEFT);
        if (digitalRead(I_UP) == HIGH)
            step(I_UP);        
        if (digitalRead(I_DOWN) == HIGH)
            step(I_DOWN);
        if (digitalRead(I_RIGHT) == HIGH)
            step(I_RIGHT);   
    }
}

/* -------------- support routines -------------- */

// returns true if 'digit' represents an ascii digit between 0 and 9
boolean isDigit (char digit) {
    return (digit >= '0' && digit <= '9');
}

//
void processCommand(char commandValue, int dataValue) {
    
    if ('i' == commandValue) {// set iPause
        iPause = dataValue;
        return;
    } else if ('s' == commandValue) {// set stepDwell
        stepDwell = dataValue;
        return;
    }
    
    // if "move" command, process it
    byte direction = 255;
    if ('L' == commandValue)
        direction = I_LEFT;
    else if ('U' == commandValue)
        direction = I_UP;
    else if ('D' == commandValue)
        direction = I_DOWN;
    else if ('R' == commandValue)   
        direction = I_RIGHT; 
    if (255 != direction) {
        for (int i = 0; i < dataValue; i++)
            step(direction);
         return;   
    }
    
}

//
void step(byte direction) {
    switch (direction) {
        case I_LEFT:
            m1Pin = cShift(-1,m1Pin);
            pulse(M1PINS[m1Pin]);
            break;
        case I_UP:
            m2Pin = cShift(1,m2Pin);
            pulse(M2PINS[m2Pin]);
            break;            
        case I_DOWN:
            m2Pin = cShift(-1,m2Pin);
            pulse(M2PINS[m2Pin]);
            break;
        case I_RIGHT:
            m1Pin = cShift(1,m1Pin);
            pulse(M1PINS[m1Pin]);
            break;
        default:
            // invalid value, ignore
            break;
    }
}

//
void pulse(byte pinToPulse) {
    digitalWrite(pinToPulse,HIGH);
    delay(stepDwell);
    digitalWrite(pinToPulse,LOW);    
    delay(iPause);
}

/*
   performs a circular shift of the index indexToShift, by shiftDirection.
   operation is done on a 4-bit word. returns the index shifted to.
   cShift(1,0) -> 1 (1000 -> 0100), cShift(1,1) -> 2 (0100 -> 0010)
   cShift(1,2) -> 3 (0010 -> 0001), cShift(1,3) -> 0 (0001 -> 1000)
   cShift(-1,0) -> 3 (1000 -> 0001), cShift(-1,1) -> 0 (0100 -> 1000)
   cShift(-1,2) -> 1 (0010 -> 0100), cShift(-1,3) -> 2 (0001 -> 0010)
*/
byte cShift(char shiftDirection, byte indexToShift) {
    char shiftedIndex = shiftDirection + indexToShift;
    if (shiftedIndex > 3)
        shiftedIndex = 0;
    else if (shiftedIndex < 0)
        shiftedIndex = 3;
    return shiftedIndex;
}

Web UI for the StepASketch:



<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="Content-Style-Type" content="text/css">
    <title>Step a Sketch Controller</title>
    <link rel="icon" href="favicon.ico" type="image/x-icon" />
    <script type="text/javascript">
    /* ----------------- base utils -----------------*/
    function $() { return document.getElementById(arguments[0]); }
    function $F() { return document.getElementById(arguments[0]).value; }
    function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; }     
    function syncAjax(url,data) {
      var ajax = new XMLHttpRequest(); 
      try {
          ajax.open("POST", url, false);
          ajax.setRequestHeader("Content-type", "text/plain");
          ajax.send(data);
      } catch (e) {console.log('exception:' + e);}
      return ajax.responseText;                
    }
    /* ----------------- base utils -----------------*/
          
          
    // basic drawing related ..................................................    
    var CANVAS;
    var CTX;

    function init() {
        CANVAS = document.getElementById('plot');
        CTX = CANVAS.getContext('2d');    
        clearCanvas();
    }
    
    function clearCanvas() {
        CTX.clearRect(0, 0, CANVAS.width, CANVAS.height);
        CTX.strokeStyle = "#000000";
        CTX.strokeRect(0, 0, 800, 500);     
    }



    // manual line drawing related ..................................................
    var P1 = null;
    var P2 = null;    
    function getCoordinates(e) {
        var x = e.clientX;
        var y = e.clientY;
        $("xycoordinates").innerHTML = "(" + x + "," + y + ")";
    }
    function clearCoordinates() {
        $("xycoordinates").innerHTML = "";
    }
    function canvasClicked(e) {
        var markerSize = 6;
        var x = e.clientX;
        var y = e.clientY;   
        baseDrawLine(x,y-markerSize,x,y+markerSize);     
        baseDrawLine(x-markerSize,y,x+markerSize,y); 
        if (null == P1) {
            P1 = {};
            P1.x = x;
            P1.y = y;
        } else {
            P2 = {};
            P2.x = x;
            P2.y = y;
        }
    }
    function manualLine() {
        drawLine (P1.x, P1.y, P2.x, P2.y);
    }






    // machine drawing related ..................................................
    /*      
            q    determinant      m  dx  dy
            -------------------------------
            a  x1 > x2, y1 > y2,  +  -   -
            b  x1 < x2, y1 > y2,  -  +   -
            c  x1 < x2, y1 < y2,  +  +   +
            d  x1 > x2, y1 < y2,  -  -   +        
    */     

    /*
        drawing primitive function from the underlying system.
    */
    function baseDrawLine(fromX, fromY, toX, toY) {
        //console.log('from:' + fromX + ',' + fromY + ' to:' + toX + ',' + toY);
        CTX.lineWidth = 1;
        CTX.strokeStyle = "#000000";
        CTX.beginPath();
        CTX.moveTo(fromX, fromY);
        CTX.lineTo(toX, toY);
        CTX.stroke();
    }


    // suports simulating the stepper motor drive
    function stepDrawLine(fromX, fromY, toX, toY) {
        
        var relX = toX - fromX;
        var relY = toY - fromY;
        
        if (relX < 0)
            stepRender('L', Math.abs(relX), fromX, fromY);
        else
            stepRender('R', Math.abs(relX), fromX, fromY);
            
        if (relY < 0)
            stepRender('U', Math.abs(relY), fromX, fromY);
        else
            stepRender('D', Math.abs(relY), fromX, fromY);        
    }
    
    // simulates the stepper motor drive on the device
    function stepRender(direction, steps, startingX, startingY) {

        switch (direction) {
            case 'L':
                baseDrawLine(startingX, startingY, startingX-steps, startingY);
                break;
            case 'R':
                baseDrawLine(startingX, startingY, startingX+steps, startingY);
                break;
            case 'U':
                baseDrawLine(startingX, startingY, startingX, startingY-steps);
                break;
            case 'D':
                baseDrawLine(startingX, startingY, startingX, startingY+steps);
                break;
            default:
                break;
        }   
        
        if (! $('simulate_switch').checked)
            toDevice(direction, steps);
    }

    /*
        calculates the interpolated points for straight line
    */
    function drawLine(fromX, fromY, toX, toY) {
        console.log('from:' + fromX + ',' + fromY + ' to:' + toX + ',' + toY);
        if (fromX == toX || fromY == toY) {
            console.log('X\'s or Y\'s equal');
            //baseDrawLine(fromX, fromY, toX, toY);
            stepDrawLine(fromX, fromY, toX, toY);
            return;
        }
        
        var P_next = {};
        var P_current = {};
        P_current.x = fromX;
        P_current.y = fromY;
        
        var slope_m = Math.abs((toY - fromY) / (toX - fromX));    
        var slope_type = (fromX > toX) ? ((fromY > toY) ? 'A' : 'D') : ((fromY > toY) ? 'B' : 'C');
        var is_slope_upward = slope_m > 1;
        console.log('slope_m = ' + slope_m + ' is_slope_upward = ' + is_slope_upward + ' slope_type = ' + slope_type);
        var step_range = (is_slope_upward) ? Math.abs(fromY - toY) : Math.abs(fromX - toX);
        console.log('step_range ' + step_range);
        
        for (var step = 1; step < step_range; step++) {
            var relX = (is_slope_upward) ? Math.round(step / slope_m) : step;
            var relY = (is_slope_upward) ? step : Math.round(step * slope_m);
            switch (slope_type) {
                case 'A':
                    relX = -relX;
                    relY = -relY;
                    break;
                case 'B':
                    relY = -relY;
                    break;
                case 'D':
                    relX = -relX;
                    break;
                default:
                    break;
            }
            P_next.x = fromX + relX;
            P_next.y = fromY + relY;            
            //console.log('rel ' + relX + ' ' + relY + ' Pc:' + P_current.x + ',' + P_current.y + ' Pn:' + P_next.x + ',' + P_next.y);
            //baseDrawLine(P_current.x, P_current.y, P_next.x, P_next.y);
            stepDrawLine(P_current.x, P_current.y, P_next.x, P_next.y);
            P_current.x = P_next.x;
            P_current.y = P_next.y;
        }
    }        
    






    function processInput() {

        var lines = $F('textarea1').split('\n');
        var prevX = -1;
        var prevY = -1;
        for (var i = 0; i < lines.length; i++) {
            var currX = -1;
            var currY = -1;
            var line = lines[i];
            if (line.indexOf('G00') == 0 || line.indexOf('G01') == 0) {
                var parts = line.split(' ');
                if (parts.length > 2) {
                    if (parts[1].indexOf('X') == 0) 
                        currX = parseInt(parts[1].substring(1)); // cast to wholenumber
                    if (parts[2].indexOf('Y') == 0) 
                        currY = parseInt(parts[2].substring(1)); // cast to wholenumber
                    if (currX > -1 && currY > -1) {
                        console.log('x,y:' + currX + ',' + currY);
                        console.log(prevX + ',' + prevY);
                        if (prevX != -1 && prevY != -1) {
                            //baseDrawLine(prevX, prevY, currX, currY);
                            drawLine(prevX, prevY, currX, currY);
                        }
                        prevX = currX;
                        prevY = currY;
                    }
                }
            }
        }
    }


    // device communication related .................................................
    
    function deviceCommand(ref) {
        var command = ref.id.substring(0,1);
        var value = $F(command + '_value');
        $('comm_log').innerHTML = command + value + '<br />';
        var response = toDevice(command, value);
        $('comm_log').innerHTML += response;
    }
    
    function toDevice(command, value) {
        return response = syncAjax('/', command + value);
    }
    
    

    function test() {

    }
          
    </script>
    <style media="screen" type="text/css">
        body,table, button {font-family:verdana,helvetica,arial,sans-serif;margin:0px;font-size:10px;}
        button {cursor:pointer;}
        input {border: solid 1px gray;}
        input.d_input {width:24px;}

    </style>
</head>
<body onload="init()">
    <table width="100%" cellpadding="0" cellspacing="0">
    <tr>
        <td valign="top" width="800">
    <canvas id="plot" width="800" height="500" style="background-color:#DCDCDC;" onmousemove="getCoordinates(event)" onmouseout="clearCoordinates()" onclick="canvasClicked(event)">
    <p>browser doesn't support canvas.</p>
    </canvas>    
    <table width="100%">
      <tr>
        <td>
          <button onclick="clearCanvas();P1=P2=null;">clear canvas</button>         
          <button onclick="manualLine()" title="draw line between 2 points picked on canvas">line</button>
        </td>
        <td align="right"><span id="xycoordinates"></span></td>      
      </tr>
    </table>
        </td>
        <td valign="top">
    G-code to be processed:<br />        
    <textarea id="textarea1" rows="30" cols="40">

    </textarea>
    <br />
    <button onclick="processInput()">process</button> <input type="checkbox" id="simulate_switch" checked="checked" /> simulate
        </td>
    </tr>    
    </table>    
    
    <hr />
    
    <table>
      <tr>
        <td valign="top">
             <table style="padding:5px;">
              <tr><td colspan="2">serial port
                                 <button id="o_command" onClick="deviceCommand(this)">open</button><input type="hidden" id="o_value" value="" />
                                 <button id="c_command" onClick="deviceCommand(this)">close</button><input type="hidden" id="c_value" value="" />
                  <hr /></td></tr>
              <tr><td><input type="text" class="d_input" id="i_value" maxlength="3" /></td><td><button id="i_command" onclick="deviceCommand(this)">set pause</button></td></tr>
              <tr><td><input type="text" class="d_input" id="s_value" maxlength="3" /></td><td><button id="s_command" onclick="deviceCommand(this)">set dwell</button></td></tr>
              <tr><td colspan="2"><hr /><div id="comm_log" /></td></tr>
             </table>       
        </td>
        <td>
            <table style="border:1px solid gray;padding:5px;">
                <tr align="middle"><td colspan="2"></td><td><input type="text" class="d_input" id="U_value" maxlength="3" /></td><td colspan="2"></td></tr>
                <tr align="middle"><td colspan="2"></td><td><button id="U_command" onclick="deviceCommand(this)">U</button></td><td colspan="2"></td></tr>
                <tr align="middle"><td><input type="text" class="d_input" id="L_value" maxlength="3" /></td>
                                   <td><button id="L_command" onclick="deviceCommand(this)">L</button></td>
                                   <td></td><td><button id="R_command" onclick="deviceCommand(this)">R</button></td>
                                   <td><input type="text" class="d_input" id="R_value" maxlength="3" /></td></tr>
                <tr align="middle"><td colspan="2"></td><td><button id="D_command" onclick="deviceCommand(this)">D</button></td><td colspan="2"></td></tr>
                <tr align="middle"><td colspan="2"></td><td><input type="text" class="d_input" id="D_value" maxlength="3" /></td><td colspan="2"></td></tr>
            </table>        
        </td>
      </tr>
    </table>
    

    
    

    
    
</body>
</html>        




Python web server and serial port connector:


#!/usr/bin/python

import BaseHTTPServer
import SimpleHTTPServer
import serial

HTTP_PORT = 56789
SERIAL_PORT = '/dev/ttyUSB0'

SERIAL_REF = None

def execute_command(commandData):
    global SERIAL_REF
    if 'o' == commandData:
        SERIAL_REF = serial.Serial(SERIAL_PORT, baudrate=9600, timeout=None)
        return 'ok - opened'
    elif 'c' == commandData:
        SERIAL_REF.close()
        return 'ok - closed'
    else:
        SERIAL_REF.write(commandData + '\n')
        response = SERIAL_REF.readline()
        return response

class SimpleHTTPHandlerImpl(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_GET(self):
        try:
            #serve files, and directory listings by following self.path from current working directory
            SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
        except:
            result = '<html><body>error...</body></html>'
            self.wfile.write(result)
    def do_POST(self):
        """Handle a post request"""
        length = int(self.headers.getheader('content-length'))        
        data_string = self.rfile.read(length)
        result = execute_command(data_string)
        self.wfile.write(result)
            
            
def main():
    server = BaseHTTPServer.HTTPServer(("localhost", HTTP_PORT), SimpleHTTPHandlerImpl)
    try:
        print "serving at port", HTTP_PORT
        server.serve_forever()
    except KeyboardInterrupt:
        print 'shutting down...'
        server.socket.close()
        
if __name__ == '__main__':
    main()        

    

    


Serial Bluetooth RF Transceiver Module


Module from goodluck buy:

http://www.goodluckbuy.com/serial-bluetooth-rf-transceiver-module-rs232.html

This small size Bluetooth TTL transceiver module allows your target device to both send or receive the TTL data via Bluetooth technology without connecting a serial cable to your computer. It's easy to use and completely encapsulated.

TTL data transparent transfer between a host Bluetooth device.
Works with any USB Bluetooth adapters.
Default Baud Rate: 9600,8,1,n.
Coverage up to 30ft.
Built in antenna.
Power input: +3.3VDC.
Mini Size.

The UART interface is TTL Compatible because.
The Module can be configured with AT Commands.

You only be able to change the PIN with the AT Commands.
The module can only act as a slave, so you cant connect modules together.
If you need a Master functionalitiy, you can flash other Firmware on to the module.
The firmware can be found later on my website http://www.endasmedia.ch

I soldered leads to the Tx, Rx, 3.3V and GND pads. Was not careful, and tore out the whole Rx pad :{. On powering it up, was able to find it from the laptop (showed up as "livnor", and needed to use pin "1234").

Using python to search for it, first installed pybluez (from synaptic). From the following code, was able to determine it's id. After that, wasn't able to get any further, with actually doing serial over bluetooth. This site has some nice examples of python, check it out:
http://homepages.ius.edu/rwisman/C490/html/PythonandBluetooth.htm

from bluetooth import *

print "performing inquiry..."

nearby_devices = discover_devices(lookup_names = True)

print "found %d devices" % len(nearby_devices)

for name, addr in nearby_devices:
     print " %s - %s" % (addr, name)  


performing inquiry...
found 1 devices
 linvor - 00:12:01:11:03:53


JY-MCU Bluetooth Module:

See this instructable to hookup Arduino, Android phone, SL4A python and this bluetooth module.

Got this from DealExtreme.

Code sample to use this with python and an arduino:

//ran this program on the arduino

void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);  
  digitalWrite(13, LOW);
}
void loop() {
  if (Serial.available() > 0) {  
    char incoming = Serial.read();
    if (incoming == 'a')
      digitalWrite(13, HIGH);
    if (incoming == 'b')
      digitalWrite(13, LOW);      
  }
}

connected the blutooth device to the arduino

Vcc -> 5V
Gnd -> Gnd
Rx  -> Tx
Tx  -> Rx

On applying power, a red led keeps blinking (blinking for discoverable, solid after it paired.
ran this program on the laptop

#!/usr/bin/python
from bluetooth import *
print "performing inquiry..."
nearby_devices = discover_devices(lookup_names = True)
print "found %d devices" % len(nearby_devices)
for name, addr in nearby_devices:
     print " %s - %s" % (addr, name)

it printed out

performing inquiry...
found 1 devices
 linvor - 00:12:05:11:90:32

then ran this program, to test out connectivity

#!/usr/bin/python
from bluetooth import *
server_address = "00:12:05:11:90:32"
port = 1
print "connecting to \"%s\" on %s" % (server_address, port)
sock = BluetoothSocket( RFCOMM )
sock.connect((server_address, port))
print "connected.  ready for input..."
while True:
    data = raw_input() # read stdin, stripping the trailing newline
    sock.send(data)
    if data == 'x':
        break
sock.close()

The first time, linux popped up a dialog asking for pin to pair, entered 1234. On Linux, pair with the device on your computer, then use the arduino serial monitor to interact.