The Code

A lot of the code is just taking example code from the AF_Motor library as well as the Firefly Firmata and making slight changes to them. The calibration uses both Processing and Arduino but the tattoo drawing just uses Arduino thanks to the Firefly plugin to Grasshopper. Below the code is also two low res images of the grasshopper files.

Calibration Processing:

import hypermedia.net.*;
import processing.serial.*;

/**
* init
*/
UDP udpr; // define the UDP object
Serial myPort;
int a = 200;
String message;
int mx=0;
int my=0;
int premy = 0;

/**
* init
*/
void setup() {

// create a new datagram connection on port 6000
// and wait for incomming message
udpr = new UDP( this, 8000);
//udp.log( true ); // <– printout the connection activity
udpr.listen( true );

myPort = new Serial(this, Serial.list()[0], 9600);
myPort.buffer(2);
size(400, 400);
}

void draw() {

String[] coo = split(message, ‘,’);
//print(coo.length);
if (coo != null)
{
mx = int(coo[0]);
my = int(coo[1]);
}
if (mx > 10) {
myPort.write(mx);
println(mx);
}
if (my != premy) {
myPort.write(my);
// println(my);
}
println(my);
premy = my;
}

void receive( byte[] data, String ip, int port ) { // <– extended handler

// get the “real” message =
// forget the “;\n” at the end <– !!! only for a communication with Pd !!!
data = subset(data, 0, data.length);
message = new String( data );

}

Calibration Arduino:

#include <AFMotor.h>
#include <Servo.h>

Servo myservo; // pen servo
Servo myservo2; // torque servo
AF_Stepper stepper(200, 2); // number of steps per full rotation, PIN
AF_Stepper stepper1(200, 1); // number of steps per full rotation, PIN

int potpin = 0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin

void setup()
{
myservo.attach(10); // attaches the servo on pin 9 to the servo object
myservo2.attach(9);
Serial.begin(9600);
stepper.setSpeed(20); // Stepper 20 rpm
stepper1.setSpeed(50); // Stepper 20 rpm
}

void loop()
{
int input = Serial.read(); // read serial
if (input > 10 && input < 180) {
myservo.write(input); // sets the servo position according to the scaled value
delay(5); // waits for the servo to get there
Serial.println(input);
}

switch (input){
case 1: //If processing passes a ‘1’ do case one
if(input == 1){
myservo.write(0);
delay(5);
myservo2.write(100);
stepper1.step(104, FORWARD, DOUBLE);
delay(700);
myservo2.write(110);
stepper1.step(104, FORWARD, DOUBLE);
delay(700);
myservo2.write(120);
stepper1.step(104, FORWARD, DOUBLE);
delay(700);
myservo2.write(130);
stepper1.step(104, FORWARD, DOUBLE);
delay(700);
myservo2.write(140);
stepper1.step(104, FORWARD, DOUBLE);
delay(700);
myservo2.write(150);
stepper1.step(108, FORWARD, DOUBLE);
delay(700);
myservo2.write(160);
stepper1.step(108, FORWARD, DOUBLE);
delay(700);
myservo2.write(170);
stepper1.step(108, FORWARD, DOUBLE);
delay(700);
myservo2.write(174);
stepper1.step(30, FORWARD, DOUBLE);
stepper.step(1767, FORWARD, DOUBLE);
}
break;

case 2: //If processing passes a ‘1’ do case one
if(input == 2){
myservo.write(0);
delay(5);
myservo2.write(174);
stepper1.step(33, BACKWARD, DOUBLE);
delay(700);
myservo2.write(171);
stepper1.step(104, BACKWARD, DOUBLE);
delay(700);
myservo2.write(161);
stepper1.step(104, BACKWARD, DOUBLE);
delay(700);
myservo2.write(151);
stepper.step(1767, FORWARD, DOUBLE);
}
break;
case 3: //If processing passes a ‘1’ do case one
if(input == 3){
myservo.write(0);
delay(5);
myservo2.write(151);
stepper1.step(33, BACKWARD, DOUBLE);
delay(700);
myservo2.write(148);
stepper1.step(108, BACKWARD, DOUBLE);
delay(700);
myservo2.write(138);
stepper1.step(100, BACKWARD, DOUBLE);
delay(700);
myservo2.write(128);
stepper.step(1767, FORWARD, DOUBLE);
}
break;
case 4: //If processing passes a ‘1’ do case one
if(input == 4){
myservo.write(0);
delay(5);
myservo2.write(128);
stepper1.step(33, BACKWARD, DOUBLE);
delay(700);
myservo2.write(125);
stepper1.step(108, BACKWARD, DOUBLE);
delay(700);
myservo2.write(115);
stepper1.step(108, BACKWARD, DOUBLE);
delay(700);
myservo2.write(105);
stepper.step(1767, FORWARD, DOUBLE);
}
case 5: //If processing passes a ‘1’ do case one
if(input == 5){
myservo.write(0);
delay(5);
myservo2.write(105);
stepper1.step(119, BACKWARD, DOUBLE);
delay(700);
myservo2.write(94);
stepper1.step(108, BACKWARD, DOUBLE);
delay(700);
myservo2.write(84);
stepper.step(1767, FORWARD, DOUBLE);
}
break;
case 6: //If processing passes a ‘1’ do case one
if(input == 6){
myservo.write(0);
delay(5);
myservo2.write(84);
stepper1.step(33, BACKWARD, DOUBLE);
delay(700);
myservo2.write(81);
stepper1.step(108, BACKWARD, DOUBLE);
delay(700);
myservo2.write(71);
stepper1.step(108, BACKWARD, DOUBLE);
delay(700);
myservo2.write(61);
stepper.step(1767, FORWARD, DOUBLE);
}
break;
case 7: //If processing passes a ‘1’ do case one
if(input == 7){
myservo.write(0);
delay(5);
myservo2.write(61);
stepper1.step(33, BACKWARD, DOUBLE);
delay(700);
myservo2.write(58);
stepper1.step(100, BACKWARD, DOUBLE);
delay(700);
myservo2.write(48);
stepper1.step(100, BACKWARD, DOUBLE);
delay(700);
myservo2.write(38);
stepper.step(1767, FORWARD, DOUBLE);
}
break;
case 8: //If processing passes a ‘1’ do case one
if(input == 8){
myservo.write(0);
delay(5);
stepper.step(93, BACKWARD, DOUBLE);
}
break;
case 9: //If processing passes a ‘1’ do case one
if(input == 9){
myservo.write(0);
delay(5);
stepper.step(93, BACKWARD, DOUBLE);
}
break;

}
}

