Coding AxiDraw as I want

Hello everybody !

Just want to precise first that I’m not a native English speaker so please be merciful with me if you spot grammar mistakes or anything…

I need help on a project about making an AxiDraw v3 robot (painting robot in short) move following a pattern that I will create. For example, let’s take a snake pattern, the robot goes along the x-axis (solely), then when it has reached his maximal value (let’s say 21cm), it goes on the y-axis for 3cm, then goes back to the x-axis and so on.

To do that, I found a code on the Internet where I could “control” AxiDraw…

import de.looksgood.ani.*;
import processing.serial.*;

//import javax.swing.UIManager; 
//import javax.swing.JFileChooser; 


// Really raw axidraw controller (code taken from RobotpaintRT)

// press 'm' to unlock/lock motors
// press 'z' to zero (set home location)
// moveToXY(int, int); to move around
// raiseBrush(); etc.


// User Settings: 
float MotorSpeed = 1500.0;  // Steps per second, 1500 default

int ServoUpPct = 70;    // Brush UP position, %  (higher number lifts higher). 
int ServoPaintPct = 30;    // Brush DOWN position, %  (higher number lifts higher). 
int ServoWashPct = 20;    // Brush DOWN position for washing brush, %  (higher number lifts higher). 

boolean reverseMotorX = false;
boolean reverseMotorY = false;

int delayAfterRaisingBrush = 300; //ms
int delayAfterLoweringBrush = 300; //ms

//int minDist = 4; // Minimum drag distance to record

boolean debugMode = true;


// Offscreen buffer images for holding drawn elements, makes redrawing MUCH faster

PGraphics offScreen;

PImage imgBackground;   // Stores background data image only.
PImage imgMain;         // Primary drawing canvas
PImage imgLocator;      // Cursor crosshairs
PImage imgButtons;      // Text buttons
PImage imgHighlight;
String BackgroundImageName = "background.png"; 
String HelpImageName = "help.png"; 

float ColorDistance;
boolean segmentQueued = false;
int queuePt1 = -1;
int queuePt2 = -1;

//float MotorStepsPerPixel =  16.75;  // For use with 1/16 steps
float MotorStepsPerPixel = 8.36;// Good for 1/8 steps-- standard behavior.
int xMotorPaperOffset =  1400;  // For 1/8 steps  Use 2900 for 1/16?

// Positions of screen items

//float paintSwatchX = 108.8;
//float paintSwatchY0 = 84.5;
//float paintSwatchyD = 54.55;
//int paintSwatchOvalWidth = 64;
//int paintSwatchOvalheight = 47;

//int WaterDishX = 2;
//int WaterDishY0 = 88;
//float WaterDishyD = 161.25;
//int WaterDishDia = 118;

//int MousePaperLeft =  185;
//int MousePaperRight =  769;
//int MousePaperTop =  62;
//int MousePaperBottom =  488;

int xMotorOffsetPixels = 0;  // Corrections to initial motor position w.r.t. lower plate (paints & paper)
int yMotorOffsetPixels = 4 ;


int xBrushRestPositionPixels = 18;     // Brush rest position, in pixels
int yBrushRestPositionPixels =  yMotorOffsetPixels;

int ServoUp;    // Brush UP position, native units
int ServoPaint;    // Brush DOWN position, native units. 
//int ServoWash;    // Brush DOWN position, native units

int MotorMinX;
int MotorMinY;
int MotorMaxX;
int MotorMaxY;

boolean firstPath;
boolean doSerialConnect = true;
boolean SerialOnline;
Serial myPort;  // Create object from Serial class
int val;        // Data received from the serial port

boolean BrushDown;
boolean BrushDownAtPause;
boolean DrawingPath = false;

int xLocAtPause;
int yLocAtPause;

int MotorX;  // Position of X motor
int MotorY;  // Position of Y motor
int MotorLocatorX;  // Position of motor locator
int MotorLocatorY; 
int lastPosition; // Record last encoded position for drawing

int selectedColor;
int selectedWater;
int highlightedWater;
int highlightedColor; 


boolean lastBrushDown_DrawingPath;
int lastX_DrawingPath;
int lastY_DrawingPath;


int NextMoveTime;          //Time we are allowed to begin the next movement (i.e., when the current move will be complete).
int SubsequentWaitTime = -1;    //How long the following movement will take.
//int UIMessageExpire;
int raiseBrushStatus;
int lowerBrushStatus;
int moveStatus;
int MoveDestX;
int MoveDestY; 
//int getWaterStatus;
//int WaterDest;
//boolean WaterDestMode;
int PaintDest; 

int CleaningStatus;
int getPaintStatus; 
boolean Paused;


int ToDoList[];  // Queue future events in an integer array; executed when PriorityList is empty.
int indexDone;    // Index in to-do list of last action performed
int indexDrawn;   // Index in to-do list of last to-do element drawn to screen


// Active buttons
PFont font_ML16;
PFont font_CB; // Command button font
PFont font_url;


int TextColor = 75;
int LabelColor = 150;
//color TextHighLight = Black;
int DefocusColor = 175;

