Hi all,
I've got quite far with this problem but I seem to have come up against a bit of a wall that I can't get past... The task is simple and uses two Teensy 3.2 Arduinos to test some code:
Arduino 1 (Transmitter) - Read a potentiometer and convert the input to a square wave pulse on one of the output pins between around 122 and 2445Hz to simulate 10-200mph as read by a gearbox 17 tooth wheel
Arduino 2 (Receiver) - To read the pulse rate and convert into a speed value that can be displayed using a stepper motor.
The code I'm using for the transmitter:
#include <AnalogSmooth.h>
/* 2126mm per tyre revolution = 470 revs per km
diff ratio 3.42 so 1607 revs per km on gearbox = 1.6074 revs per m
So 10mph = 4.4704 m/s = *3.42 diff ratio = 7.19 revs/s = 122.23 pulses /s (17 teeth on gearbox wheel) = interval time of 8.181ms = 8181
200mph = 89.408 m/s = 42.0545 revs/s *3.42 diff ratio = 143.826 GB revs/s = 2445.05 pulses /s = interval time of 0.4089ms = 409
*/
int sensorPin = A0; // select the input pin for the potentiometer
unsigned long potReading = 0; // variable to store the value coming from the sensor
unsigned long val = 0; //value to be used with map
const int speedled = 13; // the number of the LED pin //speed pulse
const int speedpin = 12; // the number of the pulse pin //speed pulse
int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW; // ledState used to set the LED
unsigned long currentMicros = 0;
unsigned long previousMicros = 0; // will store last time LED was updated
unsigned long interval = 500; // interval at which to blink (milliseconds
unsigned long time = 0;
unsigned long previousTime = 0; // will store last time Time was updated
unsigned long previousMillis = 0; // will store last time LED was updated
unsigned long Minterval = 50; // interval at which to blink (milliseconds
unsigned long Mtime = 0;
float damping_coefficient = 0.01;
float Hz = 0;
int i = 1;
//--------------------------------------
// Defaults to window size 10
AnalogSmooth as = AnalogSmooth();
// Window size can range from 1 - 100
AnalogSmooth as100 = AnalogSmooth(100);
//----------------------------------------
void setup()
{
Serial.begin(115200);
// Serial.println("Start...");
// set the digital pin as output:
pinMode(speedpin, OUTPUT);
pinMode(speedled, OUTPUT);
}
void loop()
{
potReading = as100.analogReadSmooth(sensorPin) / 10;
potReading = potReading * potReading;
potReading = potReading / 100;
unsigned long currentMillis = millis();
Mtime = currentMillis - previousMillis;
if (Mtime > Minterval)
{
//Tone Version (weird response)
//Hz = map(potReading, 104, 1, 122, 2445); // interval adjuster from .40ms to 8.18ms //8196 1169 //10465, 100, 8181, 409
//Serial.println(Hz);
//Count Version
//Serial.println(potReading);
interval = map(potReading, 104, 1, 8181, 409); // interval adjuster from .40ms to 8.18ms //8196 1169 //10465, 100, 8181, 409
previousMillis = currentMillis;
Hz = 1000000.0 / interval;
Serial.println(Hz, 2);
Serial.println(interval);
}
//Tone Version
//tone(speedpin,Hz);
//Count Version
currentMicros = micros();
time = currentMicros - previousMicros;
if (time > interval)
{
ledState = !ledState; // 1 -> 0 -> 1 -> 0 etc
digitalWrite(speedpin, ledState);
previousMicros = currentMicros;
//digitalWrite(speedled, ledState);
}
}
The code I'm using for the receiver:
#include <AccelStepper.h>
// Define some steppers and the pins the will use
AccelStepper stepper1(AccelStepper::DRIVER, 5, 6);
const int RESET = 18; // pin for RESET
//------------------------------------------
volatile unsigned long VSS_count = 0;
unsigned long VSS_prior_count = 0;
int pin_VSS = 14;
void pulse() {
VSS_count = VSS_count + 1;
}
int SPEED_MPH;
int SPEED_STEPS;
int SPEED_SEND;
int currentMillis;
unsigned long lastMillis;
unsigned long VSS_new_count;
int teeth = 17;
float diffRatio = 3.42;
int WheelCirc = 2126; //mm
float toothDistance = (1.0 / (teeth));
float disttravelled = WheelCirc / diffRatio;
unsigned long elapsedTime;
unsigned long speedRaw;
int pulsegroup = 0;
unsigned long time;
//--------------------------------------------------
void setup()
{
pinMode(RESET, OUTPUT);
digitalWrite(RESET, LOW);
delay(1); // keep reset low min 1ms
digitalWrite(RESET, HIGH);
stepper1.setMaxSpeed(10000.0);
stepper1.setAcceleration(50000.0);
stepper1.runToNewPosition(3780);
stepper1.runToNewPosition(0);
//---------------------------------------------------
toothDistance = toothDistance * disttravelled;
//---Speed Input Count-----------------------------------
pinMode(pin_VSS, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pin_VSS), pulse, RISING);
NVIC_SET_PRIORITY(IRQ_PORTA, 0);
//---------------------------------------------------
}
void loop() {
noInterrupts ();
VSS_new_count = VSS_count;
interrupts ();
time = millis();
pulsegroup = VSS_new_count - VSS_prior_count;
if (pulsegroup > 9) {
elapsedTime = (time - lastMillis);
speedRaw = ((VSS_new_count - VSS_prior_count) * 60 * 1000 / (toothDistance * elapsedTime)) / 10;
VSS_prior_count = VSS_new_count;
lastMillis = time;
}
SPEED_STEPS = map(speedRaw, 10, 200, 0, 3780);
stepper1.moveTo(SPEED_STEPS);
stepper1.run();
}
Here's a video using the current setup on the transmitter (counting micros and changing pin state): VIDEO
I have also tried the other code currently deactivated where I use the tone() function and that seems to produce a more stable pointer, but it is less responsive - it sits still, then jumps quickly to the next position around 30-50 degrees away but the pot is being rotated smoothly.
So I have two problems with this that I'm not sure how to solve:
Problem 1) The pointer obviously isn't following the pot as the pot is linear and the change in frequency required is exponential. I have tried to square the pot input which has helped but the pointer still responds to low speed in much higher resolution than high speed so something still isn't set right.
Problem 2) Either the pulses aren't being generated uniformly, or the receiver isn't interpreting them properly. I don't have an oscilloscope so I can't check which side is causing the issue but I suspect it's the transmitter.