DIY kz1000 stepper tachometer

More
01 Oct 2018 10:51 #791656 by weeZee
DIY kz1000 stepper tachometer was created by weeZee
Easier to link to a descriptive video, I had an Emgo stepper tach for a kz1000 in my z650.
Despite having a clean digital signal it never worked too well.
So I've put together an equivalent circuit that I could reprogram until it worked smoothly.
The stepper is a £4 32-step instrumentation stepper driven by a dedicated microstepper board, about £8


Please Log in or Create an account to join the conversation.

More
01 Oct 2018 10:52 #791657 by weeZee
Replied by weeZee on topic DIY kz1000 stepper tachometer
Code:
#include <AccelStepper.h> #include <FreqMeasure.h> #define SERIAL_BAUD 57600 // defined in several places #define DEBUG 1 #define STEPPER_DIR_PIN 5 #define STEPPER_STEP_PIN 6 #define DRIVER_NOSLEEP_PIN 7 #define FREQMEASURE_PIN 8 // for reference ICP1 is pin 8 #define DRIVER_FAULT_PIN 11 #define CONFIG 9 #define M0_PIN 12 #define M1_PIN 10 #define LED_PIN 13 #define STEPS 30 * 32 // 1/32 microstepping = 960 // FreqMeasure library signal input // #define CAPTURE_USE_TIMER1 // ICP1 is pin 8 // 230 deg full scale from 500rpm to 12000rpm in 20 deg increments. // 30*32 = 960 steps over 300 deg // 10 deg / 32 per microstep => 64 microsteps per 1k rpm => (64 microsteps)/1000 steps per rpm => (64 microsteps * 60 rpm)/1000 // 0.0135mV on volt sense pin on DRV8834 driver VREF pin, counterclockwise to decrease Vref // https://www.pololu.com/product/2134 // https://www.youtube.com/watch?feature=player_embedded&v=89BHS9hfSUk // M0 M1 Microstep Resolution // Low Low Full step // High Low Half step // Floating Low 1/4 step // Low High 1/8 step // High High 1/16 step // Floating High 1/32 step const byte WINDOW = 10; // rectangular smoothing window width, must be > 2 const float RPS2STEP = 3.81; //3.84; const long overfloNum = long(float(WINDOW) * float(F_CPU) * RPS2STEP); //uPCfreq; AccelStepper tachStepper(AccelStepper::DRIVER, STEPPER_STEP_PIN, STEPPER_DIR_PIN); int shiftIndex = WINDOW-2; int32_t avgFreq[WINDOW]; // be warned of rollover issues with long delays int32_t freq, lastFreq, newTarget = 0; void(* resetFunc) (void) = 0; // the reset function at address 0 void setup() { pinMode(LED_BUILTIN, OUTPUT); pinMode(DRIVER_NOSLEEP_PIN, OUTPUT); digitalWrite(DRIVER_NOSLEEP_PIN, LOW); // DRV8834 driver pinMode(DRIVER_FAULT_PIN, INPUT_PULLUP); pinMode(STEPPER_DIR_PIN, OUTPUT); pinMode(STEPPER_STEP_PIN, OUTPUT); pinMode(CONFIG, INPUT); // floating pinMode(M0_PIN, INPUT); // floating //pinMode(M0_PIN, OUTPUT); pinMode(M1_PIN, OUTPUT); //digitalWrite(M0_PIN, LOW); // set DRV8834 board to full steps digitalWrite(M1_PIN, HIGH); digitalWrite(DRIVER_NOSLEEP_PIN, HIGH); // wake DRV8834 driver // tachStepper.setMinPulseWidth(4); 250kHz for DRV8834, limited to 20us in AccelStepper @16MHz //tachStepper.setPinsInverted( bool directionInvert = false, bool stepInvert = false, bool enableInvert = false ) tachStepper.setPinsInverted(true, false, false); // cause I wired in the stepper backwards. tachStepper.setMaxSpeed(15000); tachStepper.setAcceleration(10000); tachStepper.runToNewPosition(30*32); tachStepper.runToNewPosition(-10); delay(150); // relax tachStepper.setCurrentPosition(0); // Serial.begin(SERIAL_BAUD); // Serial.println(F("Start")); // Serial.print(F("overfloNum: ")); // Serial.println(overfloNum); FreqMeasure.begin(); // prime the moving average LP filter for (shiftIndex = 0; shiftIndex <= (WINDOW-1); shiftIndex++){ while (FreqMeasure.available() == false) { } avgFreq[shiftIndex] = FreqMeasure.read(); freq += avgFreq[shiftIndex]; } shiftIndex = WINDOW-2; } void loop() { // moving window LP filter if (!digitalRead(DRIVER_FAULT_PIN)) { // Serial.println(F("FAULT")); resetFunc(); } // reset unit on driver fault if (FreqMeasure.available()){ lastFreq = freq; freq -= avgFreq[shiftIndex]; avgFreq[shiftIndex] = FreqMeasure.read(); //FreqMeasure.countToFrequency(rawFreq/WINDOW); freq += avgFreq[shiftIndex]; // replace array shuffling with a moving index if (shiftIndex >= (WINDOW - 1)){ shiftIndex = 0; } else { shiftIndex += 1; } newTarget = overfloNum/freq; if (newTarget > 32) { //8.333 newTarget -= 32; //8.333; // = 500rpm } else { newTarget = 0; } //Serial.println(newTarget); tachStepper.moveTo(newTarget); } else { tachStepper.run(); } }