//SimpleButton pauseButton;
//SimpleButton brushUpButton;
//SimpleButton brushDownButton;
//SimpleButton cleanButton;
//SimpleButton parkButton;
//SimpleButton motorOffButton;
//SimpleButton motorZeroButton;
//SimpleButton clearButton;
//SimpleButton replayButton;
//SimpleButton urlButton;
//SimpleButton openButton;
//SimpleButton saveButton;


//SimpleButton brushLabel;
//SimpleButton motorLabel;
//SimpleButton UIMessage;

void setup() {
  size(800, 600);

  Ani.init(this); // Initialize animation library
  Ani.setDefaultEasing(Ani.LINEAR);

  MotorMinX = 0;
  MotorMinY = 0;
  MotorMaxX = int(floor(xMotorPaperOffset + width * MotorStepsPerPixel)) ;
  MotorMaxY = int(floor(height * MotorStepsPerPixel)) ;

  //MotorMaxX = int(floor(xMotorPaperOffset + float(MousePaperRight - MousePaperLeft) * MotorStepsPerPixel)) ;
  //MotorMaxY = int(floor(float(MousePaperBottom - MousePaperTop) * MotorStepsPerPixel)) ;

  ServoUp = 7500 + 175 * ServoUpPct;    // Brush UP position, native units
  ServoPaint = 7500 + 175 * ServoPaintPct;   // Brush DOWN position, native units. 

  MotorX = 0;
  MotorY = 0; 

  ToDoList = new int[0];
  ToDoList = append(ToDoList, -35);  // Command code: Go home (0,0)

  indexDone = -1;    // Index in to-do list of last action performed
  indexDrawn = -1;   // Index in to-do list of last to-do element drawn to screen

  raiseBrushStatus = -1;
   lowerBrushStatus = -1; 
   moveStatus = -1;
   MoveDestX = -1;
   MoveDestY = -1;

int[] pos = getMotorPixelPos();

  Paused = false;
  BrushDownAtPause = false;
  MotorLocatorX = pos[0];
  MotorLocatorY = pos[1];

  NextMoveTime = millis();
}



void draw() {
  if (doSerialConnect)
  {
    // FIRST RUN ONLY:  Connect here, so that 

    doSerialConnect = false;

    scanSerial();

    if (SerialOnline)
    {    
      myPort.write("EM,2\r");  //Configure both steppers to 1/8 step mode

      // Configure brush lift servo endpoints and speed
      myPort.write("SC,4," + str(ServoPaint) + "\r");  // Brush DOWN position, for painting
      myPort.write("SC,5," + str(ServoUp) + "\r");  // Brush UP position 

      //    myPort.write("SC,10,255\r"); // Set brush raising and lowering speed.
      myPort.write("SC,10,65535\r"); // Set brush raising and lowering speed.


      // Ensure that we actually raise the brush:
      BrushDown = true;  
      raiseBrush();    

      println("Now entering interactive painting mode.\n");
      //redrawButtons();
    } else
    { 
      println("Now entering offline simulation mode.\n");

      //UIMessage.label = "WaterColorBot not found.  Entering Simulation Mode. ";
      //UIMessageExpire = millis() + 5000;
      //redrawButtons();
    }
  }
}







boolean brushIsUp = true;
void mousePressed() {
  if (brushIsUp) {
    lowerBrush();
    println("Brush Up");
  
  } else {
    raiseBrush();
    println("Brush Down");
    myPort.write("SP,0\r");
  }
  brushIsUp = !brushIsUp;
}




void mouseReleased() {

   myPort.write("XM," + str(1000) + "," + str(1000) + "," + str(1000) + "\r");
}


void keyReleased()
{

  if (key == CODED) {

    //if (keyCode == UP) keyup = false; 
    //if (keyCode == DOWN) keydown = false; 
    //if (keyCode == LEFT) keyleft = false; 
    //if (keyCode == RIGHT) keyright = false; 

    if (keyCode == SHIFT) { 

      //shiftKeyDown = false;
    }
  }

  if ( key == 'h')  // display help
  {
    //hKeyDown = false;
  }
}



void keyPressed()
{

  int nx = 0;
  int ny = 0;

  if (key == CODED) {

    // Arrow keys are used for nudging, with or without shift key.

    if (keyCode == UP) 
    {
      //keyup = true;
    }
    if (keyCode == DOWN)
    { 
      //keydown = true;
    }
    //if (keyCode == LEFT) keyleft = true; 
    //if (keyCode == RIGHT) keyright = true; 
    //if (keyCode == SHIFT) shiftKeyDown = true;
  } else
  {

    if ( key == 'b')   // Toggle brush up or brush down with 'b' key
    {
      if (BrushDown)
        raiseBrush();
      else
        lowerBrush();
    }

    if ( key == 'z'){  // Zero motor coordinates
      zero();
      println("zero'd");
    }

    if ( key == ' ') { //Space bar: Pause
      pause();
      println("paused");
    }

    if ( key == 'q')  // Move home (0,0)
    {
      raiseBrush();
      moveToXY(0, 0);
    }


    if ( key == 'r')  // go to random
    {
      moveToXY(int(random(8000)), int(random(6000))); 
    }


    if ( key == 'm'){  // Disable motors, to manually move carriage.  
      motorsOff();
      println("motors unlocked");
    }

    if ( key == '1')
      MotorSpeed = 100;  
    if ( key == '2')
      MotorSpeed = 250;        
    if ( key == '3')
      MotorSpeed = 500;        
    if ( key == '4')
      MotorSpeed = 750;        
    if ( key == '5')
      MotorSpeed = 1000;        
    if ( key == '6')
      MotorSpeed = 1250;        
    if ( key == '7')
      MotorSpeed = 1500;        
    if ( key == '8')
      MotorSpeed = 1750;        
    if ( key == '9')
      MotorSpeed = 2000;
  }
}

