Search This Blog

Showing posts with label DIY. Show all posts
Showing posts with label DIY. Show all posts

Wednesday, 21 October 2015

My Reprap Prusa i3 Kit [ second of a multipart blog] - The Build!

This past weekend, I finally had the time to start building my Reprap Prusa i3 3D Printer,  which I ordered a few weeks ago from  Shenzhen Sunhokey Electronics Co., Ltd. on Aliexpress.com

 

 

 

 

 

 

  

 

 

The kit came with a DVD which included about a dozen videos of the step-by-step assembly process.  There is no speech in the videos, just some background music, and periodic overlay of the hardware required to assemble each step.

 

The videos run at a fairly leisurely pace, but yes... I did have to pause them many times to keep up. 

 

Here's a sample video to show you what 

the process looks like.

 The build started fairly smoothly, with the X-axis motor block and opposite belt tensioner slider assemblies. (Yeah, I'm too lazy to look up the official names of these two components)



 

 

 

My Assistant and fellow builder - Camden, found himself getting rather tired, early into the build! But, like a trooper, he put in a good couple hours.  Thank you Camden.




Next up, was the actual hotend carriage assembly.  I'll have to admit, it was very exciting to see these pieces built first.  Good job Shenzhen Sunhokey Electronics Co., Ltd.!  

At first, I wasnt sure how I would feel about the transparent acrylic frame and parts, but as the build progressed, I grew rather fond of it.

 





 

 

 

Next came Z-Axis Motor brackets, end stops, and then the frame and rails for the Y-Axis heated bed


I wrapped up for the weekend at this point.  Two days of "duration", and about 6 hours of "effort".   

 

 

The next three articles over the upcoming week will be: 

1) wiring all of the motors, switches, heaters, etc to the control board and firing it up.   

2) calibrating and troubleshooting (probably not in that order!)  

3) finally running a first print. 

 

Cheers.

 

 

Tuesday, 13 October 2015

My Reprap Prusa i3 Kit [ first of a multipart blog] - The unboxing!



I finally bit the bullet, and ordered an actual real 3d Printer from Aliexpress.com.  I've needed an actual functioning mechanical printer to finish my testing and calibration on the Printer firmware that I've been working on for several months now. 

The homemade rig that I cobbled together was not capable of the tolerances that my firmware and electronics could theoretically achieve.

I've put it off until now for many reasons:  Mostly because I'm pig headed and didn't want to admit that I'm not a mechanical genius....

Anyway, a few friends convinced me that this was the right way to go, to finish my ACTUAL project, which was the combination of electronics and associated software/firmware to support it.


The kit I ordered was from    Shenzhen Sunhokey Electronics Co., Ltd.

I must say that I was rather impressed with the speed in which this kit was delivered from China to Canada. From the time I ordered, it took about a business week to process the order, but once I received notification that the package had shipped, It was here with about 4 days.   Thank you Aliexpress.com


Without further ado, let's begin the unpacking:


The Fedex dude pretty much had a hernia dropping this little box at my door.  The packaging said 13.5kg, which is about 30lbs for you Americans... But it felt a lot heavier than that.  Must make a note to self to return (go?) to the gym.
















I've removed the thick protective foam top that covered everything to show that this is indeed very well packaged.  








With the box containing the acrylic frame components removed, you can see the electronic and mechanical components nestled tightly within the foam.





The distributor even has little cutouts to cover the stepper motors and linear and threaded rods!









 


 

The aluminum bowden extruder was pre-assembled to the stepper motor, and the machining on the hotend looks to be quite good.








 The power supply is a beefy 12v 30A (360watt) unit.  

My only complaint, is that I was not aware that you had to specify North American AC adapter.  It comes, by default, with a European adapter.  



Yeah, I'm RTFM challenged, ok!?



The Controller board is a MKS Gen 2Z v1.1
This is basically a combination of the Arduino MEGA2560 plus a RAMPS1.4 board.  It still uses the A4988 stepper driver boards. 

Included in this kit is an un-named LCD display with SDCARD and a rotary encoder for menu selection. 
 






