Difference between revisions of "DIY - RPM and Temperature Data Logger"

From ItsQv
Jump to: navigation, search
(Introduction)
 
(37 intermediate revisions by the same user not shown)
Line 7: Line 7:
 
|-
 
|-
 
|  
 
|  
| align="right" width="50%" | DIY Test Tool
+
| align="right" width="50%" | DIY Arduino Tools!
 
|}
 
|}
 
+
<br>
 +
{{UnderConst}}
 +
<br>
 
== <br>Introduction ==
 
== <br>Introduction ==
  
Line 36: Line 38:
 
| align="center" | [[File:REG03.JPG|800px]]
 
| align="center" | [[File:REG03.JPG|800px]]
 
|-
 
|-
| align="center" | First flight set-up
+
| align="center" | First flight set-up bits
 
|}
 
|}
 
<br>
 
<br>
Line 58: Line 60:
 
<br><br>
 
<br><br>
  
'''Omron Relay''' - After trying many different software attempts to create a smooth pass-through mode for the signal from the flight controller directly to the ESC, I finally decided to use the normally closed side of a relay to accomplish this task. There are two reasons for this-
+
'''Omron Relay''' - After trying many different software attempts to create a smooth pass-through mode for the signal from the flight controller directly to the ESC, I finally decided to use the normally closed side of a relay to accomplish this task. There are few reasons for this-
 
<br>
 
<br>
 
: 1. If the board fails for some reason the relay will close to direct pass-through making it possible to continue flying the plane.
 
: 1. If the board fails for some reason the relay will close to direct pass-through making it possible to continue flying the plane.
 
: 2. Having a direct, hard wired pass-through makes it completely smooth which is important in how the regulated section of the software works.
 
: 2. Having a direct, hard wired pass-through makes it completely smooth which is important in how the regulated section of the software works.
 
: 3. Inexpensive ($1.79)
 
: 3. Inexpensive ($1.79)
<br><br>
+
<br>
  
'''HobbyWing RPM Sensor''' - I actually started with an early Eagle Tree unit that had an issue with how the power wires were from the factor - Black = Positive, Red = Negative. While looking for a replacement I found the HobbyWing version which according to my O-scope produces the same output. Bonus is they are less than a quarter of the price of the Eagle Tree units ($4.49)
+
'''HobbyWing RPM Sensor''' - I actually started with an early Eagle Tree unit that had an issue with how the power wires were from the factory - Black = Positive, Red = Negative (wtf?). While looking for another pre-built solution I found the HobbyWing version which according to my O-scope produces the same output. Bonus is they are less than a quarter of the price of the Eagle Tree units ($4.49)
 
<br><br>
 
<br><br>
  
Line 71: Line 73:
 
<br><br>
 
<br><br>
  
All together then, the parts for a single build cost me ~$18 plus any shipping.
+
All together then, the parts for a single build cost me about $18.
 
<br><br>
 
<br><br>
  
Line 122: Line 124:
 
| align="center" | Current board (bottom)
 
| align="center" | Current board (bottom)
 
|}
 
|}
 +
<br><br>
 +
 +
== Code, Use & Results ==
 +
 +
'''The Arduino code can be downloaded here-'''<br>
 +
 +
v16r2 - July 24, 2019 - <u>'''[http://www.itsqv.com/share/RPM_Regulator_v16r2.zip RPM_Regulator_v16r2.zip]'''</u>
 
<br>
 
<br>
  
<!--== Code ==
+
Below are some details of the major code sections:
 +
<br><br>
  
<code>
+
: '''Throttle Value & Percent'''<br>
/* adjustable variables for signal smoothing  and PID parameters */
+
: This section covers collecting the throttle-in PWM value (thrIn) using a PWM read library. I chose using this library approach as opposed to a simple "pulseIn" capture because it gives cleaner results. Added to this I am using an exponential smoothing filter to calm down the <i>jumpiness</i> of the input. In the last part of this I convert the throttle input to throttle percent for displaying in the data file.
int rpmRND = 25;                                          // rounding value for rpm signal (default 25)
+
<br>
int EFW = 10;                                            // exponential filter weight (default 10)
+
int EFWB = 20;                                            // exponential filter weight (default 20)
+
int PST = 50;                                            // PID sample time (default 50)
+
float kP = 0.07;                                          // PID proportional factor
+
float kI = 0.03;                                          // PID integral factor
+
float kD = 0;                                            // PID derivative factor
+
int avgN = 20;                                            // temperature average number (default 20)
+
int period = 200;                                        // data print period in ms (default 200)
+
float numpoles = 14;                                      // number of motors magnet poles
+
</code>
+
<br><br>-->
+
  
