Hey all,
Namaste. This community has been a great help over the past few weeks. I've gotten a printer carriage to move from position to position with pretty good performance.
At least, the performance is good most of the time. Sometimes the carriage slams into the limit of travel. Specifically, I think it ignores one or more I2C writes from master which should tell it to go to the desired position, and instead continues at a previously communicated speed and direction until it hits the wall. Testing this hypothesis, I figured that at higher speeds, I would have more encoder interrupts, and thus a higher chance of causing the carriage to run into the wall. It appears to be the case that higher speeds and longer travel distances (i.e. more interrupts) make this happen more often. It can happen at slow speeds too if you wait long enough. The position seems to be accurately counted throughout testing probably to within a line or two at 600 lpi as I am always able to go back to the initial position from power on with no visible position error. Paul's encoder library is pretty great!
I'm not too sure what the next step is from here. I would really prefer that there is zero chance of the carriage crashing in the middle of a performance or slurring the melody. I could use a second Atmega328P for handling motor and actuator control and then just leave the other one to solely count and communicate encoder lines. I plan on having 6 of these things sharing an I2C connections, so that would be 12 Atmega328Ps. That's not terrible cost-wise (I don't think), but I'm open for other suggestions. My schematic and code used in testing are below or attached:
Atmega328P Slave Code:
#include <PWMFreak.h>
#include <Wire.h>
#include <Encoder.h>
//#include <TimerOne.h>
#define RESOLUTION 100000
union Buffer
{
long longNumber;
byte longBytes[4];
};
Buffer position; // create an instance of Buffer
byte addr = 8;
Encoder myEnc(2, 3);
byte pluckPin = 4;
byte dampPin = 5;
byte PWMPin = 6;
byte DirPin = 7;
byte limPin = 8;
byte speed;
byte dir;
void setup() {
// Serial.begin(250000);
// Serial.println("Boot up");
Wire.begin(addr); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
Wire.onReceive(receiveEvent); // register event
pinMode(pluckPin, OUTPUT);
pinMode(dampPin, OUTPUT);
pinMode(DirPin, OUTPUT);
pinMode(PWMPin, OUTPUT);
pinMode(limPin, INPUT);
setPwmFrequency(6, 1);
}
void loop()
{
position.longNumber = myEnc.read();
}
void requestEvent()
{
Wire.write(position.longBytes, 4); // send requested bytes
}
void receiveEvent(int howMany) {
char act = 0;
while (Wire.available()) { // loop through all but the last
// Serial.print("Bytes available: "); Serial.println(Wire.available());
if (Wire.available() > 1) {
analogWrite(PWMPin, 0); // if the encoder interrupts this event handler but it gets this far, at least it stays put
act = Wire.read();
speed = Wire.read();
dir = Wire.read();
// Serial.print("act: "); Serial.print(act); Serial.print(", speed: "); Serial.print(speed); Serial.print(", dir: "); Serial.println(dir);
}
else {
act = Wire.read(); // receive byte as a character
// Serial.print("act: "); Serial.println(act);
}
}
switch (act) {
case 'p':
toggle(pluckPin);
// Serial.print("pluckPin state: "); Serial.println(digitalRead(pluckPin));
break;
case 'd':
toggle(dampPin);
// Serial.print("dampPin state: "); Serial.println(digitalRead(dampPin));
break;
case 's':
// Serial.print("Setting speed to : ");Serial.print(speed);Serial.print(" with direction: ");Serial.println(dir);
digitalWrite(DirPin, dir);
analogWrite(PWMPin, speed);
break;
case 'h':
// home();
default:
// Serial.print("It defaulted! act was: "); Serial.println(act);
break;
}
// Serial.println();
}
void toggle(byte pin) {
bool state = digitalRead(pin);
digitalWrite(pin, !state);
}
//void home() {
// Wire.end();
// digitalWrite(DirPin, LOW); analogWrite(PWMPin, 40);
// while(digitalRead(limPin) == false){delay(20);}
// analogWrite(PWMPin, 0); digitalWrite(DirPin, HIGH);
// myEnc.write(0);
// Wire.begin(addr);
//}
Teensy Master code: attached as Maestro.ino
DiddleyBow library to simplify Teensy Master Code: Attached as DiddleyBow.h and DiddleyBow.cpp
Schematic: attached, and hopefully shown below
Maestro.ino (6.71 KB)
DiddleyBow.h (1.72 KB)
DiddleyBow.cpp (2.75 KB)