diff --git a/README.md b/README.md index 72e7827b19afd04fee6dd41c81348252104dd444..9634d8947c4a298c96f0eb7229e2c21d01789316 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,124 @@ # Dynamometer +## Week 6 - 4/8/21 + +This week I polished up the saturation sweep from last week, as well as added a thermocouple and wrote a script, which does a thermal sweep over a range of holding currents. To take a step back, I started this project by writing a script that sweeps through a range of motor speeds, and applies increasing torques until the motor stalls. The result of that data is commonly called a speed-torque curve, or an efficiency map, depending on what you're interested in. + +With that said, there's an upfront decision that needs to be made when starting the test (at least for an open loop stepper motor), which is to question what current the driver should chop at when driving through the sweep. So if you had a motor of dubious origin, or you wanted to be sure you were driving your motor at the optimal power for your application, you could run a bunch of those efficiency map sweeps at different currents, and see how performance changed for each chopper current setpoint. With that said, the power you can dump through a motor is bounded in two ways: + +* Saturation - at a certain point you will have saturated your motor's core, and the relative increase in B (flux) you get from an increase in H (amp-turns), begins to scale with the permeability of free space. All of that to say, the increase in torque you with increasing current will diminish exponentially. +* Thermal - at a certain point you will begin to degrade the insulation on your motor's windings and cause a short or otherwise damage your motor ([not to mention that BH curves are temperature dependent long before having to worry about curie temps.](https://www.jstage.jst.go.jp/article/isijinternational/57/10/57_ISIJINT-2017-145/_html/-char/en#:~:text=A%20BH%20curve%20illustrates%20the,vibrating%20sample%20magnetometer%20(VSM))) + +So if you wanted to get a holistic understanding of the performance of a motor driven at optimal power inputs, you would want to know where (ie. at what current) your motor began to saturate, and where your motor began to overheat, to inform what current you ran your efficiency map through. To that end these final two tests do just that, by sweeping increasing current setpoints and measuring peak static holding torque at each, and then again sweeping through increasing current setpoints and measuring steady state temperature at each. + + + + + +Temperature is being measured via a K-type thermocouple read over a MAX31885X, and again logged directly to the micro during the test. The sweep looks for a "steady state" of 5 consecutive temp readings, spaced at 2.5 second intervals before increasing to the next current setpoint. In retrospect after seeing the data plotted, it looks like I am probably still pretty far from true steadystate, but at least this way the test is kept to under 20 mins. Below is an image of the thermocouple as attached to the motor, first with a layer of thermal transfer tape, and then a silicon foam for insulation held in place with aluminum tape. For the sweep above, the foam popped off in the last 5 mins of the test, which causes some weird jumps at the end. Additionally from the FLIR image below that, it's apparent that different parts of the motor can hit wildly different temperatures (at its hottest point this motor hit ~75deg C). I think in the future I will mount the thermocouple to the aluminum bearing housing of the motor, or potentially drill into it and attach the thermocouple directly to the windings. + + + + + +Last week I mentioned that I suspected that most stepper motors are primarily thermally limited, rather than saturation limited, and this week I have my first datapoint to that end. It turns out that for this particular motor (a relatively small, 34mm long, NEMA17 with high inductance at 37 mH), the limits appear to be definitively on the saturation end! Still lots of work to improve data quality and repeatability (on a seperate day this sweep hit 36Ncm so I suspect my taring is still problematic, and I need more resolution for the absorber duty cycle driver). + +Lastly I have a strong suspicion that for steppers, what appears to be a saturation limit may have more to do with the strength of the motor's biasing magnet. So at a certain applied field strength, our Hybrid Permanent Magnet + Variable Reluctance motor just begins to behave like a Variable Reluctance motor... Not sure of a good way to prove this outside of simulation, but it definitely poses an interesting question. Really all I have going for this idea is that there are relatively massive amount of steel (and short high reluctance gaps) in a stepper motor, compared to most BLDCs of considerably higher power. If you have a good understanding of the balance between saturation and biasing magnets, I would love to talk! + +## Week 5 - 4/1/21 + +This week I took a first stab at one of the initial motivations for building the dynamometer. That is looking at stepper motor torque bounds as we approach saturation and thermal limits for the motor. The plot below illustrates this by sweeping through increasing current chopping setpoints (keeping in mind that open loop stepper motors are driven as constant current devices). What we see is a very linear response in peak holding torque (all of these sweeps were conducted at 0 rpm). The exception to this occurs at 3000mA, where we see what looks like a dramatic reduction in peak torque. In reality this is the power supply running my absorber (the brushed DC motor) hitting its current limit (ie. the test motor does not stall here). So with that said I am publishing this very wrong data early (but such is the nature of hitting class deadlines). So I have no reason to suspect that this motor doesn't continue off linearly into the 4A or 5A regime, which would pose a lot of interesting questions as discussed below. + + + +[Here's a link to the stepper that I am testing.](https://www.omc-stepperonline.com/nema-23-bipolar-1-8deg-1-9nm-269oz-in-2-8a-3-2v-57x57x76mm-4-wires.html) It's one of the more commonly used NEMA23 steppers used for DIY applications, rated for 1.9Nm at 2800mA. Fortunately this lines up extremelyt well with our own tests! At 2500mA we acheive a peak torque of 195N*cm. Below is an image of stepperonline's speed torque curve (you can disregard the 36V vs 48V difference as this has minimal impact at 0 RPM). + + + +So this plot gets at the question of, is power consumption for NEMA-packaged steppers thermally or saturation limited, and how close are we getting to saturation limits? (I think they're almost certainly thermally limited). The first thing to look for is if we can see the effects of saturation happening before thermal limitations kick in. There's a neat [paper from the biomimetics lab](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7827048) that lays this question out in the context of BLDCs (they also discuss the possibility of hitting a curie temp limit, but that typically happens well past saturation). + +If we are very far from saturation then there's a good argument to make for having drivers that tap into more peak current headroom that would otherwise burn up the motor in steady state (especially for steppers with high inductance when you aren't in the peak ~3A regime of most drivers anyways) that would otherwise go unused. Ultimately this gets at trying to level the driver playing field between "variable reluctance hybrid motors" (steppers) and "3-phase PM motors" (BLDCs), and then get definitive numbers for low RPM torque output, because I haven't seen anyone publish data along those lines. So the question boils down to the tradeoffs between a motor with high pole count + low reluctance flux path (again a stepper) vs. everything BLDCs have going for them: external rotors + way more PM material + better cooling, etc. + +It's very likely clearpath and all of the closed loop stepper companies do this already, but depending on how this data pans out, there's a neat case to make for taking cheap off the shelf steppers and driving them with parameters very tuned to their performance (on the boundary of melting windings) via the dyno, and seeing how much more performance you get. + +Next steps to look into here are: +* Recalibrate my load cell as I've moved a lot of things around since its initial calibration (despite the fact that my data seems to line up well with the vendors). +* Add a thermocouple to the logging setup such that we can also get measurements getting at thermal limits. +* Switch over to a weaker NEMA17 form factor for the test motor, such that I have ample absorber torque to make sure I can defeat the test motor at any reasonable holding current. + +## Week 4 - 3/25/21 + +This week I focused on improving data analysis (see the nicely interpolated speed-torque curves below), speeding up test times, and slogging through the endless process of finding bugs and improving repeatability. + + + +Becuase getting an idea of repeatability involves running tests over and over again, I wound up writing a good deal of code to minimize test length. The bulk of the speed up efforts stem from the effects of the back-emf produced by the absorber as it is being spun by the test motor. If my absorber produces 10V when being spun at 500RPM, I need to overcome this voltage before I can actually start producing torque on the test motor. Imagine I am sweeping absorber voltages with 0.1V increments. Unfortunately this means that I am sweeping through absorber voltages (either actively or passively), it means I would need to sweep from 0 to 10V (100 measurements at 0.1V increments!) before I actually started producing any torque on the motor. That's why you can see a lot of points clustered at the bottom of each RPM sweep, where many of effectively the same measurement are being taken, before we have overcome the back-EMF of the motor. The code that I ultimately settled on is to measure a torque floor at the start of each RPM measurement, and then tick up the sweep counter until torque surpases the torque floor by some threshold. The associated sweep counter becomes the new starting point for the counter, so I waste less time sweeping all the way up to that counter value each time. This step saves on the order of 10's of minutes if sweeping over smaller RPM intervals, like 25 RPM or 50 RPM. What might be better (assuming I am commited to this particular brushed DC absorber motor) would be to really measure the KV of the absorber, and then actually just start PWMing at the voltage directly under the assumed back-EMF for an associated RPM. Oh well, might resort to that later, but it was late at the time and it's working now... + +All of this trouble has certainly had me questioning the use of a brushed DC motor as an absorber. An eddy current brake or even a mechanical disc brake for example would be able to generate a linear and continuous torque response, indepedent of what's happening with the test motor. + +Another speed-up effort was switching to low pass filtering rather than averaging for current sensing, which is still contributing more nosie than I would like considering the current measurements are very small and on the order of noise + voltage is constant. This results in occasional anomalies in the efficiency data. A huge bottleneck in test speed is the 80Hz sample rate of the HX711 load cell amp. I currently average 10 samples in rapid succession to also smooth out some noise, but because there can be very real jumps in torque data, I am not quite sure that a low pass filter that spans torque sweep steps is a good idea here as well... + +I also caught an interesting bug that was manufesting as all of my torque measurements shifting up or down on the order of 10 N*cm between tests for the same motor. I believe this stemmed from taring the torque sensor after energizing the test motor. This would generate not-insignificant amounts of torque to overcome friction in the slewing bearing and absorber motor, depending on where the test motor had come to a rest during the last stall from the prior test. + +Before I mentioned the problem of back EMF creating a threshold voltage that you needed to reach in order to start generating usable torque. In the plot below you can see that really clearly, with the 3 clusters of sample points pointed at by the callout. What's happening here is that the RPM sweep begins in passive mode, so just PWMing between open and closed absorber motor windings. At lower RPM (150, 200, and 250), there isn't enough back EMF to stall the motor, so the controller switches over to active mode. When this happens, we start at PWM of 0, so we again have to sweep all the way up to a voltage that overcomes the back-EMF of the motor. At higher RPM, this transition happens at higher and higher torque, as shown in the plot below. You can also get an idea of my current repeatability between the two tests run above and below. Efficiency data is sort of all of the place, and the very coarse torque increments at later RPM result in lots of uncertainty in terms of where peak torque for a given RPM will land (despite relatively consistent data for lower RPM). + + + +I had a suspicion that the default Arduino analogWrite's PWM frequency (about 1.8kHz for the M4 feathers) was slow enough to be on the order of cogging in the stepper and/or the absorber, resulting in weird harmonics causing early torque stalls where the torque might jump as it hits a harmonic. With some help from Jake, I switched over to routing timers and setting up PWM on the register level for the SAMD51. Despite having access to a 120 MHz clock, the prescalar and PWM resolution increments are quite coarse, so the best I could do as an improvement was getting to ~8kHz with the same 8-bit resolution. In the end I intend to switch over to 16-bit PWM resolutionm which actually takes me right back to 1.8kHz. Because the KV of my absorber is large enough that I only resolve extremely coarse torque steps at higher RPM (see the plots above), while the 256 step sweep is more than enough for lower RPM, I will need much more for higher RPMs. + + + +Overall this week was a humbling lesson in why it's easy to protoype something that appears to be working on a surface level, generate a bunch of beautiful data or create a nice working demo, and still only have done 50% (if not less) of the work to create something truely reliable and useful. + +## Week 3 - 3/18/21 + +[Here's video of the dyno running as of last night.](https://vimeo.com/525624403) I thought I remembered it being possibleto embed youtube/vimeo links directly into gitlab markdown, but it doesn't seem to be working atm. + +This week all of the remaining subsystems came together (except for a thermocouple which I would like to add for some future sweeps) and I was able to generate some interesting data as shown in the plots below. Back in week 2 I sketched out an illustration of the sweep I was planning to make: Commutate at some constant RPM and then incrementally increasing opposing torque via the absorber. At each increment, measure torque via the load cell, RPM via the encoder, stepper voltage and current consumption via the INA260. For an open loop stepper, stepper voltage and current comsumption will remain relatively constant across the entire sweep, increasing slightly with increasing RPM. The product of these two will give us electrical power consumption. As torque increases, we eventually stall or backdrive the motor as shown in the video below. At this point we have acheived the peak torque output of the motor at that RPM. The plot (and V = L*di/dt) suggest that for a motor that is not acheiving steady state current consumption for an inductor, as RPM increases, max torque decreases, because we are not giving enough time for current to fully develop in the inductor before commutation occurs and we attempt to reverse polarity and therefore current direction. + +We can also calculate mechanical power output at each increment by taking the product of torque and RPM. By dividing mechanical power output by electrical power input, we can determine motor efficiency across the entire torque speed curve. So our final plot shows us not only the standard torque speed curve (the interpolation of points spanning peak torque at each RPM), but also motor efficiency there as well. + + + +One really nice thing about this setup is that both motors are actively controlled by a single microcontroller, which is also performing all of the data collection. After a reset, the microcontroller waits for a computer to connect and open up serial communication (via a data collection script written in python), after which it will start the test and run it to completion autonomously. Then the data is written to a CSV and plots like the one above can be generated, all of which happens without user intervention. + +It would be fair to say that those peak values are the only really useful bits of data generated here, but I would argue that given how frequently open loops steppers are used, there are valuable insights to be had below that interpolated line. For example, if driving an electric vehicle with an open loop stepper (not recommended), this data informs us about the power consumption headroom we have by switching to a closed loop system (you don't get to choose torque demand for some commutation speed when driving on a road). For a closed loop motor, this data becomes much more relevant, which will be a good future direction to take the project. Several things to note from looking at the graph above: + + - All of the efficiencies at RPM = 0 are dark blue, or 0%. This makes sense considering we are doing 0 work at 0 RPM, and the product of (0 RPM x some torque = 0). + - Similarly all of lower torque values have efficiencies close to 0. Our open loop stepper is blindly dumping current into the motor windings, and it isn't until we actually start oposing that electrical power with the absorber, that we can actually say work is being done. + - There are anomalies in the peak torque and efficiency data for RPMs spanning 50-350 RPM. This happens for reasons I will discuss below, but I expect that with some tweaking I should be able to get much cleaner results in that RPM regime. + + +As expected, the absorber proved to be the most difficult system to integrate. Most dynamometers operate under a resistive, but not actively driven load, like an induction motor wired as an eddy current brake, or some mechanical system like a disc brake or flywheel. I wanted to pull useful data from the 0 and low RPM regime as well, which is often where steppers are driven, so I wanted an absorver that was also capable of actively generating a torque on the DUT. My initial thought was that by just using a brushed DC motor, I would be able to directly drive it with a variable power supply (fortunately I have one that's capable of taking analog 0-5V input from a micro as shown last week). By putting a diode in series with the power supply, I intended to prevent back EMF from flowing, which is problematic because it would generate an unwanted torque floor at higher RPM, as well and/or damage my switching power supply. What I had missed is that back EMF is actually generated in the same direction as the resistive torque I wanted to generate on my load, so I spent an embaressing amount of time flipping the diode and motor polarity back and forth trying to figure out what was happening. *It's worth noting that this system works for a configuration where I wanted to stall the motor in the forward direction, which is not an entirely un-useful test to run, but I don't think would agree with a properly run test. What I wound up doing is ditching the variable power supply (it's actually useful for sweeping through stepper input voltages), and running the absorber motor off of a fixed voltage driven through a micro controlled brushed motor driver (an H-bridge). This way I can control the absorber in two ways: + + - At low RPM I PWM the H-bridge between load and recirculation, which is standard fare for driving a brushed DC motor, generating an active torque on the DUT. + - At high RPM I PWM the H-bridge between high impedance and recirculation, which effectively turns it into an eddy current brake. The way the inductances of all of my motors stack up, the stepper will start stalling via this case at around 250 RPM. + + So that all actually seems to work quite well. The catch is that I am using a standard arduino analogWrite to generate those PWMs, which is fixed at 500 Hz without spending a day reading the SAMD51 datasheet and flipping registers to switch clocks/timer multiplexing/prescalers. Because 500 Hz is approaching cogging ripple of the brushed DC motor and stepper at certain RPMs, I believe I am getting a very choppy back torque on the stepper as I flip in and out of harmonics between the absorber and driver. Next steps here will be to actually go register spleunking and speed up that PWM frequency. + +### Future things to get to + +One very useful parameter space to explore will be the bounds on peak torque through increasing peak current limit. Let's imagine a 58mm long NEMA 23 stepper with 3 ohms of winding resistance, and 10 mH of winding inductance (made up numbers). The manufacturer will recommend some peak current for a motor with these parameters (guessing at 2A). I am still unsure if that peak current is thresholded by motor saturation, or temperature (what I think is more likely). With a thermocouple on the motor, I plan to add another dimension to sweep, which will be peak current in the motor. With this data it should be possible to really get into optimizing stepper closed loop stepper driving, where we could tap into a thermally not-sustainable current regime for added torque over some stretch of time. This data would also allow us to make more informed decisions when selecting between steppers with varying winding resistance and inductance, when trading off between peak speed and torque. Lots more to get to for this section, but I am running out of time for this week. + + +<figure class="video_container"> + <iframe src="https://player.vimeo.com/video/525624403?badge=0&autopause=0&player_id=0&app_id=58479" frameborder="0" allowfullscreen="true"> </iframe> +</figure> + +## Week 2 3/11/21 + +[<img src="images/3_10_21_frame.jpg" width="900">](https://gitlab.cba.mit.edu/davepreiss/motor-testing-data/-/blob/master/images/3_10_21.mp4) + +Picture above is a link to a video. Still waiting on an INA260 from digikey for power measurement, after which I should be able to fully characterize steppers (and other motors) with speed-torque curves heatmapped with efficiency. This should look like the image below: + + + Below is a high level overview of the dynamometer showing each major subsystem (aside from the power measurement IC which is being shipped from digikey). Each one is discussed in further detail below (please pardon my use of a breadboard at this stage :D).  +## Week 1 3/4/21 + ### RPM Measurement RPM is measured with a 32ppr optical quadrature encoder mounted to the back of the absorber. Only one channel of the encoder is used, but rising and falling edges are both used. Measuring RPM is then done with a single interrupt triggering a counter and a timer. @@ -30,9 +145,15 @@ Because the power supply can only be controlled to 24V with our 3v3 analog outpu  +# Pre-HTMS: Stall Condition Motor Test Rig -# Stall Condition Motor Test Rig +### Goals +* Standardize peak torque data relative to power (servos are typically giving peak torques when subject to many amps of current) +* Add real time temperature data to get an idea of sustainability of above ^ +* Better understand tradeoffs between DC motors (hobby servos) - Steppers - BLDCs (both with and without reduction) +* Inform design/selection for future actuator use cases +* Complement a [real dynamometer](https://build-its.blogspot.com/2019/12/motor-dynamometer.html) to acheive higher fidelity at stall condition ### [Link to motor testing data](https://docs.google.com/spreadsheets/d/1aPr13svrutCMsQIfM--7oKSVCTAup2I7W5gBSr05Mjo/edit#gid=883650838) diff --git a/images/3_10_21.mp4 b/images/3_10_21.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..25e11022de560076af6c94c1d1f5566f08b6c7e5 Binary files /dev/null and b/images/3_10_21.mp4 differ diff --git a/images/3_10_21_frame.jpg b/images/3_10_21_frame.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5330927e2d3efaed5749e17e56670580633cb312 Binary files /dev/null and b/images/3_10_21_frame.jpg differ diff --git a/images/dyno/23HS30_2804S.png b/images/dyno/23HS30_2804S.png new file mode 100644 index 0000000000000000000000000000000000000000..938d9acf0f689d527460a0daebcb3e42aaa75c74 Binary files /dev/null and b/images/dyno/23HS30_2804S.png differ diff --git a/images/dyno/currentSweep.png b/images/dyno/currentSweep.png new file mode 100644 index 0000000000000000000000000000000000000000..704fc4c8bbab3e02acb5c070288e4b03d59b0280 Binary files /dev/null and b/images/dyno/currentSweep.png differ diff --git a/images/dyno/curveSketch.jpg b/images/dyno/curveSketch.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bca30346dd5ff743746665063376444f80d52408 Binary files /dev/null and b/images/dyno/curveSketch.jpg differ diff --git a/images/dyno/flir.png b/images/dyno/flir.png new file mode 100644 index 0000000000000000000000000000000000000000..82c3e92c378fc13481a25066ba93927c9c482758 Binary files /dev/null and b/images/dyno/flir.png differ diff --git a/images/dyno/saturationSweep.png b/images/dyno/saturationSweep.png new file mode 100644 index 0000000000000000000000000000000000000000..dfaaf351eb910d5b03c266d91dc5b3b943f7f706 Binary files /dev/null and b/images/dyno/saturationSweep.png differ diff --git a/images/dyno/tempSweep.png b/images/dyno/tempSweep.png new file mode 100644 index 0000000000000000000000000000000000000000..8cc7fe33954797140bc4903dae4874fd5f7083b7 Binary files /dev/null and b/images/dyno/tempSweep.png differ diff --git a/images/dyno/testData.csv b/images/dyno/testData.csv new file mode 100644 index 0000000000000000000000000000000000000000..4fa6ad772c7e25fcfe3261e3a9b82eb5c6a15405 --- /dev/null +++ b/images/dyno/testData.csv @@ -0,0 +1,367 @@ +BEGIN TEST +NEMA23 Length=58mm R=3ohms I=10mH +Microstepping: 16 +Current Limit: 750 +Voltage Setpoint: 20026.25 +BEGIN SWEEP AT RPM: 0.00 +0,94,20026.25,68.75 +0,147,20023.75,85 +0,31,20021.25,76.25 +0,78,20026.25,96.25 +0,107,20023.75,72.5 +0,93,20023.75,96.25 +0,75,20023.75,72.5 +0,188,20023.75,83.75 +0,71,20022.5,97.5 +0,137,20022.5,73.75 +0,115,20022.5,75 +0,50,20026.25,88.75 +0,78,20025,75 +0,67,20021.25,96.25 +0,166,20021.25,76.25 +0,84,20023.75,90 +0,155,20025,97.5 +0,174,20022.5,73.75 +0,154,20021.25,98.75 +0,119,20026.25,96.25 +0,142,20023.75,90 +0,229,20022.5,100 +0,118,20022.5,68.75 +0,110,20022.5,88.75 +0,182,20025,85 +0,124,20027.5,91.25 +0,187,20022.5,82.5 +0,73,20023.75,88.75 +0,175,20022.5,85 +0,193,20025,83.75 +0,188,20025,91.25 +0,216,20026.25,88.75 +0,337,20023.75,85 +0,524,20028.75,97.5 +0,706,20026.25,98.75 +0,940,20026.25,73.75 +0,1212,20031.25,76.25 +0,1549,20028.75,86.25 +0,2104,20031.25,92.5 +0,3364,20025,97.5 +0,4290,20028.75,87.5 +0,5653,20027.5,96.25 +0,7429,20032.5,85 +0,8539,20035,97.5 +0,9125,20037.5,72.5 +0,10931,20037.5,97.5 +0,12484,20033.75,91.25 +0,16893,20033.75,86.25 +0,19579,20032.5,88.75 +0,21704,20031.25,88.75 +0,23212,20030,72.5 +0,24747,20035,85 +0,25956,20030,87.5 +0,28883,20030,75 +0,30569,20030,90 +0,31865,20032.5,80 +0,34438,20026.25,73.75 +0,35664,20028.75,75 +0,37353,20028.75,100 +0,38640,20030,72.5 +0,39875,20032.5,71.25 +0,41263,20027.5,72.5 +0,42058,20033.75,73.75 +0,43506,20028.75,87.5 +0,43860,20035,101.25 +0,44060,20036.25,68.75 +0,44521,20032.5,73.75 +0,45091,20035,72.5 +BEGIN SWEEP AT RPM: 50.00 +50,1009,20018.75,116.25 +50,-226,20021.25,123.75 +50,3290,20021.25,120 +50,-971,20021.25,141.25 +50,2773,20020,142.5 +50,1635,20018.75,127.5 +50,-510,20022.5,110 +50,3731,20021.25,111.25 +50,-639,20021.25,116.25 +50,2676,20021.25,125 +50,1889,20021.25,126.25 +50,-607,20022.5,132.5 +50,3693,20025,152.5 +50,78,20021.25,111.25 +50,1975,20020,123.75 +50,2404,20021.25,116.25 +50,-526,20020,115 +50,3293,20018.75,107.5 +50,872,20020,132.5 +50,830,20020,147.5 +50,3184,20021.25,138.75 +50,-482,20021.25,113.75 +50,3149,20022.5,118.75 +50,1504,20023.75,130 +50,-28,20018.75,141.25 +50,3853,20017.5,128.75 +50,-8,20020,137.5 +50,3986,20022.5,146.25 +50,3371,20023.75,105 +50,1955,20022.5,108.75 +50,7020,20025,118.75 +50,8359,20020,146.25,, +50,9753,20018.75,147.5 +50,8445,20025,150 +50,14142,20022.5,177.5 +50,13877,20022.5,106.25 +50,16543,20025,122.5 +50,19540,20026.25,113.75 +50,17787,20020,168.75 +50,23913,20016.25,148.75 +50,24382,20018.75,296.25 +50,25595,20026.25,352.5 +50,30341,20012.5,315 +50,29146,20016.25,381.25 +50,35076,20021.25,303.75 +50,1993,20033.75,431.25 +50,2126,19987.5,127.5 +50,1623,20023.75,341.25 +50,-588,20096.25,-118.75 +50,1368,19935,213.75 +50,1021,20022.5,111.25 +50,-315,20075,47.5 +50,1459,20036.25,333.75 +50,3053,20023.75,130 +BEGIN SWEEP AT RPM: 100.00, +100,147,20012.5,211.25,, +100,-111,20018.75,193.75 +100,2086,20020,150 +100,3397,20016.25,187.5 +100,1577,20018.75,151.25 +100,-431,20017.5,246.25 +100,707,20021.25,175 +100,3132,20016.25,186.25 +100,3090,20020,172.5 +100,569,20017.5,171.25 +100,-112,20015,216.25 +100,1946,20021.25,137.5 +100,3625,20017.5,195 +100,2247,20020,173.75 +100,6,20011.25,171.25 +100,690,20013.75,186.25 +100,3123,20017.5,140 +100,3726,20016.25,172.5 +100,1540,20015,145 +100,246,20011.25,181.25 +100,1852,20015,160 +100,4271,20018.75,140 +100,5097,20015,171.25 +100,2662,20016.25,160 +100,3124,20015,180 +100,5416,20017.5,201.25 +100,8139,20016.25,156.25 +100,7671,20012.5,195 +100,7290,20017.5,201.25 +100,10999,20012.5,248.75 +100,14621,20013.75,252.5 +100,16729,20016.25,223.75 +100,16046,20017.5,260 +100,18306,20016.25,252.5 +100,22502,20002.5,283.75 +100,25682,20000,342.5 +100,26464,19997.5,391.25 +100,26307,20026.25,423.75 +100,29519,20006.25,397.5 +100,34304,20022.5,347.5 +100,36862,20020,380 +BEGIN SWEEP AT RPM: 150.00, +150,1290,20013.75,236.25,, +150,-159,20012.5,246.25 +150,-352,20011.25,217.5 +150,997,20013.75,232.5 +150,2623,20011.25,211.25 +150,2435,20012.5,222.5 +150,875,20012.5,221.25 +150,-291,20013.75,233.75 +150,-147,20015,263.75 +150,1492,20012.5,233.75 +150,2960,20015,216.25 +150,2506,20015,213.75 +150,939,20012.5,270 +150,29,20012.5,273.75 +150,880,20013.75,252.5 +150,2547,20012.5,218.75 +150,3684,20011.25,225 +150,3150,20015,253.75 +150,1687,20011.25,252.5 +150,885,20013.75,266.25 +150,2246,20010,238.75 +150,5649,20010,231.25 +150,14228,20003.75,325 +150,13601,20008.75,335 +150,11993,20007.5,321.25 +150,11562,20007.5,298.75 +150,15434,20000,303.75 +150,19404,20000,323.75 +150,22057,20003.75,360 +150,23014,20002.5,372.5 +150,23424,20003.75,363.75 +150,24846,19993.75,403.75 +150,28401,19993.75,400 +150,33169,19998.75,447.5 +150,36467,19998.75,466.25 +150,-531,20020,163.75 +BEGIN SWEEP AT RPM: 200.00, +200,1196,20008.75,266.25,, +200,251,20012.5,310 +200,1877,20008.75,267.5 +200,-245,20011.25,293.75 +200,2107,20006.25,257.5 +200,33,20010,272.5 +200,1428,20007.5,272.5 +200,943,20010,290 +200,913,20008.75,268.75 +200,1995,20008.75,301.25 +200,262,20006.25,283.75 +200,2749,20002.5,271.25 +200,773,20008.75,263.75 +200,2947,20001.25,281.25 +200,1734,20005,282.5 +200,2663,20001.25,268.75 +200,3333,20008.75,286.25 +200,2428,19998.75,278.75 +200,4571,20005,287.5 +200,2952,20002.5,308.75 +200,5881,20002.5,292.5 +200,11085,20000,416.25 +200,26642,19988.75,490 +200,26597,19993.75,530 +200,26361,19995,480 +200,27814,19987.5,527.5 +200,28241,19988.75,553.75 +200,33519,19986.25,585 +200,33403,19990,607.5 +BEGIN SWEEP AT RPM: 250.00, +250,1189,20006.25,265,, +250,913,20008.75,333.75 +250,736,20003.75,293.75 +250,549,20002.5,303.75 +250,557,20001.25,335 +250,662,20002.5,330 +250,639,20002.5,328.75 +250,762,20003.75,333.75 +250,1131,20002.5,333.75 +250,1568,20005,358.75 +250,2012,20003.75,347.5 +250,2529,20003.75,310 +250,3151,20005,316.25 +250,3741,20002.5,327.5 +250,4354,20002.5,340 +250,4986,20001.25,340 +250,5530,20003.75,336.25 +250,6013,20001.25,341.25 +250,6332,19996.25,381.25 +250,7319,19993.75,400 +250,8385,19993.75,410 +250,21808,19983.75,597.5 +BEGIN SWEEP AT RPM: 300.00, +300,1173,20001.25,281.25,, +300,1463,20008.75,347.5 +300,962,19996.25,356.25 +300,1312,20005,298.75 +300,1540,20007.5,338.75 +300,1034,20000,336.25 +300,1698,20005,296.25 +300,1784,20003.75,378.75 +300,1651,19996.25,358.75 +300,2523,20003.75,323.75 +300,2538,20007.5,377.5 +300,2850,19998.75,353.75 +300,3818,20001.25,378.75 +300,3999,20000,396.25 +300,4624,19992.5,388.75 +300,5594,19998.75,368.75 +300,5893,20000,400 +300,6646,19992.5,433.75 +300,7644,19993.75,421.25 +300,8515,19995,437.5 +300,10855,19987.5,467.5 +300,28992,19972.5,773.75 +BEGIN SWEEP AT RPM: 350.00, +350,981,20000,318.75,, +350,909,20006.25,386.25 +350,902,20003.75,386.25 +350,974,20002.5,292.5 +350,1160,20003.75,393.75 +350,1219,20002.5,402.5 +350,1381,20003.75,308.75 +350,1754,19997.5,313.75 +350,2111,19996.25,388.75 +350,2530,20005,358.75 +350,2998,20003.75,370 +350,3566,19993.75,386.25 +350,4274,20001.25,397.5 +350,4868,19998.75,452.5 +350,5442,19992.5,391.25 +350,6441,19991.25,400 +350,7238,19992.5,497.5 +350,7956,19992.5,521.25 +350,9332,19990,452.5 +350,10763,19983.75,546.25 +350,13486,19978.75,633.75 +BEGIN SWEEP AT RPM: 400.00, +400,969,19996.25,390,, +400,1148,20000,312.5 +400,1247,19998.75,365 +400,1103,20006.25,380 +400,971,20000,400 +400,1117,19993.75,380 +400,1424,20000,368.75 +400,2136,19993.75,478.75 +400,2786,19997.5,416.25 +400,3407,19990,393.75 +400,3755,19995,370 +400,4228,20002.5,478.75 +400,4858,19997.5,471.25 +400,5631,19983.75,452.5 +400,6890,19985,485 +400,8240,19991.25,561.25 +400,9227,19985,567.5 +400,10089,19982.5,507.5 +400,11731,19981.25,585 +400,13050,19983.75,645 +400,17192,19971.25,775 +BEGIN SWEEP AT RPM: 450.00, +450,457,19996.25,423.75,, +450,1312,19997.5,388.75 +450,558,19998.75,392.5 +450,1553,20000,385 +450,981,19995,387.5 +450,2074,19997.5,335 +450,1792,19996.25,382.5 +450,2974,19998.75,358.75 +450,2986,19988.75,436.25 +450,4149,19991.25,422.5 +450,4389,19987.5,493.75 +450,5516,19990,493.75 +450,6170,19987.5,540 +450,7123,19985,590 +450,8135,19981.25,610 +450,9538,19982.5,636.25 +450,10624,19972.5,665 +450,12061,19970,673.75 +450,14614,19968.75,681.25 +450,15855,19970,677.5 +BEGIN SWEEP AT RPM: 500.00, +500,1835,20010,333.75,, +500,1934,19986.25,586.25 +500,1790,19992.5,466.25 +500,1883,20012.5,286.25 +500,2049,19990,501.25 +500,2234,19986.25,495 +500,2633,20000,307.5 +500,3275,19985,521.25 +500,4025,19977.5,552.5 +500,4904,19997.5,407.5 +500,5957,19981.25,608.75 +500,6998,19978.75,642.5 +500,8207,19985,561.25 +500,9168,19983.75,586.25 +500,10407,19977.5,645 +500,11920,19975,637.5 +END TEST, diff --git a/images/dyno/testData.jpg b/images/dyno/testData.jpg new file mode 100644 index 0000000000000000000000000000000000000000..820402955e770ac5c8001ba58c0e5eb3230d1219 Binary files /dev/null and b/images/dyno/testData.jpg differ diff --git a/images/dyno/thermocouple.png b/images/dyno/thermocouple.png new file mode 100644 index 0000000000000000000000000000000000000000..5c457d8f88bf5e0c0c343cb459bc0a96e65f4fe4 Binary files /dev/null and b/images/dyno/thermocouple.png differ