Drawing Arduino:

#include <Servo.h>
#include <AFMotor.h>
#include <pins_arduino.h>
#include <AccelStepper.h>
#define BAUDRATE 115200 //Set the Baud Rate to an appropriate speed
#define BUFFSIZE 256 // buffer one command at a time, 12 bytes is longer than the max length
#define DIR_PIN_A 2 //Set Direction Pin for Stepper A to Digital Pin 2
#define STEP_PIN_A 3 //Set Step Pin for Stepper A to Digital Pin 3
#define DIR_PIN_B 4 //Set Direction Pin for Stepper B to Digital Pin 4
#define STEP_PIN_B 5 //Set Step Pin for Stepper B to Digital Pin 5
#define DIR_PIN_C 6 //Set Direction Pin for Stepper C to Digital Pin 6
#define STEP_PIN_C 7 //Set Step Pin for Stepper C to Digital Pin 7
#define DIR_PIN_D 8 //Set Direction Pin for Stepper D to Digital Pin 8
#define STEP_PIN_D 12 //Set Step Pin for Stepper D to Digital Pin 9

long motorPos[4] = {
0,0,0,0};
int motorSpeed = 100; //Set default speed value
int motorAcc = 20; //Set default acceleration value
int motorRun = 0;
int motorReset = 1;

int prev1 = 0;
char *parseptr;
char buffidx;
AF_Stepper motor1(200, 2);
AF_Stepper motor2(200, 1);

char buffer[BUFFSIZE]; // this is the double buffer
uint16_t bufferidx = 0; // a type of unsigned integer of length 8,16, or 32 bits
uint16_t p1, s1;

Servo servo1; // both end servos
Servo servo2; // pen servo

void forwardstep1() {
motor1.onestep(FORWARD, DOUBLE);
}
void backwardstep1() {
motor1.onestep(BACKWARD, DOUBLE);
}
void forwardstep2() {
motor2.onestep(FORWARD, DOUBLE);
}
void backwardstep2() {
motor2.onestep(BACKWARD, DOUBLE);
}
// Define some steppers and the pins they will use: Ex: Accelstepper stepper1(1, 3, 4) <- STEP PIN 3, DIR PIN 4.
AccelStepper stepper1(forwardstep1, backwardstep1);
AccelStepper stepper2(forwardstep2, backwardstep2);
AccelStepper stepper3(1, STEP_PIN_C, DIR_PIN_C);
AccelStepper stepper4(1, STEP_PIN_D, DIR_PIN_D);