== Code ==
+
: '''Temperature Captures'''<br>
 +
: The two temperature probes are picked up using the analog inputs A0 & A1. The code which configures these two inputs for the data file is taken directly from a code snippet found at <u>[http://www.circuitbasics.com/arduino-thermistor-temperature-sensor-tutorial/ CircuitBasics.com]</u>. The output to the data file is given in degrees Fahrenheit but can be changed to degrees Celsius by commenting out the two lines where the conversion is made. In the latest code, v16r2, this is line 137 and line 142.
 +
<br>
  
Copy the following into a new Arduino sketch and load to the board-
+
: '''Throttle Pass-Through'''<br>
 +
: This piece of code takes the input from an RX channel and makes sure the pass-through relay is left in its normally closed state allowing a direct hardwire path between the throttle input and ESC output. It also holds the pass-through switch state at 0.
 
<br>
 
<br>
<nowiki>
 
/*
 
v15r1 - Added SPDT signal relay (mechanical) to get hard wired
 
pass-through and normally closed safety if there is a board fail.
 
*/
 
/*Project Details
 
  Brushless motor ESC, adjustable (in flight) RPM regulator with
 
  two temperature probes and data capture.
 
  ©Mark Qvale, 2019
 
  Creative Commons Attribution-ShareAlike 3.0 License
 
 
 
  Arduino Board and Pins used-
 
  Board - Arduino Pro Mini, Atmega 328P, 5v, 16mHz
 
  Pin 2 - RPM rpm sensor pin
 
  Pin 8 - Passthrough/Regulated switch channel
 
  Pin 9 - ESC out
 
  Pin 3 - RX/FC throttle in
 
  Pin 4 - Relay trigger out
 
  
  Arduino bord to Micro SD Card Shield Pins-
+
: '''Throttle Regulation'''<br>
  Pin 10 - CS
+
: Using the RX switch channel, this sets up the throttle regulation by first setting one-time values for the RPM set-point (rpmset) and initial throttle out setting (thrOut). Next, through three "IF" statements the rpm is checked every 2 seconds (RST) and compared to the rpm set-point. If the rpm is low the throttle output is increased by 1, if the throttle is high, the throttle output is decreased by one. The final value is then sent to the ESC.<br>
  pin 11 - MOSI
+
: '''Note:''' I did try using a PID controller here but the tuning became problematic because of the filters and timers needed to stabilize the rpm read. In the section (below) "Bench Test Results" you can see how well this simple regulation method works.
  pin 12 - MISO
+
<br>
  pin 13 - SCK(CLK)
+
 
 +
: '''Switch Safety'''<br>
 +
: This section which looks for a switch channel input of less than 900ms (PWM) which generally means there is a connection or RX problem. It keeps the relay and throttle output in a "fail-safe" mode if there is no input from the RX switch channel. This is
 +
<br>
 
    
 
    
  Items needed for this build-
+
: '''RPM Signal Capture'''<br>
1x Hobbywing RPM sensor for brushless motors
+
: This piece of code was found while doing a search on "HobbyWing RPM Sensor" and works quite well. It did present some issues when I tried to use a PID control loop and also before I added the SPDT relay. Additionally, I added a second exponential smoothing filter to help stabilize the rpm read and rpm stabilization. The code for this can be found below.<br>
2x 100k or 10k thermistors
+
: <u>https://www.locarbftw.com/using-an-arduino-to-read-rpm-from-the-hobbywing-rpm-sensor/</u>
1x Nano or Pro-Mini board
+
<br><br>
1x Micro SD card shield
+
1x SPDT Signal relay, 5v
+
2x R1 resistors (see below)
+
2x 10nF (103) capacitors (to stabilize temp readings)
+
+
Temp sensor & resistors-
+
Glass bead thermistor 100k NTC3950
+
  R1 = 100K ohms
+
10k thermistor
+
  R1 = 10K ohms
+
Pin A0 is Temp 1 input
+
Pin A1 is Temp 2 input
+
  
Acknowledgements-
+
=== Radio TX and RX Configuration ===
Tom Igoe for his data log example code
+
Adrian Li for the RPM counter section found at https://www.locarbftw.com/using-an-arduino-to-read-rpm-from-the-hobbywing-rpm-sensor/
+
*/
+
  
#include <Servo.h>                                        // Servo control library - Servo (built-in) by Michael Margolis
+
This is pretty simple. A single channel is used to activate the Pass-through/Regulate modes from a switch on the Tx. Select a channel for this function and set it up on a switch with the following parameters-
#include <Filter.h>                                       // Filter library - MegunoLink by Number Eight Innovation
+
<br>
#include <PID_v1.h>                                      // Control Loop library - PID by Brett Beauregard
+
: Switch position 1 = +100%  This is Pass-Through mode
#include <PWM.hpp>                                       // PWM reader library by Kamran Ahmad
+
: Switch position 2 = -100%  This is RPM Regulate mode (Make sure this is not below a pulse width of 900ms)
#include <SPI.h>                                         // Serial Peripheral Interface library by Arduino
+
<br><br>
#include <SD.h>                                          // SD Card library by Arduino/Sparkfun
+
=== Using the Tool ===
#define INTERRUPT_PIN 0                                  // defines pin 2 (0) as RPM interrupt
+
  
Servo escout;                                            // create servo/esc object
+
It is very simple to use! Assuming you have bench tested after getting it all put together and run the Arduino serial monitor to confirm the card is initializing and collecting data, first, connect the device into your plane-
 +
<br>
 +
'''My Pin-Outs'''<br>
  
/* adjustable variables for signal smoothing  and PID parameters */
+
{| border="0" cellspacing="1" cellpadding="1" width="900" align="center"
int rpmRND = 25;                                          // rounding value for rpm signal (default 25)
+
|-
int EFW = 10;                                            // exponential filter weight (default 10)
+
| align="center" | [[File:REG09.jpg|800px]]
int EFWB = 20;                                            // exponential filter weight (default 20)
+
|}
int PST = 50;                                            // PID sample time (default 50)
+
<br>
float kP = 0.07;                                          // PID proportional factor
+
float kI = 0.03;                                          // PID integral factor
+
float kD = 0;                                            // PID derivative factor
+
int avgN = 20;                                            // temperature average number (default 20)
+
int period = 200;                                        // data print period in ms (default 200)
+
float numpoles = 14;                                      // number of motors magnet poles
+
  
/* global variables */
+
: 2. Plug a Micro SD card into the card shield
const int chipSelect = 10;                                // data write pin number
+
: 3. Connect power and listen for the ESC to initialize which confirms it is in "pass-through" mode
unsigned long time_now = 0;                              // print timer variable
+
: 4. Do all your normal pre-flight checks and tests including checking that the throttle works as you expect
volatile int interruptCount;                              // RPM count variable
+
: 5. Launch the plane and fly to a straight and level position at a speed above stall
unsigned long time = 0;                                  // initialize time variable
+
: 6. Flip the mode switch to Regulate and it should now stay at this airspeed until you move the switch back to Pass-through
int csw = 0;                                              // switch state key 0
+
: 7. When ready flip the mode back to pass-through and land the plane.
int nsw = 1;                                              // switch state key 1
+
: 8. Pull the Micro SD card and check the log to see time, rpm and temp data logged
int switchState;
+
: 9. Run this way on several props all at the same air speed and you will be able to see direct in-flight comparisons of what different props can do.
int relay = 4;                                            // relay pin
+
<br><br>
int sig;                                                  // lower limit PWM signal variable
+
int thout;                                                // regulated ESC throttle output variable
+
float thpwm;                                              // RX/FC throttle input variable
+
float thrP = 0;                                          // throttle percent variable
+
int tempPin0 = A0;                                        // temperature read/compute variables
+
int tempPin1 = A1;                                        //
+
int Vo0;                                                  //
+
int Vo1;                                                  //
+
float avgT1;                                              //
+
float avgT2;                                              //
+
float R1 = 10000;                                        //
+
float logR2, R2, logR3, R3, T1, T2;                      //
+
float c1 = 1.009249522e-03;                              //
+
float c2 = 2.378405444e-04;                              //
+
float c3 = 2.019202697e-07;                              //
+
  
PWM thrIn(3);                                            // setup pin 3 for throttle input using the PWM ibrary
+
=== Bench Test Results ===
  
/* Exponential filter setup */
+
Below is a set of Excel charts created by my Medusa Data analyzer showing a bench test run using a 4S Li-ion battery pack which was charged to 15v and over 27 minutes run down to 12.4v (3.1v/cell). The test was started at an RPM set-point of 5075 rpm which consumed 55 watts of power. You can see the RPM is maintained at a fairly steady state with a variation of +/-50 RPM for the entire run. This is as good a resolution as I can get with the components used (and my programming abilities).
ExponentialFilter<long> ADCFilter(EFW, 0);                // rpm smoothing filter
+
<br>
ExponentialFilter<long> ADCFilterB(EFWB, 0);              // throttle signal smoothing filter
+
{| border="0" cellspacing="1" cellpadding="1" width="900" align="center"
 +
|-
 +
| align="center" | [[File:REG11.JPG|900px]]
 +
|}
 +
<br>
 +
You can also see the current increases as the voltage drops which is a good indication that the power (in watts) into the ESC/motor was also steady state.<br>
 +
{| border="0" cellspacing="1" cellpadding="1" width="900" align="center"
 +
|-
 +
| align="center" | [[File:REG13.JPG|900px]]
 +
|}
 +
<br>
 +
{| border="0" cellspacing="1" cellpadding="1" width="900" align="center"
 +
|-
 +
| align="center" | [[File:REG15.JPG|900px]]
 +
|}
 +
<br>
 +
As expected, the device continually checked and adjusted the throttle to comensate for the measured RPM readings.<br>
 +
{| border="0" cellspacing="1" cellpadding="1" width="900" align="center"
 +
|-
 +
| align="center" | [[File:REG17.JPG|900px]]
 +
|}
 +
<br>
  
/* PID controller setup */
+
=== In-Flight Results ===
double rpmset, rpm, pwmsignal;                            // define variables connected to the PID controller
+
PID myPID(&rpm, &pwmsignal, &rpmset, kP, kI, kD, DIRECT); // PID tune set-up (original PID tune values - 2,5,1)
+
  
void setup()
+
TBA
{
+
<!--
  Serial.begin(115200);                                  // start the serial monitor
+
{| border="0" cellspacing="1" cellpadding="1" width="900" align="center"
  rpm = 0;                                                // initialize rpm variable
+
|-
  rpmset = 0;                                            // initialize PID variable, rpmset
+
| align="center" | [[File:REG08.JPG|900px]]
  thrIn.begin(true);                                      // begin reading throttle input (3)
+
|-
  escout.attach(9);                                      // attach ESC object (9)
+
| align="center" | 30 minute test run
  pinMode(relay, OUTPUT);                                // relay on/off switch pin (4)
+
|}
  pinMode(8, INPUT);                                      // set pinmode on RX switch pin (8)
+
-->
  pinMode(INTERRUPT_PIN, INPUT);                          // set pinmode on RPM pin (2)
+
<br><br>
  attachInterrupt(INTERRUPT_PIN,interruptFired, CHANGE);  // set-up interrupt count on RPM pin (2)
+
  myPID.SetSampleTime(PST);                              // PID sampling rate in milliseconds (default = 50)
+
  myPID.SetMode(AUTOMATIC);                              // set PID mode, AUTOMATIC or MANUAL
+
  myPID.SetOutputLimits(900, 2000);                      // set low and high pwmsignal limits
+
  Serial.print("Initializing SD card...");                // see if the card is present and can be initialized
+
  if (!SD.begin(chipSelect)) {                            //
+
    Serial.println("Card fail, or not present");          //
+
    while(1);                                            //
+
  }
+
  Serial.println("card initialized.");                    //
+
  File dataFile = SD.open("Data_Log.csv", FILE_WRITE);    // name and open the CSV file
+
  if (dataFile) {
+
    dataFile.println("Time(s),Temp 1(F),Temp 2(F),RPM,Thr %,Switch");    // write the column headings to the csv file
+
    dataFile.close();                                    // close file
+
  }
+
}
+
  
void loop(){
+
== One Issue ==
  time = millis();                                        // time in ms
+
  thpwm = thrIn.getValue();                              // capture throttle signal
+
  ADCFilterB.Filter(thpwm);                              // throttle signal filter
+
  thpwm = ADCFilterB.Current();                          //
+
  
// +++++++++++++++++++++++++++++++++++++++++++ Throttle Percent ++++++++++++++++++++++++++
+
First, I am not an expert at writing or optimizing code. I am also not an electrical engineer (I am a retired Mechanical Engineer however) so if you see something that doesn't make sense or could be done differently with better results, please don't hesitate to contact me (bottom of this page) and let me know your thoughts.
  thrP = thpwm;                                          // copy throttle signal value
+
<br>
  thrP = constrain(thrP, 990, 2010);                      // constrain values for mapping
+
  thrP = map(thrP, 990, 2010, 0, 100);                    // map throttle values to percent throttle
+
  
// +++++++++++++++++++++++++++++++++++++++++++ Temp 1 & 2 ++++++++++++++++++++++++++++++++++
+
Now the '''ONE ISSUE'''<br>
  Vo0 = analogRead(tempPin0);                            // read temp pin 0
+
The one issue that drove me crazy while trying to get this to work in a plane is the fact the HobbyWing RPM sensor is massively affected by any 1.2G VTx. I chased this problem all over the map until I finally (simply) connected the RPM sensor to my oscilloscope on the bench and watched what happened when I turned on a 1.2G VTx which was in a plane at a distance of ~6 feet (2m). There were no connections at all between the plane and the bench test set-up. On the other hand a 5.8G, 600mw VTx has no affect so that is what I will use in testing.
  R2 = R1 * (1023.0 / (float)Vo0 - 1.0);
+
<br><br>
  logR2 = log(R2);
+
  T1 = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
+
  T1 = T1 - 273.15;                                      // temp in Celsius
+
  T1 = (T1 * 9.0)/ 5.0 + 32.0;                            // temp converted to Farenheit
+
  for(int i = 0; i < avgN; ++i){
+
    avgT1 += T1;
+
  }
+
  avgT1 /= avgN;
+
  avgT1 = int(avgT1);
+
 
+
  Vo1 = analogRead(tempPin1);                            // read temp pin 0
+
  R3 = R1 * (1023.0 / (float)Vo1 - 1.0);
+
  logR3 = log(R3);
+
  T2 = (1.0 / (c1 + c2*logR3 + c3*logR3*logR3*logR3));
+
  T2 = T2 - 273.15;                                      // temp in Celsius
+
  T2 = (T2 * 9.0)/ 5.0 + 32.0;                            // temp converted to Farenheit
+
  for(int i = 0; i < avgN; ++i){
+
    avgT2 += T2;
+
  }
+
  avgT2 /= avgN;
+
  avgT2 = int(avgT2);
+
 
+
/* +++++++++++++++++++++++++++++++++++++ Switch Pass through +++++++++++++++++++++++++++++++++++++ */
+
  if (pulseIn(8, HIGH) > 1600){                          // pass-through switch position
+
    digitalWrite(relay, LOW);                            // holds relay closed (NC relay)
+
    csw=0;                                                // switch state key
+
    switchState = csw;
+
  }
+
/* +++++++++++++++++++++++++++++++++++++ Switch RPM Regulation +++++++++++++++++++++++++++++++++++ */
+
  if(pulseIn(8, HIGH) >= 900 && pulseIn(8, HIGH) <= 1600) // regulate RPM switch position
+
    {
+
    digitalWrite(relay, HIGH);                            // opens throttle pass-through relay
+
    if(nsw != csw){                                      // checks switch state
+
      rpmset = rpm;                                      // creates rpm signal set-point for the PID controller
+
      sig = thpwm+1;                                      // PWM transfer value
+
      delay(2);                                          // relay delay (one time)
+
      csw = nsw;                                          // switch state cancel
+
    }
+
    switchState = nsw;
+
    myPID.Compute();                                      // compute the PID pwmsignal correction
+
    thout = pwmsignal;                                    // converts PID pwmsignal to an integer for ESC output
+
    thout = constrain(thout, sig, 2000);                  // sets PWM range based on PWM transfer value as the lower limit
+
    escout.writeMicroseconds(thout);                      // send regulated throttle value to the ESC
+
  }
+
/* +++++++++++++++++++++++++++++++++++++ Switch Safety +++++++++++++++++++++++++++++++++++++++++++ */
+
  if(pulseIn(8, HIGH) < 900){                            // sets escout to 0 if no or low switch pulse detected (safety)
+
    escout.writeMicroseconds(0);
+
    digitalWrite(relay, LOW);                            // sets pass-through relay closed
+
  }
+
/* ++++++++++++++++++++++++++++++++++++++++++++ RPM Signal Capture +++++++++++++++++++++++++++++++ */
+
  noInterrupts();                                        // RPM count code
+
  interruptCount = 0;                                    //
+
  interrupts();                                          //
+
  delay(10);                                              //
+
  noInterrupts();                                        //
+
  int critical_rpm = interruptCount;                      //
+
  interrupts();                                          //
+
  rpm = ((critical_rpm)*(60))/(numpoles)*100;
+
  ADCFilter.Filter(rpm);                                  // exponential smoothing filter enable
+
  rpm = ADCFilter.Current();                              // smoothing filter output
+
  rpm = int(round(rpm/rpmRND))*rpmRND;                    // rpm converted to an integer and rounded
+
  if(rpm <= 1000){
+
    rpm = 99;
+
  }
+
/* ++++++++++++++++++++++++++++++++++++++++++++ Datafile Write ++++++++++++++++++++++++++++++++++ */
+
  if(millis() >= time_now + period){                      // start print timer
+
    time_now = millis();                                  // reset print timer
+
 
+
  File dataFile = SD.open("Data_Log.csv", FILE_WRITE);    // open the data log file
+
  if (dataFile) {                                        // if available, write
+
    dataFile.print(time/1000);                            // write to card - time in seconds
+
    dataFile.print(", ");
+
    dataFile.print(avgT1);                                // write to card - Temp 1
+
    dataFile.print(", ");
+
    dataFile.print(avgT2);                                // write to card - Temp 2
+
    dataFile.print(", ");
+
    dataFile.print(rpm);                                  // write to card - RPM
+
    dataFile.print(", ");
+
    dataFile.print(thrP);                                // write to card - Throttle percent
+
    dataFile.print(", ");
+
    dataFile.println(switchState);                        // write to card - Switch state
+
    dataFile.close();                                    // close data card file
+
  }
+
  else {
+
    Serial.println("Card error!");
+
  }
+
  }
+
/* ++++++++++++++++++++++++++++++++++++++++++++ Serial Monitor Output +++++++++++++++++++++++++++ */
+
  Serial.print("\n  RPM: ");
+
  Serial.print(rpm);
+
  //Serial.print("  set-point: ");
+
  //Serial.print(rpmset);
+
  //Serial.print("  Thr signal: ");
+
  //Serial.print(thpwm * 2.2);
+
  Serial.print("  state: ");
+
  Serial.print(switchState);
+
  Serial.print("  Thr %: ");
+
  Serial.println(thrP);
+
}
+
/* ++++++++++++++++++++++++++++++++++++++++++++ RPM Counter Increment +++++++++++++++++++++++++++ */
+
void interruptFired(){
+
  interruptCount++;
+
}
+
</nowiki>
+
  
 
== See Also ==
 
== See Also ==
  
TBA
+
:* [[DIY - Battery Pack Spot Welder]]
 +
:* [[DIY - Dynamic Motor and Prop Balancer]]
 +
:* [[DIY - Motor and Prop Test Bench]]
 +
:* [[DIY - Vacuum Forming Box]]
 
<br><br>
 
<br><br>
  

Latest revision as of 00:41, 25 July 2019


© Mark Qvale - July, 2019

REG00.JPG
  DIY Arduino Tools!


Tools.jpg This page or section is under construction and will change going forward.

Questions or Comments? Please contact the Wiki administrator



Introduction

Folks on RCGroups and FB have asked about some of the test tools I use to get the recommendations, charts and numbers I use in my posts. This article describes the build of a tool to measure and log the RPM of a brushless motor plus two temperature probes.

This DIY tool came from a need to be able to test components at steady state power, current and RPM levels to fully understand the loads being placed on the components. The first version of this device served to regulate the RPM at a steady state regardless of voltage supply to test battery packs and ESC's. I then re-configured the tool to regulate the current pulled from the ESC to further test battery packs in a controlled environment without the need for an expensive lab quality power supply.

The latest effort, shown here, is to make this a stand-alone in-flight tool as a means to help with choosing the best motors & props for maximum flight efficiency on an FPV fixed wing project. The goal is to have the ability to set the RPM, like a cars cruise control, then fly for a short period (5 minutes) and capture the logging info. Doing this on several different props running the same airspeed in every case will give excellent real-world comparison information.

Tool Description

The tool captures RPM and two temperature values and logs them to a Micro SD card as a CSV file type which can be read and analyzed in MS Excel.

  • RPM is captured using a Hobbywing RPM sensor which is the same as the Eagle Tree and Spektrum RPM sensors.
  • RPM can be set using the TX while flying as either direct pass-through or regulated rpm.
  • Temperature is captured using two glass bead NTC3950 thermistors commonly found on 3D printer set-ups.
  • One temp sensor is epoxied onto the motor cross mount and the other is slipped under the ESC shrink cover on the MosFet side.
  • One extra radio channel is needed to activate the pass-through/regulated functions.


REG03.JPG
First flight set-up bits


Parts

The following are the parts used in the latest version of this tool-

1. Arduino 5v/16mhz Pro Mini Board
2. Omron 5v SPDT Signal Relay
3. Hobbywing RPM Sensor
4. NTC3950 Thermistors
5. Pin headers
6. Double Sided Prototyping PCB
7. 2x 100k Ohm, 1/4 watt resistors
8. 2x 10nF (103) capacitors



Part Selection

Arduino Pro Mini - I wanted a small board with enough IO to handle all the tasks. The Pro Mini or the Arduino Nano both easily fit the bill as does the Teensy LC board. The Pro Mini was finally selected because it works and I can find them for around $5 each.

Omron Relay - After trying many different software attempts to create a smooth pass-through mode for the signal from the flight controller directly to the ESC, I finally decided to use the normally closed side of a relay to accomplish this task. There are few reasons for this-

1. If the board fails for some reason the relay will close to direct pass-through making it possible to continue flying the plane.
2. Having a direct, hard wired pass-through makes it completely smooth which is important in how the regulated section of the software works.
3. Inexpensive ($1.79)


HobbyWing RPM Sensor - I actually started with an early Eagle Tree unit that had an issue with how the power wires were from the factory - Black = Positive, Red = Negative (wtf?). While looking for another pre-built solution I found the HobbyWing version which according to my O-scope produces the same output. Bonus is they are less than a quarter of the price of the Eagle Tree units ($4.49)

NTC3950 Thermistors - I selected this type of temp sensor because I had them already and they are really inexpensive ($1.40 ea). Also they are very easy to attach to the motor and ESC because of their size.

All together then, the parts for a single build cost me about $18.

Schematic

The schematic for this build can be seen here-

REG02.jpg


  • Power for the Arduino board, RPM sensor and Micro SD shield (MSD) is supplied from the ESC. In the event the ESC is an Opto type, a separate 5v supply will need to be used.
  • Power to the temp sensors is supplied from the Vcc pin on the Arduino board.
  • The mode switch input is a single signal wire from the chosen switch channel on the RX.
  • Throttle-in comes from the flight controller or RX in the case where no flight controller is used.



Board Builds

Here are some images of the first few versions and close-ups of the latest build-

REG01.jpg
Some of the proto set-ups
1. First test board
2. First Regulator only board
3. First data logger for in-flight
4. Bread-boarding the new relay
5. Current build


REG06.JPG
Current board (top)


REG05.JPG
Current board (bottom)



Code, Use & Results

The Arduino code can be downloaded here-

v16r2 - July 24, 2019 - RPM_Regulator_v16r2.zip

Below are some details of the major code sections:

Throttle Value & Percent
This section covers collecting the throttle-in PWM value (thrIn) using a PWM read library. I chose using this library approach as opposed to a simple "pulseIn" capture because it gives cleaner results. Added to this I am using an exponential smoothing filter to calm down the jumpiness of the input. In the last part of this I convert the throttle input to throttle percent for displaying in the data file.


Temperature Captures
The two temperature probes are picked up using the analog inputs A0 & A1. The code which configures these two inputs for the data file is taken directly from a code snippet found at CircuitBasics.com. The output to the data file is given in degrees Fahrenheit but can be changed to degrees Celsius by commenting out the two lines where the conversion is made. In the latest code, v16r2, this is line 137 and line 142.


Throttle Pass-Through
This piece of code takes the input from an RX channel and makes sure the pass-through relay is left in its normally closed state allowing a direct hardwire path between the throttle input and ESC output. It also holds the pass-through switch state at 0.


Throttle Regulation
Using the RX switch channel, this sets up the throttle regulation by first setting one-time values for the RPM set-point (rpmset) and initial throttle out setting (thrOut). Next, through three "IF" statements the rpm is checked every 2 seconds (RST) and compared to the rpm set-point. If the rpm is low the throttle output is increased by 1, if the throttle is high, the throttle output is decreased by one. The final value is then sent to the ESC.
Note: I did try using a PID controller here but the tuning became problematic because of the filters and timers needed to stabilize the rpm read. In the section (below) "Bench Test Results" you can see how well this simple regulation method works.


Switch Safety
This section which looks for a switch channel input of less than 900ms (PWM) which generally means there is a connection or RX problem. It keeps the relay and throttle output in a "fail-safe" mode if there is no input from the RX switch channel. This is


RPM Signal Capture
This piece of code was found while doing a search on "HobbyWing RPM Sensor" and works quite well. It did present some issues when I tried to use a PID control loop and also before I added the SPDT relay. Additionally, I added a second exponential smoothing filter to help stabilize the rpm read and rpm stabilization. The code for this can be found below.
https://www.locarbftw.com/using-an-arduino-to-read-rpm-from-the-hobbywing-rpm-sensor/



Radio TX and RX Configuration

This is pretty simple. A single channel is used to activate the Pass-through/Regulate modes from a switch on the Tx. Select a channel for this function and set it up on a switch with the following parameters-

Switch position 1 = +100% This is Pass-Through mode
Switch position 2 = -100% This is RPM Regulate mode (Make sure this is not below a pulse width of 900ms)



Using the Tool

It is very simple to use! Assuming you have bench tested after getting it all put together and run the Arduino serial monitor to confirm the card is initializing and collecting data, first, connect the device into your plane-
My Pin-Outs

REG09.jpg


2. Plug a Micro SD card into the card shield
3. Connect power and listen for the ESC to initialize which confirms it is in "pass-through" mode
4. Do all your normal pre-flight checks and tests including checking that the throttle works as you expect
5. Launch the plane and fly to a straight and level position at a speed above stall
6. Flip the mode switch to Regulate and it should now stay at this airspeed until you move the switch back to Pass-through
7. When ready flip the mode back to pass-through and land the plane.
8. Pull the Micro SD card and check the log to see time, rpm and temp data logged
9. Run this way on several props all at the same air speed and you will be able to see direct in-flight comparisons of what different props can do.



Bench Test Results

Below is a set of Excel charts created by my Medusa Data analyzer showing a bench test run using a 4S Li-ion battery pack which was charged to 15v and over 27 minutes run down to 12.4v (3.1v/cell). The test was started at an RPM set-point of 5075 rpm which consumed 55 watts of power. You can see the RPM is maintained at a fairly steady state with a variation of +/-50 RPM for the entire run. This is as good a resolution as I can get with the components used (and my programming abilities).

REG11.JPG


You can also see the current increases as the voltage drops which is a good indication that the power (in watts) into the ESC/motor was also steady state.

REG13.JPG


REG15.JPG


As expected, the device continually checked and adjusted the throttle to comensate for the measured RPM readings.

REG17.JPG


In-Flight Results

TBA

One Issue

First, I am not an expert at writing or optimizing code. I am also not an electrical engineer (I am a retired Mechanical Engineer however) so if you see something that doesn't make sense or could be done differently with better results, please don't hesitate to contact me (bottom of this page) and let me know your thoughts.

Now the ONE ISSUE
The one issue that drove me crazy while trying to get this to work in a plane is the fact the HobbyWing RPM sensor is massively affected by any 1.2G VTx. I chased this problem all over the map until I finally (simply) connected the RPM sensor to my oscilloscope on the bench and watched what happened when I turned on a 1.2G VTx which was in a plane at a distance of ~6 feet (2m). There were no connections at all between the plane and the bench test set-up. On the other hand a 5.8G, 600mw VTx has no affect so that is what I will use in testing.

See Also



Comments? Questions?

email me!