- Joined
- May 13, 2021
- Messages
- 26
A while back I posted a question on why my Rube Goldberg contraption wasn't cutting spirals (here). I learned that I need to move the table while I rotate the piece, so I went on a mission to learn how to do that. Since, at the time, I didn't know the proper phrases for what I was looking for, my google-fu pretty much sucked and I wasn't really finding anything that I could apply. The mechanical examples were interesting, but I would be locked into certain gear ratios and I saw a couple of videos of an electronic "transmission", but no details were exposed. It was at this point that my ignorance required that I get some education.
First, I got a Raspberry Pi and started doing some tutorials in general programming.
Then I got some Pi Picos.
Then I got an Arduino Uno (rev 3). I kind of settled in on this micro controller to concentrate on more in-depth learning.
I learned of a thing called an Optical Digital Encoder, for transmitting the turns of the table crank to somewhere.
I learned about stepper motors and all that was involved with utilizing them.
I copied example code and tried to Frankenstein something to where the stepper would spin at some ratio to the encoder input. Of course this resulted in some failure and I even smoked a couple of boards. The best way to learn something is to figure out why it's not working. As of today, I think I've made a lot of progress in both C programming and properly understanding and assembling the electronic bits.
At this point, I have the ratio I needed for the specific cutting project, but it's hard coded. Now I want to expand on this "electronic transmission" and make it more generic so I can input the cutting angles I need from a user interface. At this moment I'm learning how to program LCD screens and accepting input from a keypad.
Here is my working proof-of-concept so far.
That tension spring works like crap. It doesn't keep the belt tight enough to even overcome the out-of-roundness from being shipped. Since then I ditched that and just tightened it by hand and tightened the clamps.
Strapping the motor to the table works out well. I can adjust it to take up the belt slack if I need to rotate the head back.
Missing: the pic of the power supply. I've switched from the original Arduino Uno to an Arduino Nano. Same pins and stuff, just smaller.
Here is my code so far:
/*
The encoder portion of this code is lifted from MoThunderz at https://github.com/mo-thunderz/RotaryEncoder.
I learned a lot from him.
*/
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
// Define rotary encoder pins
#define ENC_A 2
#define ENC_B 3
#define DirPin 6
#define PulsePin 7
#define StepsToTake 16 // This is the "factor" in determining the ratio of input to output
//for 0.33" in the x direction, the turntable will turn 90º giving me my 23º spiral
unsigned long _lastIncReadTime = micros();
unsigned long _lastDecReadTime = micros();
int _pauseLength = 25000;
int _fastIncrement = 10;
volatile int Direction = 0;
volatile int counter = 0;
LiquidCrystal_I2C lcd(0x27,20,4); //i2c addr, 20 chars, 4 lines
void setup() {
// Set encoder pins and attach interrupts
pinMode(ENC_A, INPUT_PULLUP);
pinMode(ENC_B, INPUT_PULLUP);
pinMode(DirPin, OUTPUT);
pinMode(PulsePin, OUTPUT);
attachInterrupt(digitalPinToInterrupt(ENC_A), read_encoder, HIGH);
attachInterrupt(digitalPinToInterrupt(ENC_B), read_encoder, HIGH);
// Start the serial monitor to show output
Serial.begin(115200);
lcd.init();
lcd.init(); //dunno why I have to do this twice
lcd.backlight();
}
void loop() {
static int lastCounter = 0;
// If count has changed print the new value to serial
if(counter != lastCounter){
Serial.println(counter);
lastCounter = counter;
}
lcd.setCursor(0,0);
lcd.print("Encoder: ");
lcd.setCursor(9,0);
lcd.print(counter);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print("Stepper: ");
lcd.setCursor(9,1);
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read()); //still working on how to get and display the number of turns the stepper is taking
}
lcd.print(counter);
lcd.print(" ");
}
void read_encoder() {
// Encoder interrupt routine for both pins. Updates counter
// if they are valid and have rotated a full indent
static uint8_t old_AB = 3; // Lookup table index
static int8_t encval = 0; // Encoder value
static const int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // Lookup table
old_AB <<=2; // Remember previous state
if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B
encval += enc_states[( old_AB & 0x0f )];
// Update counter if encoder has rotated a full indent, that is at least 4 steps
if( encval > 3 ) { // Four steps forward
Direction = 1;
int changevalue = 1;
if((micros() - _lastIncReadTime) < _pauseLength) {
// changevalue = _fastIncrement * changevalue;
}
_lastIncReadTime = micros();
counter = counter + changevalue; // Update counter
encval = 0;
sendPulseToStepper(Direction);
}
else if( encval < -3 ) { // Four steps backward
Direction = 0;
int changevalue = -1;
if((micros() - _lastDecReadTime) < _pauseLength) {
//changevalue = _fastIncrement * changevalue;
}
_lastDecReadTime = micros();
counter = counter + changevalue; // Update counter
encval = 0;
sendPulseToStepper(Direction);
}
}
void sendPulseToStepper(bool Direction){
digitalWrite(DirPin, Direction);
for (int x = 0; x < StepsToTake; x++){
digitalWrite(PulsePin, HIGH);
delayMicroseconds(10);
digitalWrite(PulsePin, LOW);
delayMicroseconds(10);
}
}
In my research into all this, I did run across electronic lead screws for lathes. That's a really similar situation to what I need. I actually ended up buying and implementing Clough42's Electronic Lead Screw for my lathe! However, C++ is definitely gibberish to me so no help (yet) in trying to implement his algorithms.
Anyway, I'm making incremental progress, but my old brain is resistant to accepting anything new, but I'm forcing it into submission with lots of coffee.
Any comments are welcome! I don't know what I don't know I don't know.
First, I got a Raspberry Pi and started doing some tutorials in general programming.
Then I got some Pi Picos.
Then I got an Arduino Uno (rev 3). I kind of settled in on this micro controller to concentrate on more in-depth learning.
I learned of a thing called an Optical Digital Encoder, for transmitting the turns of the table crank to somewhere.
I learned about stepper motors and all that was involved with utilizing them.
I copied example code and tried to Frankenstein something to where the stepper would spin at some ratio to the encoder input. Of course this resulted in some failure and I even smoked a couple of boards. The best way to learn something is to figure out why it's not working. As of today, I think I've made a lot of progress in both C programming and properly understanding and assembling the electronic bits.
At this point, I have the ratio I needed for the specific cutting project, but it's hard coded. Now I want to expand on this "electronic transmission" and make it more generic so I can input the cutting angles I need from a user interface. At this moment I'm learning how to program LCD screens and accepting input from a keypad.
Here is my working proof-of-concept so far.
That tension spring works like crap. It doesn't keep the belt tight enough to even overcome the out-of-roundness from being shipped. Since then I ditched that and just tightened it by hand and tightened the clamps.
Strapping the motor to the table works out well. I can adjust it to take up the belt slack if I need to rotate the head back.
Missing: the pic of the power supply. I've switched from the original Arduino Uno to an Arduino Nano. Same pins and stuff, just smaller.
Here is my code so far:
/*
The encoder portion of this code is lifted from MoThunderz at https://github.com/mo-thunderz/RotaryEncoder.
I learned a lot from him.
*/
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
// Define rotary encoder pins
#define ENC_A 2
#define ENC_B 3
#define DirPin 6
#define PulsePin 7
#define StepsToTake 16 // This is the "factor" in determining the ratio of input to output
//for 0.33" in the x direction, the turntable will turn 90º giving me my 23º spiral
unsigned long _lastIncReadTime = micros();
unsigned long _lastDecReadTime = micros();
int _pauseLength = 25000;
int _fastIncrement = 10;
volatile int Direction = 0;
volatile int counter = 0;
LiquidCrystal_I2C lcd(0x27,20,4); //i2c addr, 20 chars, 4 lines
void setup() {
// Set encoder pins and attach interrupts
pinMode(ENC_A, INPUT_PULLUP);
pinMode(ENC_B, INPUT_PULLUP);
pinMode(DirPin, OUTPUT);
pinMode(PulsePin, OUTPUT);
attachInterrupt(digitalPinToInterrupt(ENC_A), read_encoder, HIGH);
attachInterrupt(digitalPinToInterrupt(ENC_B), read_encoder, HIGH);
// Start the serial monitor to show output
Serial.begin(115200);
lcd.init();
lcd.init(); //dunno why I have to do this twice
lcd.backlight();
}
void loop() {
static int lastCounter = 0;
// If count has changed print the new value to serial
if(counter != lastCounter){
Serial.println(counter);
lastCounter = counter;
}
lcd.setCursor(0,0);
lcd.print("Encoder: ");
lcd.setCursor(9,0);
lcd.print(counter);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print("Stepper: ");
lcd.setCursor(9,1);
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read()); //still working on how to get and display the number of turns the stepper is taking
}
lcd.print(counter);
lcd.print(" ");
}
void read_encoder() {
// Encoder interrupt routine for both pins. Updates counter
// if they are valid and have rotated a full indent
static uint8_t old_AB = 3; // Lookup table index
static int8_t encval = 0; // Encoder value
static const int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; // Lookup table
old_AB <<=2; // Remember previous state
if (digitalRead(ENC_A)) old_AB |= 0x02; // Add current state of pin A
if (digitalRead(ENC_B)) old_AB |= 0x01; // Add current state of pin B
encval += enc_states[( old_AB & 0x0f )];
// Update counter if encoder has rotated a full indent, that is at least 4 steps
if( encval > 3 ) { // Four steps forward
Direction = 1;
int changevalue = 1;
if((micros() - _lastIncReadTime) < _pauseLength) {
// changevalue = _fastIncrement * changevalue;
}
_lastIncReadTime = micros();
counter = counter + changevalue; // Update counter
encval = 0;
sendPulseToStepper(Direction);
}
else if( encval < -3 ) { // Four steps backward
Direction = 0;
int changevalue = -1;
if((micros() - _lastDecReadTime) < _pauseLength) {
//changevalue = _fastIncrement * changevalue;
}
_lastDecReadTime = micros();
counter = counter + changevalue; // Update counter
encval = 0;
sendPulseToStepper(Direction);
}
}
void sendPulseToStepper(bool Direction){
digitalWrite(DirPin, Direction);
for (int x = 0; x < StepsToTake; x++){
digitalWrite(PulsePin, HIGH);
delayMicroseconds(10);
digitalWrite(PulsePin, LOW);
delayMicroseconds(10);
}
}
In my research into all this, I did run across electronic lead screws for lathes. That's a really similar situation to what I need. I actually ended up buying and implementing Clough42's Electronic Lead Screw for my lathe! However, C++ is definitely gibberish to me so no help (yet) in trying to implement his algorithms.
Anyway, I'm making incremental progress, but my old brain is resistant to accepting anything new, but I'm forcing it into submission with lots of coffee.
Any comments are welcome! I don't know what I don't know I don't know.
Last edited: