DIY kz1000 stepper tachometer
- weeZee
-
Topic Author
- Offline
- User
- Posts: 81
- Thanks: 22
DIY kz1000 stepper tachometer
01 Oct 2018 10:51
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
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.
- weeZee
-
Topic Author
- Offline
- User
- Posts: 81
- Thanks: 22
Re: DIY kz1000 stepper tachometer
01 Oct 2018 10:52Code:
#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.
- weeZee
-
Topic Author
- Offline
- User
- Posts: 81
- Thanks: 22
Re: DIY kz1000 stepper tachometer
01 Oct 2018 10:55
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.