But hey I’m a bit lost here since I’m still fairly new to Processing…
In fact, the purpose of the code was to make the robot draw a straight line, but I don’t understand how the line is drawn. For me, you would have to define a MoveToXY() function, and then put it in a void loop() (or in a draw()) function.

So if somebody could help with that problem, it would be really cool !

Best regards.

1 Like

sorry, can not help, but you could help us:
like a link where you get the code from?
robopaint-rt/processing/RoboPaint_RT/RoboPaint_RT.pde at master · evil-mad/robopaint-rt · GitHub what is from 2013

or a link to the external lib?
Ani - An animation library for Processing from 2015
download
http://www.looksgood.de/libraries/Ani/Ani-latest.zip what is version 2.7

and acc

Feedback is very welcome, but please use the processing discourse forum for that. If you want a quick answer: drop simultaniously an email to me (benedikt ät looksgood döt de), including the link to the post (i’m a very infrequent reader of the processing discourse).

you could send him a email, but as your question is not about his lib,
more about that code, you could post a issue at
Issues · evil-mad/robopaint-rt · GitHub .

Thanks for your answer !

Here’s the link from where I got my code :
https://github.com/koblin/AxiDrawProcessing2

And this is the one for Ani library :
http://www.looksgood.de/libraries/Ani/

I will also contact them but as it is a problem of coding on Processing, I thought it would be better to poste on the Processing forum.

so now we have 2 sources what use that call

moveToXY()

and in your link, if you look at
https://github.com/koblin/AxiDrawProcessing2/blob/master/SimpleDirectDraw/wcbcontrol.pde you find it
– in the versions

  • moveToXY(x,y)
    calls also
  • moveToXY()

using the original Ani.to …

possibly it helps if you include that sketch too.


by the way,
you need to keep a link to


inside your code! even just for a small private test!
it also helps you with your own documentation


Ok, I know that there is 2 functions that make it works.

But I don’t understand how the global thing is working. In fact there’s pretty much 2 things that I don’t comprehend.
First : What’s even the difference between these 2 functions when there general purpose is the same ?
Second : The robot is working, but the instruction to move is not even in a loop, so can I even do my pattern thing ?

that is called

method overloading
more
Default argument like c++ - #2 by kll here


hm, did you download the complete thing this time?
https://github.com/koblin/AxiDrawProcessing2/archive/master.zip

are from that example the
key [q] [r] not working?

Ok many thanks for the link !

I did download the entire thing, and [r]'s working fine but not [q].
[q] sends me to the last position, and not (0,0).

My question is still, what’s making the thing move, here we have no MoveToXY() function, so can we delete these key() function and replace it by a MoveToXY(), would it works ? I tried it but ultimately it failed (maybe because of my incompetence “lol”).

EDIT : [q] is now working just fine.

sorry, i not know anything about that,

but now you have loaded a library
and you have a external downloaded running example
now you have to learn about all function from both.

that i not understand,

that function is called by the keyPressed
and is inside the wcbcontrol.pde
and talks to the port… and use Ani.to()


i would try to start with

if ( key == 'l' ) draw_line(10,10,20,20);

and add

void draw_line(x1,y1,x2,y2)
  moveToXY(x1,y1);
  lowerbrush();
  moveToXY(x2,y2);
  raiseBrush(); 
}

just a untested idea.

Ok, thanks for the help, I will try the thing you told me !

draw loops automatically in itself

If you had something like a to do list with points you would have to go to all points oke after another. Actually there is something in the code above called todolist

Anyway during draw you would assign a x,y target, then wait till it reached it, then assign the next target from the list.

Hello !

Yeah I saw that there was a to do list, but I don’t know how to properly operate, if you have an idea of how it works, please tell it !

That’s pretty much what I did, I assigned key to movement like `if (key == ‘z’)
{

   moveToXY(700,700);   
   println("x=",MotorLocatorX,"y=",MotorLocatorY);
}`

But this solution is a bit particular, because if I want to acquire coordinate at the same time, I cannot, because I only tell him ‘go there’, instead of saying ‘each time you repeat, increase x by a’.
So the to do list is highly interesting for me, but I don’t know the way to properly operate it.

Best regards.