Hello,
I'm working on a demo P+I tacho-generator based control system using an Uno, 2x 540 motôrs (one driven, one as an rpm to V transducer with the motor voltage sensed via a potential divider made up of 2x 10K resistors) and a 60A radio control ESC. The motor is being driven from a 7V 2.5A PSU whilst the Uno is being powered from USB - all the earths are common (motor / ESC / tacho-gen / PSU / USB).
The system is fairly simple - I'm reading a a set-point from a 4K7 pot, reading in the voltage off the motor, calculating the error then using the SERVO library to output a PWM signal to the ESC, which drives the motor. I'm also calculating the summed error and feeding integral action into the mix, as well.
Everything seems to be going fine, but every thirty seconds, the pin the sensing motor (i.e. the tacho-gen via the potential divider) is connected to resets to zero, throwing the whole system back to the start. The Uno isn't resetting, as I'm using the serial monitor to log the time, PV, SP, Error and CV and it's only the PV (i.e. the tacho-gen output) that falls to zero; the time (from millis()) keeps counting up as expected.
I've connected a DVM across the tacho-gen and have determined that it's not the culprit - it's generating about 1.5-2V in the speed range I'm testing at and doesn't suddenly drop out or anything.
I've read that some PC applications can cause the Arduino to reset by sending query packets out onto the USB, but I'm fairly sure that's not what's happening here, as the Uno millis() doesn't reset. I'm sure I read somewhere that the Arduino ADC powers down or resets or something after some time period - my SP pot doesn't fall to zero, though, only the tacho-gen feed.
Every 30 seconds like clockwork...there's nothing in my code that uses that time period, unless its in the servo library...any ideas what it might be?
Thanks for any suggestions ![]()
#include <Servo.h>
const int pinESC = 9;
const int pinSP = A0;
const int pinPV = A1;
const int pinLED_G = 3;
const int pinLED_Y = 4;
Servo myservo; //create servo object to control the ESC
int iSP = 0;
int iPV_raw = 0; //raw ADC value
int iPV = 0; //average PV value
int iErr = 0;
int iCV = 0;
int iSumErr = 0;
unsigned long lTimer; //logging timer
unsigned long iTimer; //integral timer
unsigned long sTimer; //stdby timer
unsigned long fTimer; //flash timer
int Tl = 100; //logging time period
int Ti = 100; //integral time period
int Tf = 500; //flash time period
int Ts = 5000; //stdby time period
float Ki = 0.005; //integral gain
float Kp = 0.4; //proportional gain
int iArrMax = 100; //averaging filter sample size
int iIndexPV = 0;
int iSumPV = 0;
int arrPV[100];
bool bStdby = false;
bool bFlash = false;
void setup() {
Serial.begin(9600);
pinMode(pinPV,INPUT); //PV : tachogen voltage
pinMode(pinSP,INPUT); //SP : right hand pot
pinMode(pinLED_G,OUTPUT);
pinMode(pinLED_Y,OUTPUT);
//initialise the PV array
for(int i = 0 ; i < 100 ; i++) {
arrPV[i] = 0;
}
myservo.attach(9); //attaches the ESC on pin 9 to the servo object
//Serial.print("ConfigESC");
//configESC(); //goes through what's possibly the setup routine for the ESC
//Serial.println("Done");
iTimer = millis();
lTimer = millis();
sTimer = millis();
fTimer = millis();
}
void loop() {
iSP = analogRead(pinSP);
iSP = map(iSP,15,1013,0,1023); // create deadzones at either extreme
iSP = max(iSP,0);
iSP = min(iSP,1023);
//recursive filter for PV
iSumPV -= arrPV[iIndexPV]; // subtract the PV from 100 samples ago - modulo the (index + 1) with 100 so 100 = 0
arrPV[iIndexPV] = analogRead(pinPV); // put the current reading in the array
iSumPV += arrPV[iIndexPV]; // add the current PV to the running sum
iIndexPV++; // increment the array index
if(iIndexPV >= iArrMax) {
iIndexPV = 0; // reset the array index
}
iPV = iSumPV / iArrMax; // calculate the average PV value
//end of recursive filter for PV
iErr = iSP - iPV;
//Integral Action
if(millis() >= (iTimer + Ti)) {
iSumErr += iErr;
iTimer = millis(); //reset the integral timer
}
iCV = (Kp * iErr) + (Ki * iSumErr); //calculate P+I control action
iCV = min(iCV,1023); //limit iCV to < 1024
iCV = max(iCV,0); //limit iCV to > -1
iCV = map(iCV,0,1023,90,180);
if((millis() >= (lTimer + Tl)) && (!bStdby)) {
Serial.print(millis());
dLog(iSP,false);
dLog(iPV,false);
dLog(iErr,false);
dLog(iCV,true);
lTimer = millis(); //reset the log timer
}
if(iSP > 0) {
digitalWrite(pinLED_G,HIGH);
//digitalWrite(pinLED_Y,LOW);
bStdby = false;
sTimer = millis();
//iAvgCnt = 0; //reset the PV average counter
}
if(millis() >= (sTimer + Ts)) {
if(iSP == 0) {
bStdby = true;
Serial.println("<<< Standby >>>");
myservo.write(90); //zero throttle
digitalWrite(pinLED_G,LOW);
digitalWrite(pinLED_Y,HIGH);
}
sTimer = millis();
}
if(millis() >= fTimer + Tf) {
bFlash = !bFlash;
fTimer = millis();
}
myservo.write(iCV);
//delay(10);
}
void dLog(int iSig, bool bEOL) {
digitalWrite(pinLED_Y,bFlash);
if(!bEOL) {
Serial.print("\t");
Serial.print(iSig);
} else {
Serial.print("\t");
Serial.println(iSig);
}
}
void configESC() {
digitalWrite(pinLED_Y,HIGH);
myservo.write(180); //full throttle
wait(3);
myservo.write(0); //full reverse throttle
wait(3);
myservo.write(90); //zero throttle
wait(3);
digitalWrite(pinLED_Y,LOW);
}
void wait(int seconds){
for(int a = 0;a < seconds;a++) {
Serial.print(".");
delay(1000);
}
}