All of the frame components are cut out of clear acrylic. (With a nice pink protective layer... hmmm... should I leave that on? )














Also included were two 1kg spools of 1.75mm PLA to get me started.
I didn't request any particular colors, so I kind of expected something funky.  

They provided Black and White, which I'm quite happy about.





That's it for now.  

Later in the week, I'll begin assembling and documenting.  

Wish me luck!

Saturday, 18 April 2015

How we learned about electronics pre-Arduino days...

Very short post here: 

I was cleaning the basement, and came across this. It is "brand new", as in everything was still wrapped in it's original bubble wrap and had the cardboard corner protectors... huh... go figure..

Anyway boys and girls... this is what an Arduino looked like 20+ years ago.  LOL

130 rainy day electronics projects in one box...  

I tend to be a very forgetful person, but I *vividly* remember MY first computer.  

In 1976, Popular Electronics Magazine ran an article about building your very own personal computer.

The "Cosmac ELF was basically a PCB that you purchased, sourcing all of the electronic parts through the mail.  I think at the age of 10, it took me several months to get the components.  Sending off for one of two as my allowance came in, and soldering them to the circuit board. 

Picture from : http://www.homebrewcpu.com/projects.htm
Using an 8bit RCA 1802 processor meant for the newly invented digital gas pumps, the Cosmac Elf boasted 256 bytes (BYTES!) of memory, two 7 segment LEDs, 8 toggle switches for address and data input, a RUN switch, and a PROGRAM switch.  

No BIOS or bootloader... nada... and yet some simple games could be loaded (in binary!) and played for hours of fun.



Two years later, I was up to 4k of memory, a cassette tape drive, and a monochrome video display of 128x64 bits...  and a home rolled character generator!

Those were the days...

I'd LOVE to hear your stories in the comments below...



Wednesday, 8 April 2015

Marlin Firmware on Teensy 3.1 - Analog Temperature success!

I've successfully replaced the Analog functions in Marlin's temperature.cpp, with calls to Pedro Villanueva's ADC library for the Teensy 3.1, and am getting good temperature readings out of it.

Here's a couple shots from Repetier Host. 








Now on to updating the PID functions for the heaters...

This is looking quite doable my friends!