int ser1 = 90;
int ser2 = 90;

/*==============================================================================
* SETUP() This code runs once
*============================================================================*/

void setup()
{
stepper1.setCurrentPosition(0); //Move steppers to default position
stepper2.setCurrentPosition(0);
//stepper3.setCurrentPosition(0);
//stepper4.setCurrentPosition(0);
setStepperSpeeds();

Serial.begin(BAUDRATE); // Start serial communication
servo1.attach(9); // turn on servo
servo2.attach(10);
}

/*==============================================================================
* LOOP() This code loops continuously
*============================================================================*/

void loop()
{

UpdateStepperValues(); //Get all the incoming values from Firefly

if (motorReset == 1) {
stepper1.setCurrentPosition(motorPos[0]);
stepper2.setCurrentPosition(motorPos[1]);
//stepper3.setCurrentPosition(motorPos[2]);
//stepper4.setCurrentPosition(motorPos[3]);
}

stepper1.moveTo(motorPos[0]);
stepper2.moveTo(motorPos[1]);
//stepper3.moveTo(motorPos[2]);
//stepper4.moveTo(motorPos[3]);

if (motorRun == 1) {
stepper1.run();
stepper2.run();
//stepper3.run();
//stepper4.run();
}
}

/*==============================================================================
* UPDATE STEPPER VALUES FUNCTION()
*============================================================================*/

void UpdateStepperValues(){

char c; // holds one character from the serial port
if (Serial.available()) {
c = Serial.read(); // read one character
buffer[bufferidx] = c; // add to buffer

if (c == ‘\n’) {
buffer[bufferidx+1] = 0; // terminate it
parseptr = buffer; // offload the buffer into temp variable

//********************************************************

motorPos[0] = parsedecimal(parseptr); // parse the first number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

motorPos[1] = parsedecimal(parseptr); // parse the next number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

motorPos[2] = parsedecimal(parseptr); // parse the next number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

motorPos[3] = parsedecimal(parseptr); // parse the next number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

motorSpeed = parsedecimal(parseptr); // parse the next number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

motorAcc = parsedecimal(parseptr); // parse the next number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

motorRun = parsedecimal(parseptr); // parse the next number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

motorReset = parsedecimal(parseptr); // parse the next number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

ser1 = parsedecimal(parseptr); // parse the second number
parseptr = strchr(parseptr, ‘,’)+1; // move past the “,”

ser2 = parsedecimal(parseptr); // parse the third number

servo1.write(ser1);
servo2.write(ser2);

setStepperSpeeds();

bufferidx = 0; // reset the buffer for the next read
return; //return so that we don’t trigger the index increment below
}
// didn’t get newline, need to read more from the buffer
bufferidx++; // increment the index for the next character
if (bufferidx == BUFFSIZE-1) { //if we get to the end of the buffer reset for safety
bufferidx = 0;
}
}
}

double parsedecimal(char *str)
{
return atof(str);
}

void setStepperSpeeds() {

stepper1.setMaxSpeed(motorSpeed);
stepper1.setAcceleration(motorAcc);
//stepper1.setSpeed(motorSpeed);

stepper2.setMaxSpeed(motorPos[2]);
stepper2.setAcceleration(motorAcc);
//stepper2.setSpeed(motorPos[3]);

//stepper3.setMaxSpeed(motorSpeed);
//stepper3.setAcceleration(motorAcc);
// stepper3.setSpeed(motorSpeed);

//stepper4.setMaxSpeed(motorSpeed);
//stepper4.setAcceleration(motorAcc);
// stepper4.setSpeed(motorSpeed);
}

void WriteToPin(int _pin, int _value, Servo _servo){
if (_value >= 1000 && _value < 2000) // check if value should be used for Digital Write (HIGH/LOW)
{
if (_servo.attached()) _servo.detach(); // detach servo is one is attached to pin
pinMode(_pin, OUTPUT); // sets the pin for output
_value -=1000; // subtract 1000 from the value sent from Firefly
if (_value == 1) digitalWrite(_pin, HIGH); // Digital Write to pin
else digitalWrite(_pin, LOW);
}
}

Image

Calibration Grasshopper File

Image

Drawing Grasshopper File

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: