Hi all.
I hope some of you could give me a hand with the code for my project. Any comments are welcome!
I have a rotating thing, and a thing than needs rotating by a user-selectable in:out ratio.
An electronic variable ratio gearbox if you will, but with no gears
The input doesn't rotate at a constant speed. It needs to be free to accellerate, decellerate, stop and start, change direction and the output needs to remain in sync.
So far I have a rotary encoder and a stepper motor which are matched to my speed and torque requirements.
So far, every pulse of the encoder is sent to the microstepping driver and it works great. Accurate and responsive and lovely.
By changing the microstepping I can halve/double the output speed as expected, but I need more flexibility.
-
I've ruled out expensive servo drives due to cost.
-
I'm happy to keep the drive open-loop - again due to cost/complexity
-
I've ruled out trying to build my own stepper driver with H-bridge (s) to achieve uber microstepping, because this would need it's own AVR and I'm trying to keep things simple/cheap. Also it blows my mind just thinking of it.
-
I've settled with the idea of keeping my minimum step as a 1/32, and I'm happy to keep track of the difference between required step and actual step and compensate that error whenever possible.
So for example, if my in/out divider requires me to make a 0.23 step for every one encoder pulse. I'm happy to count this value in a variable and make a step only when the sum exceeds 1, then take the 1 away and keep counting the difference. Kinda like an error buffer.
Likewise, if I need to make 1.34 of a step, I'm happy to make one full step and set the 0.34 aside and add the next remainder and so on, making a step when the error amount exceeds a 1.
How would I go about implementing this "error buffer" in code?
Here is what I have so far (it's basic):
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7); // 0x27 is the I2C bus address for an unmodified backpack
volatile long counter = 0; //This variable will increase or decrease depending on the rotation of encoder
int rotations = 0;
int dirPin = 8;
int stepperPin = 7;
void setup() {
 Serial.begin (9600);
 lcd.begin (16,2); // for 16 x 2 LCD module
 lcd.setBacklightPin(3,POSITIVE);
 lcd.setBacklight(HIGH);
 //Setting interrupts
 //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
 attachInterrupt(0, ai0, RISING);
 //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
 attachInterrupt(1, ai1, RISING);
Â
 pinMode(dirPin, OUTPUT);
 pinMode(stepperPin, OUTPUT);
}
void loop() {
 if (counter>=477) {
  rotations++;
  counter=0;
 }
Â
 if (counter<=-477) {
  rotations--;
  counter=0;
 }
 // Send the value of counter
 Serial.println (counter);
 lcd.setCursor(0,0);
 lcd.print(counter);
 lcd.print("  "); // clear line
 lcd.setCursor(0,1);
 lcd.print(rotations);
 lcd.print("  "); // clear line
}
void ai0() {
 // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
 // Check pin 3 to determine the direction
 if(digitalRead(3)==LOW) {
  counter++;
  step(true,1);
 }else{
  counter--;
  step(false,1);
 }
}
void ai1() {
 // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
 // Check with pin 2 to determine the direction
 if(digitalRead(2)==LOW) {
  counter--;
  step(false,1);
 }else{
  counter++;
  step(true,1);
 }
}
void step(boolean dir,int steps){
 digitalWrite(dirPin,dir);
 digitalWrite(stepperPin, HIGH);
 digitalWrite(stepperPin, LOW);
}
Thanks for any pointers!