Monday, 24 April 2017

Arduino, Motion Control and Encoders

I took a failed Canon Pixma all-in-one inkjet apart in order to see how it was engineered. I also extracted some of the mechanics so I could learn a bit more about motion control in the real world. This post is about that exploration. I was primarily interested in the printhead carriage, as it has a feedback loop to provide information back about the speed of the carriage and which direction it is travelling in.

The printhead carriage itself is little more than some mechanics in the form of a sliding assembly that holds the printhead, a DC motor driving a belt, an optical strip and a pair of optical sensors and an LED.




The optical encoder strip is just a series of lines printed on a clear plastic strip. The image below shows the right hand side of the strip, with manufacturer details. At this point in time, I'm not sure what the resolution of the strip is, but it's higher than the 300dpi that I attempted to scan it at!


The strip and sensors make up an incremental encoder - that is, it tells you relative measurements of how much movement and in which direction. If you want to know where you are, you have to know the starting point first. If you want to know a bit more about different kinds of encoders, how they work and how to interpret their output, you can read Machine Design's Basics of Rotary Encoders: Overview and New Technologies, National Instrument's Encoder Measurements: How-To Guide, and the Encoder Primer (pdf!) which covers a number of different types of position feedback.

In order to get data back from the carriage, I needed to figure out the wiring for the optical encoder, which has 6 pins. This encoder takes the form of a package with an IR LED, and two IR sensors. The LED shines through the optical strip onto the two IR sensors, so we can figure out which side the LED is on by the fact there's only two connections for it.

The other four connections were figured out by powering up the printer and monitoring the voltages on the pins. Moving the carriage by hand allowed me to figure out which pins were outputs. The IR sensors want 3.3V and ground, and provide two quadrature outputs. On the end of the original flexible cable, this would look like:

And the pinout for this would be

PinConnection
11Q1 Output
123.3V
13Q2 Output
14/15GND

However, I don't have a suitable connector for the end of the flexible cable, mostly because removing through hole parts from a multilayer board is a pain. Utilising a different cable is simply enough, as we can solder directly to the board.

Knowing that the wiring for the sensor on the printhead was fairly easy. I worked on getting the optical sensors working, with the aid of Paul Stoffregen's Encoder library. I had a basic setup of the carriage, a Seeeduino Lite (Arduino Leonardo clone) as the controller and MAX7219 7 segment LED display for output. The majority of the code ended up dealing with formatting for the 7 segment display! The resulting test code looks like the following:


/* Connections:
 * Encoder 1 to pin 2
 * Encoder 2 to pin 3
 * VCC to 3.3v, GND to GND
 */

#define ENCODER_USE_INTERRUPTS

#include "LedControl.h"
#include <Encoder.h>
Encoder myEnc(2, 3); // INT1, INT2

// Din, Clk, CS
LedControl lc=LedControl(11,12,13,1);

int counter=0;

void setup() {
  Serial.begin(250000);
  
  lc.shutdown(0,false);
  lc.setIntensity(0,8);   // Moderate Brightness
  lc.clearDisplay(0);     // Clear display
}

/* Read counter and display it */
void loop() {
  counter=myEnc.read();
  showCount();
}

/* Show count on 7-seg */
void showCount(){
  char buff[8];
  
  istr(counter,buff);  // Convert to 7 seg data
  for (char i=0; i<8;i++) {
    lc.setRow(0,7-i,buff[i]);
  }
}

// Convert int into 7 seg raw data.
void istr(int i, char *buf) {
  for (char cnt=0;cnt<8;cnt++) buf[cnt]=0;
  
  char *p = &buf[7];
  int x = i;

  do {
    *(p--) = pgm_read_byte_near(charTable + abs(i%10));
    i /= 10;
  } while (i);

  if (x < 0) {
    *(p--) = B00000001;
  }
}

Hooking this all up and applying power to the Seeduino Lite results in a nice neat number on the display that changes as I move the carriage around by hand. A quick hint - if the encoder seems to run the wrong way, you can switch the connections to have it count in reverse direction. This way I ended up with the counter being at minimum at the right hand side, and at maximum at the left hand side.

Once the code is running, I can move the carriage by hand and I get the following result:


Based on the fact that the carriage has movement of  about 285mm, and the count end-to-end of the encoder seems to give me about 6700 counts (the carriage was not fully home in the animation above). This would put the resolution of the strip and sensors in the range of about 236 counts per cm or about 600 counts per inch.

So far I have a solid foundation in tracking where the carriage is, which means I can work towards having closed loop feedback. One of the challenges I face is the fact that at power up, the carriage could be at any position -  I need a way of taking the carriage to a known position!

Coming up soon, the challenges with PID and H bridges...


No comments:

Post a Comment