Code for a wirebender

I am new to this forum and thaught I should jump right in with a question about a project I am working on.

The idea is to build a wirebender, something along the lines of this:

Now I’ve finnished the machanical part of the project, now it’s a matter of programming.
I’m running with NEMA 17 stepper motors driven by pololu stepper drivers as often used in reprap 3D printers.
All this controlled by an arduino (at the moment a UNO because the mega 2560 which I originally intended on using doesn’t work with the processing progeam).

Now where the problem arises is that I have the code from PENSA (the guys that made the original DIWIRE) unfortunately this does not seem to be working as expected. What seems to happen is the stepper motors twitch and don’t seem to be receiving the signals from the processing program. Interestingly enough with a simple sketch to test the stepper motors controlled through the serial port they run beautifully and can be controlled from the Processing program (this should rule out a wiring problem and problems with the serial connection. I am completely lost at tyhe moment and help will definately be much appreciated! (see bottom of the post for the code on the arduino and the processing sketch).

It would be great if someone helped out! Thanks in advance!

Arduino Code:

* Feed Motor 1 - drives wire
 * z Bend Motor - performs 3D bends by rotating entire assembly
 * bend Motor - performs 2D bends by bending wire over
 * benderPin - solenoid
 */

// pin assignments
// Motor pulse and solenoid pins
const int bendMotorPls = 9;
const int zMotorPls = 10;
const int feedMotorPls = 11;
const int benderPin = 12;

// AWO pins to allow motor shaft to free spin
const int bendMotorAWO = 3;
const int zMotorAWO = 4;
const int feedMotorAWO = 5;

// Direction pins to select drive direction
const int bendMotorDir = 6;
const int zMotorDir = 7;
const int feedMotorDir = 8;

//misc program constants
const int pulseWidth = 20;
const int pulseDelay = 700;

// Drive directions in english
boolean ccw = true; // counter-clockwise drive direction
boolean cw = false; // clockwise drive direction
boolean curDir = cw; // resets direction before next angle command 

int lastbend = 0;
int fieldindex=0;
int values[300]; //creates array

void setup() {
  Serial.begin (9600); //com port communication
  pinMode (bendMotorPls, OUTPUT); //Declaring motor pins as out
  pinMode (zMotorPls, OUTPUT); 
  pinMode (feedMotorPls, OUTPUT); 
  pinMode (bendMotorAWO, OUTPUT); 
  pinMode (zMotorAWO, OUTPUT); 
  pinMode (feedMotorAWO, OUTPUT); 
  pinMode (bendMotorDir, OUTPUT);
  pinMode (zMotorDir, OUTPUT); 
  pinMode (feedMotorDir, OUTPUT); 
  pinMode (benderPin, OUTPUT); 
  digitalWrite (bendMotorPls, LOW); //starts with everything off
  digitalWrite (zMotorPls, LOW); 
  digitalWrite (feedMotorPls, LOW); 
  digitalWrite (benderPin, LOW);
  digitalWrite (zMotorAWO, HIGH);
  digitalWrite (feedMotorAWO, HIGH);
  digitalWrite (bendMotorAWO, HIGH);
}

void bend (float angle) {     //bender pin movement
  if (angle!=0){              //sets direction of bend based on + or - angle
    Serial.println("bending");
    Serial.println(angle);
    boolean dir=cw;
    boolean back=ccw;
    if (angle<0){
      dir = ccw;
      back = cw;
    }
    float rotations = 0;
    angle = abs(angle);
    if (angle <= 90){
      angle = -.0012*angle*angle+.5959*angle+.2452; //converts angle into calibrated motor steps 
      angle = 6000 * (angle/360)+220;
    }
    else if (91 <= angle <= 120){
      angle = .0044*angle*angle-.5481*angle+57.981; //converts angle into calibrated motor steps 
      angle = 5960 * (angle/360)+220;
    }
    else if (121<=angle<=180){
      angle = angle-63.26;  //converts angle into calibrated motor steps 
      angle = 5960 * (angle/360)+220;
    }   //calibration will differ depending on set up 
    rotations = angle;
    // Serial.println (angle);
    digitalWrite (bendMotorDir, dir);  
    for (int i=0; i <=rotations  ; i++){ //moves bender bin the desired angle
      digitalWrite(bendMotorPls, HIGH);
      delayMicroseconds (pulseWidth);
      digitalWrite(bendMotorPls, LOW);
      delayMicroseconds (pulseDelay);
    }
    delay (100);
    digitalWrite (bendMotorDir, back);   //moves bender pin back to home position ready for next feed
    for (int i=0; i <=rotations  ; i++){
      digitalWrite(bendMotorPls, HIGH);
      delayMicroseconds (pulseWidth);
      digitalWrite(bendMotorPls, LOW);
      delayMicroseconds (pulseDelay);
    }
  }
}

void rotatePin (boolean dir, float angle) { //moves bender pin during duck. direction specified from duck subroutine
  float rotations = 0;
  angle = 6000 * (angle/360); //converts angle to steps
  rotations = angle;
  Serial.println (dir);
  digitalWrite (bendMotorDir, dir);  
  for (int i=0; i <=rotations  ; i++){ //rotates bender motor appropriate number of steps
    digitalWrite(bendMotorPls, HIGH);
    delayMicroseconds (pulseWidth);
    digitalWrite(bendMotorPls, LOW);
    delayMicroseconds (pulseDelay);
  }
}

void zbend (float angle) { //rotates z motor
  if (angle!=0){
    Serial.println("Z bending");
    Serial.println(angle);
    boolean dir=cw;
    if (angle<0){ //+ angle is clockwise - angle is counter clockwise
      dir = ccw;
    }
    float rotations = 0;
    angle = abs(angle);
    angle = (2000 * angle)/360; //converts angle to motor steps
    rotations = angle;
    digitalWrite (zMotorDir, dir);  //sets motor direction
    for (int i=0; i <=rotations  ; i++){ //rotates z motor appropriate number of steps
      digitalWrite(zMotorPls, HIGH);
      delayMicroseconds (pulseWidth);
      digitalWrite(zMotorPls, LOW);
      delayMicroseconds (2000);
    }
  }
}

void feed (float dist) { //feeds wire
  if (dist != 0){
    Serial.println("feeding");
    Serial.println(dist);
    float rotations = 0;
    float feedCalib = 25.4*PI; //feed mm per revolution of motor
    dist = 2000 * dist/feedCalib;  //dist converted from mm to steps
    rotations = dist;
    digitalWrite (feedMotorDir, 1);  //feed motor only moves forward
    for (int i=0; i <=rotations  ; i++){ //rotate feed motor appropriate number of steps 
      digitalWrite(feedMotorPls, HIGH);
      delayMicroseconds (pulseWidth);
      digitalWrite(feedMotorPls, LOW);
      delayMicroseconds (pulseDelay);
    }
  }
}

void duck (){  //ducks bender pin under wire
  digitalWrite (benderPin, HIGH); 
  delay (100);
  rotatePin (curDir, 45);
  digitalWrite (benderPin, LOW);  //pin down move under wire
  curDir = !curDir;    //direction reversed for next duck
}

void loop() {
  int copies = 0;
  while (Serial.available ()){ //starts once serial entry made
    digitalWrite (bendMotorAWO, LOW);
    digitalWrite (zMotorAWO, LOW);
    digitalWrite (feedMotorAWO, LOW);

    int in = Serial.read();
    byte incoming = in+128; //converts bytes from processing
    if (incoming != 255){   //255 signifies end of incoming array
      Serial.println (Serial.read());
      values[fieldindex] = values[fieldindex]*10+incoming; //fills array fieldindex from incoming processing
      fieldindex++;
    }
    else{
      Serial.println("END");     //if array end marker inputs from processing end
      for (int i=0; i<=fieldindex;i++){
        Serial.println(values[i]-128);
      }
      copies=copies+1;
    }
  }
  if (copies==1){ //once bend is complete eject shape
    delay (1000);
    motorrun();
    feed(50); //eject 
    copies=copies+1;
  }
}

void motorrun(){
  int lastbend=0;
  for (int i=0; i<= fieldindex;i++){
    delay (100);
    if ((values[i]-128)==126){ //convert bytes from processing and look for feed motor marker
      feed (values[i+1]-128);  //if feed motor marker detected next value in array is a feed length
    }
    else if ((values[i]-128)==125){ //convert bytes from processing and look for bend motor marker
      int bendAng = (values[i+1]-128);  //if bend motor marker detected next value in array is a bend angle
      if ((bendAng<0&&curDir==cw) || (bendAng>0 && curDir ==ccw)){ //if incoming bend angle is opposite direction from previous angle duck pin
        duck ();
        delay (100);
      }
      bend (bendAng);
      lastbend = bendAng;
    }
    else if ((values[i]-128)==124){ //convert bytes from processing and look for z motor marker
      zbend (values[i+1]-128);  //if z motor marker detected next value in array is z bend angle
    }
  }
}

All credit for the above code goes to PENSA

Maybe useful aswell, the code that is in the processing program (this however seems to work quite nicely and doesn’t seem to be posing a problem).

//import these libraries from libraries folder
import processing.serial.*;
import geomerative.*;
import org.apache.batik.svggen.font.table.*;
import org.apache.batik.svggen.font.*;
Serial arduino;


//Declaring the objects being used to print
RShape shp;
RPoint[] points;
int maxArray = 255;
float[] angles = new float [maxArray];
float[] feeds = new float [maxArray];
float res = 10; //default resolution
int interimSteps = 1; //a counter for the preview
int steps =1;
int lastpty = 0;

boolean chngRes = false;
boolean preview = false;

void setup() {
  size (400, 400); //creates window
  background (255);
  println(Serial.list());
  arduino = new Serial(this, Serial.list() [0], 9600); //sets arduino usb port

  // VERY IMPORTANT: Allways initialize the library in the setup
  RG.init(this);
  shp = RG.loadShape("bendMe.svg"); //loads file from folder
  steps = int(shp.getCurveLength()/res);
  smooth();
  frameRate(24);
  println ();
  println ("SET THE SYSTEM TO HOME POSITION");
  println ("PRESS MOUSE BUTTON TO SET RESOLUTION");
  println ("PRESS:");
  println ("1. PROCESS SHAPE");
  println ("2. PREVIEW SHAPE");
  println ("3. SEND SHAPE TO ARDUINO");
  println ();
  println ("RESOLUTION IS CURRENTLY = " + res);  
  println ("NUMBER OF STEPS = " + steps);
}

void draw() { 
  translate(width/4, height/4);   // Sets draw location and scale
  noFill();

  if (!preview) { //draws exact shape from file bendMe.svg
    RG.setPolygonizer(RG.ADAPTATIVE);
    stroke(0, 0, 200, 150);
    shp.draw();

    RG.setPolygonizer(RG.UNIFORMLENGTH);
    if (chngRes) { //sets resolution if mouse is pressed
      background(255);
      float minDist = shp.getCurveLength()/maxArray; // minimum line distance(resolution) based on array size
      res = map(float(mouseY), 0.0, float(height), minDist, 128); //resolution based on mouse location
      shp.draw();
    }
    RG.setPolygonizerLength(res); 
    points = shp.getPoints(); //point resolution based on mouse location 

    // draw a shape of lines connecting the points
    if (points != null) {
      noFill();
      stroke(0, 200, 0, 50);
      strokeWeight (5);
      beginShape();
      for (int i=0; i<points.length; i++) {
        vertex(points[i].x, points[i].y);
      }
      endShape();
      strokeWeight (1);

      fill(0);
      stroke(0);
      for (int i=0; i<points.length; i++) {
        ellipse(points[i].x, points[i].y, 5, 5);
      }
    }
  }
  else { //draws preview shape based on set resolution
    background (255);
    stroke (random (255), random (255), random (255));
    strokeWeight (5);
    pushMatrix();
    noFill();
    beginShape();
    for (int i=1; i<=steps+2; i++) { //preview bend by relative angles
      line (0, 0, 0, feeds[i-1]);       
      translate (0, feeds [i-1]);
      rotate (-radians(angles [i+1])); //bend
    }
    preview = !preview;  
    popMatrix ();
  }
}


void mousePressed() { //mouse press sets resolution based on mouse location
  println ("RESOLUTION SET TO = " + res + " mm");
  steps = int(shp.getCurveLength()/res);
  println ("NUMBER OF STEPS = " + steps);
  chngRes = !chngRes;
}

void keyPressed() { //If keys are pressed run corresbonding subroutine 
  switch (key) {
  case '1': //calculates bend angles and feed lengths
    calcs();     
    break;

  case '2': //shows a shape preview based on set resolution
    preview = !preview; 
    break;

  case '3': //sends bend angles and feed lengths to the arduino for printing
    sendArd ();
    break;
  }
}


//this subroutine accepts feedback from the arduino. It is not necessary but sometimes needed to establish initial serial communication
/*void serialEvent (Serial p) {
  String inString = arduino.readStringUntil ('\n'); 
  if (inString !=null) {
    println(inString);
  }
}*/


void calcs () {
  float lastAng=0;
  float lastlastAng = 0;

  println ( key );
  println ();
  println ( "Processing shape" );
  println ();
  println (points.length);
  //calculate relative angles between points and assign to array angles[]
  angles [0] = 0; // first angle is zero
  for (int i = 1; i < points.length; i++) {  
    feeds[i-1] = dist (points[i-1].x, points[i-1].y, points[i].x, points[i].y); //feed legths are the distances between points
    float deltaX = points[i].x - points[i-1].x;    //change in x axis between points
    float deltaY = points[i].y - points[i-1].y;    //change in y axis between points

    //the following equations calculate the bend angles between each point
    //there are different equations for each coordinate quadrant
    if ((deltaX >=0 && deltaY >=0)||(deltaX <=0 && deltaY >=0)) { 
      angles[i] =(degrees(atan(deltaX/deltaY)) - (lastAng + lastlastAng));
    }
    if (deltaX <= 0 && deltaY < 0) {
      angles[i] = (180 + abs(degrees(atan(deltaX/deltaY)))) - (lastAng + lastlastAng);
    }
    if (deltaX >0 && deltaY <0) {
      angles[i] = (180 - abs(degrees(atan(deltaX/deltaY)))) - (lastAng + lastlastAng);
    } 
    if (angles[i]>720) {
      angles[i] = angles[i]-360;
    }
    if (angles[i]<-180) {
      angles[i] = 360+angles[i];
    }
    if (angles[i]>180) {
      angles[i] = angles[i]-360;
    }   

    //shows matrix of feeds and bend angles
    println (round(1*(feeds[i-1]))+"\t"+round(angles[i])+"\t"+"0");  //change the 1 before feeds to change scale. z bend remains 0 because this is a 2D shape
    if (abs(angles [i]) > 125) { //beacuse we are sending bytes to the arduino board no angle or feed length can exceed 125
      println ("WARNING - ANGLE TOO BIG");
    }
    lastlastAng = lastAng+lastlastAng; //sets variables to know last 2 bend angles needed to calculate bends
    lastAng = angles[i];
  }
}

void sendArd () { //sends bend angles and feed lengths to the arduino board for printing
  byte feedmotor = 126; //these byte values are markers so the arduino knows if a value is a bend, feed, or end it's the end of the array
  byte bendmotor = 125;
  byte end = 127; 

  println ( key );
  println ();
  println ( "Sending to Arduino" );
  println ( "Printing" );
  println ();

  //send commands
  for (int i = 2; i < steps+233; i++) {

    //sends arduino feed marker followed by feed length
    delay (100);
    arduino.write (feedmotor);
    println("feed");
    delay (100);
    arduino.write (byte(round (feeds[i-2])));
    delay (100);
    println (feeds[i-2]);
    //sends arduino bend marker followed by bend angle
    arduino.write (bendmotor);
    println("bend");
    delay (100);
    arduino.write (byte(round (-angles[i])));
    println (angles[i]);
  }
  println (end+128); //tells arduino the array of values in complete
  arduino.write(end);
}

Again all credit goes to PENSA for the code

hello.

My name is Hernan and I'm from Argentina.

I am with the same project, assemble everything and move the engines failed.

find the solution?

//misc program constants
const int pulseWidth = 20;
const int pulseDelay = 700;

I would start by increasing the pulseWidth. That's only 20 microseconds that the pin is held high and seems too short; try 20000 for both and see if it moves properly. If it does move then you can start decreasing those values for more speed.

Chagrin: //misc program constants const int pulseWidth = 20; const int pulseDelay = 700;

I would start by increasing the pulseWidth. That's only 20 microseconds that the pin is held high and seems too short; try 20000 for both and see if it moves properly. If it does move then you can start decreasing those values for more speed.

no I disagree pulseWidth can be as low as 5 microseconds, it's the transition that cause the step

I would check that you have step and direction pins the right way round

I also see that your loop uses an int to control it, with a float as the max value I hope the int doesn't overflow

hello.

as I said, I am with the same poyecto and all you achieve is to move only a motor for feeding.

bending the motor does not move

it can be?

will the image?

codes are apparently well, a motor moves.

help please

From a quick look the Pensa code seems to be very straightforward.

I suggest you extract just enough of it to make one motor work (perhaps the bendPin stuff) and make it into a short sketch. Then you can compare it very closely with your own working code to see where there are differences. You can then fiddle with the differences to figure out how to adjust the Pensa code so it works.

...R