Guest User

Untitled

a guest
Dec 6th, 2018
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 11.43 KB | None | 0 0
  1. /*
  2. CNC plotter using A4988 motor controller
  3.  */
  4.  
  5. #include <Arduino.h>
  6. #include <Servo.h>
  7. #include "BasicStepperDriver.h"
  8. #include "MultiDriver.h"
  9. #include "SyncDriver.h"
  10.  
  11. #define LINE_BUFFER_LENGTH 512
  12. // Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
  13. #define MOTOR_STEPS 200
  14. // Since microstepping is set externally, make sure this matches the selected mode
  15. // If it doesn't, the motor will move at a different RPM than chosen
  16. // 1=full step, 2=half step etc.
  17. #define MICROSTEPS 1
  18.  
  19. // X motor
  20. #define DIR_X 4
  21. #define STEP_X 3
  22.  
  23. // Y motor
  24. #define DIR_Y 6
  25. #define STEP_Y 5
  26.  
  27. // RPM; hopefully works
  28. #define RPM_X 60
  29. #define RPM_Y 60
  30.  
  31. // 2-wire basic config, microstepping is hardwired on the driver
  32. // Other drivers can be mixed and matched but must be configured individually
  33. BasicStepperDriver stepperX(MOTOR_STEPS, DIR_X, STEP_X);
  34. BasicStepperDriver stepperY(MOTOR_STEPS, DIR_Y, STEP_Y);
  35.  
  36. // Servo on PWM pin 9, because it's a Nano
  37. const int penServoPin = 9;
  38.  
  39. Servo penServo;  
  40.  
  41. /* Structures, global variables    */
  42. struct point {
  43.   float x;
  44.   float y;
  45.   float z;
  46. };
  47.  
  48. // Current position of plothead
  49. struct point actuatorPos;
  50.  
  51. //  Drawing settings, should be OK
  52. float StepInc = 2; // When set to 1, the thing won't move practically at all. No idea why.
  53. int StepDelay = 15;
  54. int LineDelay = 150;
  55. int penDelay = 50;
  56.  
  57. // Motor steps to go 1 millimeter.
  58. // Use test sketch to go 100 steps. Measure the length of line.
  59. // Calculate steps per mm. Enter here.
  60. // IMPORTANT: These are half the actual size, due to StepInc being 2 instead of 1.
  61. float StepsPerMillimeterX = 3.0; // horizontal plane
  62. float StepsPerMillimeterY = 3.0; // certical plane
  63.  
  64. // Drawing robot limits, in mm
  65.  
  66. float Xmin = 0;
  67. float Xmax = 40;
  68. float Ymin = 0;
  69. float Ymax = 40;
  70. float Zmin = 0;
  71. float Zmax = 1;
  72.  
  73. float Xpos = Xmin;
  74. float Ypos = Ymin;
  75. float Zpos = Zmax;
  76.  
  77. // Set to true to get debug output.
  78. boolean verbose = true;
  79.  
  80. //  Needs to interpret
  81. //  G1 for moving
  82. //  G4 P300 (wait 150ms)
  83. //  G1 F100.000000 (pen down)
  84. //  G0 F3000 (pen up)
  85. //  Discard anything with a (
  86. //  Discard any other command!
  87.  
  88. /**********************
  89.  * void setup() - Initialisations
  90.  ***********************/
  91. void setup() {
  92.   //  Setup
  93.   Serial.begin(9600);
  94.  
  95.   penServo.attach(penServoPin);
  96.   penUp(); //Just to be sure
  97.   delay(200);
  98.  
  99.   stepperX.begin(RPM_X, MICROSTEPS);
  100.   stepperY.begin(RPM_Y, MICROSTEPS);  
  101.  
  102.   //  Notifications!!!
  103.   Serial.println("Mini CNC Plotter alive and kicking!");
  104.   Serial.print("X range is from ");
  105.   Serial.print(Xmin);
  106.   Serial.print(" to ");
  107.   Serial.print(Xmax);
  108.   Serial.println(" mm.");
  109.   Serial.print("Y range is from ");
  110.   Serial.print(Ymin);
  111.   Serial.print(" to ");
  112.   Serial.print(Ymax);
  113.   Serial.println(" mm.");
  114. }
  115.  
  116.  
  117.  
  118. /**********************
  119.  * void loop() - Main loop
  120.  ***********************/
  121.  
  122. void loop()
  123. {
  124.   delay(200);
  125.   char line[ LINE_BUFFER_LENGTH ];
  126.   char c;
  127.   int lineIndex;
  128.   bool lineIsComment, lineSemiColon;
  129.  
  130.   lineIndex = 0;
  131.   lineSemiColon = false;
  132.   lineIsComment = false;
  133.  
  134.   while (1) {
  135.  
  136.     // Serial reception - Mostly from Grbl, added semicolon support
  137.     while ( Serial.available()>0 ) {
  138.       c = Serial.read();
  139.       if (( c == '\n') || (c == '\r') ) {             // End of line reached
  140.         if ( lineIndex > 0 ) {                        // Line is complete. Then execute!
  141.           line[ lineIndex ] = '\0';                   // Terminate string
  142.           if (verbose) {
  143.             Serial.print( "Received : ");
  144.             Serial.println( line );
  145.           }
  146.           processIncomingLine( line, lineIndex );
  147.           lineIndex = 0;
  148.         }
  149.         else {
  150.           // Empty or comment line. Skip block.
  151.         }
  152.         lineIsComment = false;
  153.         lineSemiColon = false;
  154.         Serial.println("ok");    
  155.       }
  156.       else {
  157.         if ( (lineIsComment) || (lineSemiColon) ) {   // Throw away all comment characters
  158.           if ( c == ')' )  lineIsComment = false;     // End of comment. Resume line.
  159.         }
  160.         else {
  161.           if ( c <= ' ' ) {                           // Throw away whitepace and control characters
  162.           }
  163.           else if ( c == '/' ) {                    // Block delete not supported. Ignore character.
  164.           }
  165.           else if ( c == '(' ) {                    // Enable comments flag and ignore all characters until ')' or EOL.
  166.             lineIsComment = true;
  167.           }
  168.           else if ( c == ';' ) {
  169.             lineSemiColon = true;
  170.           }
  171.           else if ( lineIndex >= LINE_BUFFER_LENGTH-1 ) {
  172.             Serial.println( "ERROR - lineBuffer overflow" );
  173.             lineIsComment = false;
  174.             lineSemiColon = false;
  175.           }
  176.           else if ( c >= 'a' && c <= 'z' ) {        // Upcase lowercase
  177.             line[ lineIndex++ ] = c-'a'+'A';
  178.           }
  179.           else {
  180.             line[ lineIndex++ ] = c;
  181.           }
  182.         }
  183.       }
  184.     }
  185.   }
  186. }
  187.  
  188. void processIncomingLine( char* line, int charNB ) {
  189.   int currentIndex = 0;
  190.   char buffer[ 64 ];                                 // Hope that 64 is enough for 1 parameter
  191.   struct point newPos;
  192.  
  193.   newPos.x = 0.0;
  194.   newPos.y = 0.0;
  195.  
  196.   //  Needs to interpret
  197.   //  G1 for moving
  198.   //  G4 P300 (wait 150ms)
  199.   //  G1 X60 Y30
  200.   //  G1 X30 Y50
  201.   //  M300 S30 (pen down)
  202.   //  M300 S50 (pen up)
  203.   //  Discard anything with a (
  204.   //  Discard any other command!
  205.  
  206.   while( currentIndex < charNB ) {
  207.     switch ( line[ currentIndex++ ] ) {              // Select command, if any
  208.     case 'U': // I honestly think this doesn't do anything, but I didn't remove it, because that's how it was in the faulty code
  209.       penUp();
  210.       break;
  211.     case 'D': // Same for this part
  212.       penDown();
  213.       break;
  214.     case 'G':
  215.       buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands
  216.       //      buffer[1] = line[ currentIndex++ ];
  217.       //      buffer[2] = '\0';
  218.       buffer[1] = '\0';
  219.  
  220.       switch ( atoi( buffer ) ){                   // Select G command
  221.       case 0:                                   // G00 & G01 - Movement or fast movement. Same here
  222.       case 1:
  223.         // /!\ Dirty - Suppose that X is before Y
  224.         char* indexX = strchr( line+currentIndex, 'X' );  // Get X/Y position in the string (if any)
  225.         char* indexY = strchr( line+currentIndex, 'Y' );
  226.         if ( indexY <= 0 ) {
  227.           newPos.x = atof( indexX + 1);
  228.           newPos.y = actuatorPos.y;
  229.         }
  230.         else if ( indexX <= 0 ) {
  231.           newPos.y = atof( indexY + 1);
  232.           newPos.x = actuatorPos.x;
  233.         }
  234.         else {
  235.           newPos.y = atof( indexY + 1);
  236.           indexY = '\0';
  237.           newPos.x = atof( indexX + 1);
  238.         }
  239.         drawLine(newPos.x, newPos.y ); // A DrawLine függvényben vannak stepper dolgok, a többi csak feldolgozásnak tűnik
  240.         //        Serial.println("ok");
  241.         actuatorPos.x = newPos.x;
  242.         actuatorPos.y = newPos.y;
  243.  
  244.        
  245.         // This is my (admittedly dirty) way of chekcing for G1 F100.000000 and G0 F3000
  246.         if ((NULL != strchr(line, 'F')) && (NULL != strchr(line, '1')))
  247.           penDown();
  248.         if ((NULL != strchr(line, 'F')) && (NULL != strchr(line, '3')))
  249.           penUp();
  250.         break;
  251.  
  252.       }
  253.       break;
  254.     case 'M':
  255.       buffer[0] = line[ currentIndex++ ];        // /!\ Dirty - Only works with 3 digit commands
  256.       buffer[1] = line[ currentIndex++ ];
  257.       buffer[2] = line[ currentIndex++ ];
  258.       buffer[3] = '\0';
  259.       switch ( atoi( buffer ) ){
  260.       case 300: // This is also not needed, but I left it in, just in case I used some other type of G-code
  261.         {
  262.           char* indexS = strchr( line+currentIndex, 'S' );
  263.           float Spos = atof( indexS + 1);
  264.           //          Serial.println("ok");
  265.           if (Spos == 180) {
  266.             penDown();
  267.           }
  268.           if (Spos == 140) {
  269.             penUp();
  270.           }
  271.           break;
  272.         }
  273.       case 114:                                // M114 - Repport position
  274.         Serial.print( "Absolute position : X = " );
  275.         Serial.print( actuatorPos.x );
  276.         Serial.print( "  -  Y = " );
  277.         Serial.println( actuatorPos.y );
  278.         break;
  279.       default:
  280.         Serial.print( "Command not recognized : M");
  281.         Serial.println( buffer );
  282.       }
  283.     }
  284.   }
  285. }
  286.  
  287.  
  288. /*********************************
  289.  * Draw a line from (x0;y0) to (x1;y1).
  290.  * Bresenham algo from https://www.marginallyclever.com/blog/2013/08/how-to-build-an-2-axis-arduino-cnc-gcode-interpreter/
  291.  * int (x1;y1) : Starting coordinates
  292.  * int (x2;y2) : Ending coordinates
  293.  **********************************/
  294. void drawLine(float x1, float y1) {
  295.  
  296.   if (verbose)
  297.   {
  298.     Serial.print("fx1, fy1: ");
  299.     Serial.print(x1);
  300.     Serial.print(",");
  301.     Serial.print(y1);
  302.     Serial.println("");
  303.   }  
  304.  
  305.   //  Bring instructions within limits
  306.   if (x1 >= Xmax) {
  307.     x1 = Xmax;
  308.   }
  309.   if (x1 <= Xmin) {
  310.     x1 = Xmin;
  311.   }
  312.   if (y1 >= Ymax) {
  313.     y1 = Ymax;
  314.   }
  315.   if (y1 <= Ymin) {
  316.     y1 = Ymin;
  317.   }
  318.  
  319.   if (verbose)
  320.   {
  321.     Serial.print("Xpos, Ypos: ");
  322.     Serial.print(Xpos);
  323.     Serial.print(",");
  324.     Serial.print(Ypos);
  325.     Serial.println("");
  326.   }
  327.  
  328.   if (verbose)
  329.   {
  330.     Serial.print("x1, y1: ");
  331.     Serial.print(x1);
  332.     Serial.print(",");
  333.     Serial.print(y1);
  334.     Serial.println("");
  335.   }
  336.  
  337.   //  Convert coordinates to steps
  338.   x1 = (int)(x1*StepsPerMillimeterX);
  339.   y1 = (int)(y1*StepsPerMillimeterY);
  340.   float x0 = Xpos;
  341.   float y0 = Ypos;
  342.  
  343.   //  Let's find out the change for the coordinates
  344.   long dx = abs(x1-x0);
  345.   long dy = abs(y1-y0);
  346.   int sx = x0<x1 ? StepInc : -StepInc; // Actual number of steps done in the X direction
  347.   int sy = y0<y1 ? StepInc : -StepInc; // Actual number of steps done in the Y direction
  348.  
  349.   long i;
  350.   long over = 0;
  351.  
  352.   if (dx > dy) {
  353.     for (i=0; i<dx; ++i) {
  354.       stepperX.move(sx);
  355.       over+=dy;
  356.       if (over>=dx) {
  357.         over-=dx;
  358.         stepperY.move(sy);
  359.       }
  360.       delay(StepDelay);
  361.     }
  362.   }
  363.   else {
  364.     for (i=0; i<dy; ++i) {
  365.       stepperY.move(sy);
  366.       over+=dx;
  367.       if (over>=dy) {
  368.         over-=dy;
  369.         stepperX.move(sx);
  370.       }
  371.       delay(StepDelay);
  372.     }    
  373.   }
  374.  
  375.   if (verbose)
  376.   {
  377.     Serial.print("dx, dy:");
  378.     Serial.print(dx);
  379.     Serial.print(",");
  380.     Serial.print(dy);
  381.     Serial.println("");
  382.   }
  383.  
  384.   if (verbose)
  385.   {
  386.     Serial.print("Going to (");
  387.     Serial.print(x1);
  388.     Serial.print(",");
  389.     Serial.print(y1);
  390.     Serial.println(")");
  391.   }
  392.  
  393.   //  Delay before any next lines are submitted
  394.   delay(LineDelay);
  395.   //  Update the positions
  396.   Xpos = x1;
  397.   Ypos = y1;
  398. }
  399.  
  400. // This works for sure, it's been thoroughly tested
  401. void penUp()
  402. {
  403.   for (int pos = 180; pos >= 140; pos--) {
  404.     // in steps of 1 degree
  405.     penServo.write(pos);              // tell servo to go to position in variable 'pos'
  406.     delay(15);                       // waits 15ms for the servo to reach the position
  407.   }
  408.   Zpos=Zmax;
  409.   if (verbose) {
  410.     Serial.println("Pen up!");
  411.   }
  412. }
  413.  
  414.  
  415. // This as well
  416. void penDown()
  417. {
  418.   for (int pos = 140; pos <= 180; pos++) {
  419.     penServo.write(pos);              // tell servo to go to position in variable 'pos'
  420.     delay(15);                       // waits 15ms for the servo to reach the position
  421.   }
  422.   Zpos=Zmin;
  423.   if (verbose) {
  424.     Serial.println("Pen down.");
  425.   }
  426. }
Add Comment
Please, Sign In to add comment