Please Log in or Create an account to join the conversation.

More
01 Oct 2018 10:55 #791658 by weeZee
Replied by weeZee on topic DIY kz1000 stepper tachometer
The code used for testing the unit is bodged together, but I include it for reference.
Code:
#include <TimerOne.h> uint32_t rpm500[] = {120000, // 500rpm 60000, // 1000rpm 40000, // 1500rpm 30000, // 2000rpm 24000, 20000, // 3000rpm 17142, 15000, // 4000rpm 13333, 12000, // 5000rpm 10909, 10000, // 6000rpm 9230, 8571, // 7000rpm 8000, 7500, // 8000rpm 7058, 6666, // 9000rpm 6315, 6000, // 10000rpm 5714, 5454, // 11000rpm 5217, 5000}; // 12000rpm uint32_t rpm1000[] = {60000, // 1000rpm 30000, // 2000rpm 20000, // 3000rpm 15000, // 4000rpm 12000, // 5000rpm 10000, // 6000rpm 8571, // 7000rpm 7500, // 8000rpm 6666, // 9000rpm 6000, // 10000rpm 5454, // 11000rpm 5000}; // 12000rpm from uS uint32_t rpm1000half[] = {30000, // 1000rpm 15000, // 2000rpm 10000, // 3000rpm 7500, // 4000rpm 6000, // 5000rpm 5000, // 6000rpm 4285, // 7000rpm 3750, // 8000rpm 3333, // 9000rpm 3000, // 10000rpm 2727, // 11000rpm 2500}; // 12000rpm from uS #define PWMpin 10 #define LEDpin1 7 #define LEDpin2 9 #define potPin A0 int invertDuty = 2*1024/3; void potSet() { // read the analog in value: int potValue = 0; long outputValue = 0; potValue = analogRead(potPin); // map it to the range of the analog out: outputValue = map(potValue, 0, 1023, 5000, 133333); Timer1.setPeriod(outputValue); Timer1.pwm(PWMpin, invertDuty); Timer1.pwm(LEDpin2, invertDuty); //Serial.println(outputValue); delay(5); } void predef(uint32_t r) { Timer1.setPeriod(r); Timer1.pwm(PWMpin, invertDuty); Timer1.pwm(LEDpin2, invertDuty); } void cycleRpm500() { for (int i = 0; i < 24; i++){ predef(rpm500[i]); delay(2500); } for (int i = 23; i >=0; i--){ predef(rpm500[i]); delay(2500); } } void cycleRpm1000() { for (int i = 0; i < 12; i++){ predef(rpm1000[i]); delay(2500); } for (int i = 11; i >=0; i--){ predef(rpm1000[i]); delay(2500); } } void calibrateRpm1000() { predef(rpm1000[0]); Serial.println(rpm1000[0]); delay(10000); predef(rpm1000[1]); Serial.println(rpm1000[1]); delay(5000); predef(rpm1000[3]); Serial.println(rpm1000[3]); delay(2500); predef(rpm1000[5]); Serial.println(rpm1000[5]); delay(2500); predef(rpm1000[7]); Serial.println(rpm1000[7]); delay(2500); predef(rpm1000[9]); Serial.println(rpm1000[9]); delay(2500); predef(rpm1000[11]); Serial.println(rpm1000[11]); delay(2500); } void rando() { int r = random(1,11); //Timer1.stop(); // Serial.print("random base:"); // Serial.println(rpm1000[0]); // Serial.print("random:"); // Serial.println(rpm1000[r]); for (int f = 10; f <= 500; f += 10) { // Serial.print("freq inc:"); // Serial.println(f); for (int i = 31250; i >= rpm1000[r]; i -= f) { //Serial.println(i); digitalWrite(PWMpin, HIGH); // digitalWrite(LEDpin1, HIGH); delayMicroseconds(i); digitalWrite(PWMpin, LOW); // digitalWrite(LEDpin1, LOW); delayMicroseconds(i); } //delay(2500); } //Timer1.restart(); } void rando2() { int i = rpm1000half[0]; int offset = 1250; do{ digitalWrite(PWMpin, HIGH); delayMicroseconds(i + offset); digitalWrite(PWMpin, LOW); delayMicroseconds(i + offset); } while (1); } void setup(void) { pinMode(PWMpin, OUTPUT); pinMode(LEDpin1, OUTPUT); pinMode(LEDpin2, OUTPUT); randomSeed(analogRead(0)); Timer1.initialize(100000); // 10Hz -> 250Hz (600rpm -> 12000rpm) // dutyCycle is approx 1/3 of cycle in ignition application Timer1.setPwmDuty(PWMpin, invertDuty); Serial.begin(57600); Serial.println("Start"); } void setNeedle6k(){ Timer1.setPeriod(10000); Timer1.pwm(PWMpin, invertDuty); Timer1.pwm(LEDpin2, invertDuty); delay(25000); } void loop() { //Serial.println("repeat"); //setNeedle6k(); calibrateRpm1000(); //rando(); // Timer1.stop(); // // for (int i = 0; i <= 10000; i++) { // digitalWrite(PWMpin, HIGH); //// digitalWrite(LEDpin1, HIGH); // delayMicroseconds(31250); // digitalWrite(PWMpin, LOW); //// digitalWrite(LEDpin1, LOW); // delayMicroseconds(31250); // } // // // delay(2500); // Timer1.restart(); // Timer1.setPeriod(60000); // Timer1.pwm(PWMpin, 1024/2); // delay(10000); } // digitalWrite(LEDpin1, HIGH); // digitalWrite(LEDpin2, LOW); // // for (int i = 133333; i >= 5000; i-=10){ // Timer1.setPeriod(i); // Timer1.pwm(PWMpin, invertDuty); // delay(5); // } // // for (int i = 5000; i <= 133333; i+=10){ // Timer1.setPeriod(i); // Timer1.pwm(PWMpin, invertDuty); // delay(5); // } // // digitalWrite(LEDpin1, LOW); // delay(150); // digitalWrite(LEDpin2, HIGH); //

Please Log in or Create an account to join the conversation.

Powered by Kunena Forum