My Previous blogs on this project:
(little did I know I'd be working on this on and off for a year... and the real work is just beginning)






Wednesday, 1 April 2015

Repetier successfully connected and functional with Marlin Firmware on Teensy 3.1

 I've had a few informative back and forth emails with Nikki V from Freescale regarding my failure to get connected to Repetier Host from the Marlin Firmware on my Teensy 3.1.  

(Here's a link to Nikki's 3D printer blog: https://community.freescale.com/grou...on-rampsmarlin)

As mentioned in my previous article, I was finally able to compile and install the Marlin Firmware when I used the fork that Paul Stoffregen started, along with Nikki's Configuration.h and pins.h files. However, I could not connect to the firmware with Repetier.   

Marlin was sending the appropriate communications out through the USB serial port, as evidenced by this screenshot: 

But the Repetier connect request was not initializing Marlin, and returning the printer information.



Nikki pointed me back to the same thread on the Teensy Forum that I've already read 100 times... 

Yeah... but I'm apparently blind or ignorant... or both...

She brought my attention to the fact that this issue has already been identified, and could be remediated  by clicking a "fake OK" button from within the Manual control page.
I couldn't find the "Fake OK" button, so I read a little deeper.

And then Paul chimed in with a comment about compiling on Linux, and it all came together... Thank you Nikki, Thank you Paul.

Here's what Paul had to say that made all the difference: 

I tried the Linux version. It also has only "OK", not "Fake OK", but it seems to work fine.
I had to edit the baud rate to 57600 in Configuration.h. The Linux driver doesn't seem to like 250000 (even though Teensy 3.1 complete ignores the baud rate).

Repetier-Host does seem to be getting hung up on something and requires the "OK" button clicked. I believe it's due to the missing temperature feature. The blue bar will stay stuck as "1 Command Waiting". Clicking "OK" gets it unstuck.



I set the baudrate in configuration.h to 57600, and recompiled and uploaded to the Teensy 3.1.  I then launched Repetier, and went into the printer configuration, and selected 57600.



I applied, saved, and hit "Connect" .....

And Voila!

 


 Marlin Firmware now connects, and provides printer information. 


As of today, I have hard wired in 100k thermistors for Extruder and Bed heater temperature sensing, and set the pullup resistors for the endstops...

The Quadrature encoders are functioning on X and Y axis via the Flextimer module QuadDecode library, and *MY* PID routines (using the Arduino PID library)  are successfully driving both X and Y axis DC motors from the manual controls in Repetier.

The Quadrature encoders are functioning on Z axis with Phase A/B hardware pin interrupts , and *MY* PID routines  are successfully driving one Z axis DC motors from the manual controls in Repetier.

I have a functional I2C 20x4 LCD display, as well as SDcard reader.

As far as capacity on the Teensy, here is the size of code  - all in - so far:
From the Arduino IDE:
Binary sketch size: 108,816 bytes (of a 262,144 byte maximum)
Estimated memory use: 14,080 bytes (of a 65,536 byte maximum)

Is it running... sure... is it printing... no... my budget hasn't allowed me the pleasure of a real extruder. I'm simply stepping a NEMA17 I had kicking around.    I keep saying "next paycheck!"


TODO:


  1. Acquire a real extruder/hotend  (today I'm simply driving a NEMA17 that I had kicking around.)   (anyone want to help??  LOL)
  2. Wire up FET transistors to drive extruder and bed heater elements
  3. Wire up endstops 
  4. Lots and lots and lots of PID tuning.  Things have changed since porting/merging my DC motor code into the Marlin Firmware.
  5. Take video this weekend and upload to Youtube!  LOL 
  6. Remove MY PID routines, and create macro/wrapper to use existing Marlin PID routines meant for temperature management.
  7. Put "conditional" code back in so I can merge this stuff back to github
  8. Figure out how to merge stuff back to github 
  9. figure out whether 7. or 8. should come first...

Friday, 2 January 2015

Teensy 3.1 based Repstrap control board initial wiring completed - test #1

Sorry that this is taking so long, but... (continued from last week...)
I finally have enough of the control board wired up that I can test the I2C library with Adafruit's Motor Shield V2 as well as the Adafruit LCD Backpack.
I simply took the DCMotorTest2 arduino example from the Motor Shield library, and added the LCD functionality. 

Note: Both the Motor Shield Library, as well as the LiquidCrystal libraries needed to be modified to work with Teensy 3.1.

As the Teensy is not AVR based, the I2C functions a bit different (better, trust me!)


In both instances, references to the "Wire" library had to be replaced with Teensy's  "I2C_T3" library.  ie:

//#include <Wire.h>
#include <i2c_t3.h>    // Replacement I2C library for Teensy 3.1


Also in the Motorshield library as well as it's underlying PWMServoDriver library, I had to force it to use the correct I2C channel.   As the ARM processor in the Teensy has two separate I2C channels, it was defaulting to the second one.


I found this little snippet at the beginning of each library, and modified it to use the first I2C channel.

#include "Adafruit_MotorShield.h"
#include <Adafruit_PWMServoDriver.h>
#ifdef __AVR__                        // Teensy definitely is not AVR, so it defaults
 #define WIRE Wire
#else // Arduino Due               // to wire1 as per the next line.
 // #define WIRE Wire1           // Wire1 in Teensy world is the second I2C
 #define WIRE Wire                // So i simply commented out and replaced.
#endif                                      // Not elegant, but...

And here is the example code to simply ramp the DC motor from 0-255 forward, back down to 0 and then do it again in reverse.  All the while displaying status on the 20x4 LCD panel.



/*
This is a test sketch for the Adafruit assembled Motor Shield for Arduino v2
It won't work with v1.x motor shields! Only for the v2's with built in PWM
control

For use with the Adafruit Motor Shield v2
---->    http://www.adafruit.com/products/1438
*/

//#include <Wire.h>
#include <i2c_t3.h> 
// wire for Teensy 3.1 per https://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);

// Select which 'port' M1, M2, M3 or M4. In this case, M1
Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
// You can also make another motor on port M2
//Adafruit_DCMotor *myOtherMotor = AFMS.getMotor(2);

/*
Using with the Adafruit LCD Backpack to display information
---->    http://www.adafruit.com/products/292
*/

#include "LiquidCrystal.h"

// Connect LiquidCrystal display via i2c, default address #0x20 (A0-A2 not jumpered)
LiquidCrystal lcd(0);

int spd = 150;          // Motor PWM speed from 0 - 255
int mState = FORWARD;   // State of the motor

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  Serial.println("Adafruit Motorshield v2 - DC Motor test!");

  // set up the LCD's number of rows and columns:
  lcd.begin(20, 4);
  lcd.print("Adafruit Motorshield v2");
  lcd.setCursor(0, 1);
  lcd.print("DC Motor test!");

  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
 
  // Set the speed to start, from 0 (off) to 255 (max speed)
  myMotor->setSpeed(spd);
  myMotor->run(mState);
  mState = RELEASE;
  // turn on motor
  myMotor->run(mState);
}

void loop() {
 
  Serial.print("tick");
  lcd.setCursor(0, 3);
  lcd.print("tick");

  mState = FORWARD;
  myMotor->run(mState);
  lcd.setCursor(9, 2);
  lcd.print(" Dir = FWD ");         // Display direction on LCD
 
  for (spd=0; spd<255; spd++) {
    myMotor->setSpeed(spd); 
    lcd.setCursor(0, 2);
    lcd.print("PWM = "); lcd.print(spd); lcd.print(" ");
  }
  for (spd=255; spd!=0; spd--) {
    myMotor->setSpeed(spd); 
    lcd.setCursor(0, 2);
    lcd.print("PWM = "); lcd.print(spd); lcd.print(" ");
  }
 
  Serial.print("tock");
  lcd.setCursor(0, 3);
  lcd.print("tock");

  mState = BACKWARD;
  myMotor->run(mState);
  lcd.setCursor(9, 2);
  lcd.print(" Dir = REV ");         // Display direction on LCD

  for (spd=0; spd<255; spd++) {
    myMotor->setSpeed(spd); 
    lcd.setCursor(0, 2);
    lcd.print("PWM = "); lcd.print(spd); lcd.print(" ");
  }
  for (spd=255; spd!=0; spd--) {
    myMotor->setSpeed(spd); 
    lcd.setCursor(0, 2);
    lcd.print("PWM = "); lcd.print(spd); lcd.print(" ");
  }
 

  Serial.print("tech");
  lcd.setCursor(0, 3);
  lcd.print("tech");
 
  myMotor->run(RELEASE);
  delay(1000);
}

Again, trivial, but it validated that my wiring is correct this far, and that the I2C libraries are functional.

Over the weekend, I'll get the Quadrature Decoders and PID control running, and post another update then.


Monday, 29 December 2014

Prototype Printer Controller Cont'd - Teensy 3.1 w/DC motor/encoders


Here's some more shots of the controller prototype..

I've added a DC/DC converter for clean 5v power to the electronics (5amp).  I've also added a separate 5v linear regulator for the Extruder stepper circuitry.
To get access to the extra pins on the bottom of the teensy, I used a dual row header, and bent the inside pins at a 90 degree angle, trimmed, and soldered.
The shot on the right shows the Real Time Clock crystal soldered into place.

And of course I use my 
legacy 3D extruder 
religiously to lay down layers of plastic "wire holders". 







This is where I wish I had kept all of my old wire wrap tools... Who knew I'd pick up electronics again after almost a 20 year hiatus.

Anyway, power and ground... check. 

Now to the rest of the wires..
 

Sunday, 28 December 2014

Prototype Board: DC motor/Encoder - Teensy 3.1 based 3D printer controller

This will be a short post today.  

I had mentioned putting up pictures as I go along, so I took this to show the first prototype of the controller board.

Here is the layout of my Teensy 3.1 based 3D printer controller.


As of this shot, I have not yet wired it.  Nor have I installed the analog components (power supply, heater drivers, pullup resistors, filter capacitors, etc...).  It is also missing the connector for the extruder stepper motor. 

As I described in my previous post, my motor control design is based on Adafruit's Motor Shield V2.3.  For my prototype... well... I'm using their shield, pilfered from one of my older robots. This fantastic design employs an NXP PCA9865 16 channel 12 bit PWM controller, intended to drive LEDs, but instead to  driving a pair of dual Mosfet H bridge TB6612FNG motor drivers.

The Library for this Shield works with the Teensy 3.1 just fine. (It is just I2C after all).

Ok... I'm off to wire this up... wish me luck.
 





 



Monday, 12 May 2014

Using the Arduino PID Library for position control of X and Y axis on RepScrap printer

I've updated the test code I'm using to manage my X and Y axis DC motor / linear encoder closed loop controller. 



I am currently using the Arduino PID Library by Brett Beauregard  for this, and having great success.  Videos to come tomorrow. 

I am *NOT* going to explain what PID is, or how PID works.... I couldn't possibly do it justice.  I'll simply point you to Brett's wonderful explanation:



In the following example, I set up two axis, X and Y, each using a DC motor run from the Adafruit Motor Shield V2.  This shield provides PWM control for up to four separate DC motors via I2C communications.

I then set up two Quadrature encoders, one for each axis, using the Hardware Interrupts 0 and 1 (Arduino digital pins 2 and 3) and high speed digital port reads for one half of each encoder, and then validate the state of the other phase pin of the encoder during the interrupt routine: 
Graciously borrowed from http://forum.arduino.cc/index.php?topic=41615.20;wap2

The ZERO endstop for each axis is set up using the Arduino PinChangeInterrupt library watching a pin attached to a photo-interrupter.


I would certainly accept any advice on a proper sequence to initialize each axis to the ZERO endstop.

Right now, I arbitrarily send the carriage forward for 100ms assuming this is enough time to get on the positive side of the endstop, if we were beyond it.  Then I set my current position to the maximum possible location, and start travelling back to the endstop, knowing that once I actually reach it, the interrupt routine will Zero out my position, and initialize my PID setpoint to zero as well, thus stopping travel at ZERO. 
Is there a more efficient way of doing this? 


Inside the loop portion of my code, I run the PID controls as per the library, providing motor speed control via the Adafruit motor class, and periodically check to see if both X and Y axis have reached their goal.  At which time, I randomly select a new target for each.  When I get to the real application of this, the random selection of X and Y axis targets will be replaced by GRBL coordinates. 


And without further ado, here is my working code for precise position control in X and Y axis using the Arduino PID library:

/***************************************************************************************
*  Lin_Enc_02.ino   05-12-2014   unix_guru at hotmail.com   @unix_guru on twitter
*  http://arduino-pi.blogspot.com
*
*  This sketch allows you to run two salvaged printer carriages for X/Y axis using their 
*  linear encoder strips for tracking. 
*  This example uses the Arduino PID Library found at:
*  https://github.com/br3ttb/Arduino-PID-Library/archive/master.zip
*
*  Hardware Interrupt 0 on Digital pin2 is used to determine X-Axis position
*  Hardware Interrupt 1 on Digital pin3 is used to determine Y-Axis position
*  PinchangeInterrupt is used to identify the Zero Endstop for X and Y axis

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

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <PID_v1.h> 
#include <PinChangeInt.h>


#define frontstop = 100                          // Right most encoder boundary
#define backstop = 3600                         // Left most encoder boundary


// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 

// Select which 'port' M1, M2, M3 or M4. In this case, M1
Adafruit_DCMotor *XaxisMotor = AFMS.getMotor(1);
Adafruit_DCMotor *YaxisMotor = AFMS.getMotor(2);


const int XaxisENCPinA = 2;                  // X-AXIS  encoder 1 on pins 2 and 4
const int XaxisENCPinB = 4;
const int XaxisENDSTOP = 10;               // Endstop photointerrupter for X-Axis
volatile double XaxisENCPos = 0;

const int YaxisENCPinA = 3;                  // Y-AXIS  encoder 2 on pins 3 and 5
const int YaxisENCPinB = 5;
const int YaxisENDSTOP = 11;               // Endstop photointerrupter for Y-Axis
volatile double YaxisENCPos = 0;


double XaxisSpd,  YaxisSpd;                  // Carriage speed from 0-255
double XaxisPos, YaxisPos;                   // Current Carriage position

/*working variables for PID routines*/
// Tuning parameters
float KpX=0,  KpY=0;                          //Initial Proportional Gain 
float KiX=10, KiY=10;                         //Initial Integral Gain 
float KdX=0,  KdY=0;                          //Initial Differential Gain 

double XaxisSetpoint, YaxisSetpoint;      // Taget position for carriage

// Instantiate X and Y axis PID controls
PID XaxisPID(&XaxisPos, &XaxisSpd, &XaxisSetpoint, KpX, KiX, KdX, DIRECT); 
PID YaxisPID(&YaxisPos, &YaxisSpd, &YaxisSetpoint, KpY, KiY, KdY, DIRECT); 
const int sampleRate = 1; 

long int reportTime;

void setup() {
  Serial.begin(115200);
  Serial.println("Linear Encoder Test  05-12-2014");

  AFMS.begin();  // Set up Motors
  
  XaxisMotor->run(BACKWARD);                  // Bring carriage to home position. 
  XaxisMotor->setSpeed(70); 
  delay(100);                                                // Get endstop limiter working here
  XaxisMotor->run(FORWARD);                    // Bring carriage to home position. 
  XaxisMotor->setSpeed(0); 
  

  YaxisMotor->run(BACKWARD);                  // Bring carriage to home position. 
  YaxisMotor->setSpeed(70); 
  delay(100);                                                // Get endstop limiter working here
  YaxisMotor->run(FORWARD);                    // Bring carriage to home position. 
  YaxisMotor->setSpeed(0); 
  
  attachInterrupt(0, doXaxisENC, CHANGE);     // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(1, doYaxisENC, CHANGE);     // encoder pin on interrupt 1 (pin 3)

  PCintPort::attachInterrupt(XaxisENDSTOP,doXaxisEndstop,FALLING); //X-axis Endstop ISR
  PCintPort::attachInterrupt(YaxisENDSTOP,doYaxisEndstop,FALLING); //Y-axis Endstop ISR

  randomSeed(analogRead(0));                          // Used to select random setpoints for testing

  XaxisPID.SetMode(AUTOMATIC);                //Turn on the PID loop 
  XaxisPID.SetSampleTime(sampleRate);         //Sets the sample rate 

  YaxisPID.SetMode(AUTOMATIC);                //Turn on the PID loop 
  YaxisPID.SetSampleTime(sampleRate);         //Sets the sample rate 

  reportTime = millis()+2000;
}

void loop() {
uint8_t oldSREG = SREG;                           // Store interrupt status register

  cli();
  XaxisPos = XaxisENCPos;  
  YaxisPos = YaxisENCPos;
  SREG = oldSREG;                                    // Restore interrupt status register
  

  // Temporary to create random X and Y axis setpoints for testing
  if(millis() > reportTime) {                               // Only validate this every 2 seconds
    if(XaxisPos == XaxisSetpoint && YaxisPos == YaxisSetpoint) {   
      // If both X-axis and Y-axis have reached their target - get new targets
      XaxisSetpoint =  random(200,3500);             // Keep target within bounds of Endpoints
      YaxisSetpoint =  random(200,3500);             // Keep target within bounds of Endpoints
    }    
    reportTime = millis()+2000;
}
  
  
  // Manage X-axis positioning
  XaxisPID.Compute();                          //Run the PID loop 
  if(XaxisSetpoint < XaxisPos) XaxisMotor->run(BACKWARD);  // Determine direction of travel
  else  XaxisMotor->run(FORWARD);      
  XaxisMotor->setSpeed(XaxisSpd);              // Apply PID speed to motor


  // Manage Y-axis positioning
  YaxisPID.Compute();                          //Run the PID loop 
  if(YaxisSetpoint < YaxisPos) YaxisMotor->run(BACKWARD);  // Determine direction of travel
  else  YaxisMotor->run(FORWARD);      
  YaxisMotor->setSpeed(YaxisSpd);              // Apply PID speed to motor

}


/***************************************************************************************
The following code was taken from   http://forum.arduino.cc/index.php?topic=41615.20;wap2
to utilize the fast port based encoder logic.  Thank you Lefty!
please go there for a full explanation of how this works.  I have truncated the comments 
here for brevity.

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

void doXaxisENC() {                                  // ************** X- AXIS ****************
    if (PIND & 0x04) {                              // test for a low-to-high interrupt on channel A, 
        if ( !(PIND & 0x10)) {                      // check channel B for which way encoder turned, 
           XaxisENCPos = ++XaxisENCPos;               // CW rotation
          }
        else {
           XaxisENCPos = --XaxisENCPos;               // CCW rotation
          }
    }
    else {                                          // it was a high-to-low interrupt on channel A
        if (PIND & 0x10) {                          // check channel B for which way encoder turned, 
           XaxisENCPos = ++XaxisENCPos;               // CW rotation
           }
        else {
           XaxisENCPos = --XaxisENCPos;               // CCW rotation
        }
     }
}                                                   // End of interrupt code for encoder #1


                                                   
void doYaxisENC(){                                  // ************** X- AXIS ****************
  if (PIND & 0x08) {                                // test for a low-to-high interrupt on channel A, 
     if (!(PIND & 0x20)) {                          // check channel B for which way encoder turned, 
      YaxisENCPos = ++YaxisENCPos;                  // CW rotation
     }
     else {
      YaxisENCPos = --YaxisENCPos;                  // CCW rotation
     }
  }
  else {                                            // it was a high-to-low interrupt on channel A
     if (PIND & 0x20) {                             // check channel B for which way encoder turned, 
      YaxisENCPos = ++YaxisENCPos;                  // CW rotation
      }
     else {
      YaxisENCPos = --YaxisENCPos;                  // CCW rotation
     }
  }
}                                                   // End of interrupt code for encoder #2


void doXaxisEndstop() {
  XaxisENCPos=0;                                    // X-Axis Endstop indicates ZERO position 
}

void doYaxisEndstop() {
  YaxisENCPos=0;                                    // Y-Axis Endstop indicates ZERO position 
}

            https://github.com/michaeljball/RepScrap

Updated diagram for reference:



References:

DIYDrones: Tutorial series for new Arduino PID library
http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/
http://robotics.stackexchange.com/questions/1232/how-can-i-use-the-arduino-pid-library-to-drive-a-robot-in-a-straight-line
Tim Wescott's PID without a PHD
http://abigmagnet.blogspot.ca/2008/10/dc-motor-control-part-one.html
http://www.pdx.edu/nanogroup/sites/www.pdx.edu.nanogroup/files/2013_Arduino%20PID%20Lab_0.pdf

https://www.youtube.com/watch?v=ZZYgZjMnGXU
https://www.youtube.com/watch?v=wbmEUi2p-nA
http://blog.solutions-cubed.com/pid-motor-control-with-an-arduino/
http://forum.arduino.cc/index.php/topic,45169.0.html

http://playground.arduino.cc/Code/PIDLibrary
http://playground.arduino.cc/Code/PIDAutotuneLibrary

Arduino Playground: PinChangeInterrupt Library
https://code.google.com/p/arduino-pinchangeint/downloads/list

LetsMakeRobots: PID Control by Big Face
LetsMakeRobots: PID Tutorials for Line Following by Enigmerald
LetsMakeRobots: PID without a PHD by BDK6
LetsMakeRobots: Using Motor Encoders to Control Speed by Oddbot