README.md 19.1 KB
Newer Older
David Preiss's avatar
David Preiss committed
1
2
# Dynamometer

3
4
5
6
## 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.

David Preiss's avatar
David Preiss committed
7
![comparePlot1.png](./images/dyno/comparePlot2.png)
8
9
10
11
12
13
14
15
16
17
18

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).

David Preiss's avatar
David Preiss committed
19
![comparePlot2.png](./images/dyno/comparePlot1.png)
20
21
22
23
24
25
26
27

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.

![timerRegisters.png](./images/dyno/timerRegisters.png)

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
28

David Preiss's avatar
David Preiss committed
29
30
[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.

31
32
33
34
35
36
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.

![alt_text](images/dyno/testData.jpg "image_tooltip")

David Preiss's avatar
David Preiss committed
37
38
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.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allowfullscreen="true"> </iframe>
</figure>

62
## Week 2 3/11/21
63

David Preiss's avatar
David Preiss committed
64
65
[<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)

66
67
68
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:

![alt_text](images/dyno/curveSketch.jpg "image_tooltip")
69

David Preiss's avatar
David Preiss committed
70
71
72
73
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).

![alt_text](images/dyno/overviewTemp.png "image_tooltip")

74
## Week 1 3/4/21
75

David Preiss's avatar
David Preiss committed
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
### 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.

![alt_text](images/dyno/encoder.png "image_tooltip")

### Torque Measurement

From the pictures below you can get an idea of how torque from the test motor travels through the frame and is ultimately constrained by the load cell. From early testing this system is sensitive down to the g*mm.

![alt_text](images/dyno/torqueTransmit.png "image_tooltip")

Torque is measured with a [5kg load cell](https://www.phidgets.com/?tier=3&catid=9&pcid=7&prodid=224) and a [HX711 Load Cell Amp](https://www.sparkfun.com/products/13879) on a breakout board with serial output using its own protocol (it doesn't actually use a peripheral). Torque was calibrated using 1kg and 0.5kg weight at the 75mm moment arm shown below. With the configuration below, the setup is capable of measuring a peak torque of 54kgcm, which can be increased to 208kgcm with a 20kg load cell (or ~20Nm).

![alt_text](images/dyno/cad.png "image_tooltip")

### Absorber and Back-Torque Generation

A brushed DC motor with a protected variable power supply is being used as the absorber, with the primary benefit of low RPM torque generation. Alternative absorbers considered were an eddy current brake (or an industrial induction motor with variable DC applied to one of the windings), or a bicycle disc brake.

Here's a link to the [BK-1687B](https://bkpmedia.s3.amazonaws.com/downloads/manuals/en-us/168xB_manual.pdf) power supply which can accept 0-5V voltage and current control (also via USB and the DRO). The motor is a Midwest Motion Products brushed DC motor rated to 12A and 24V and 2000 rpm MMP D33 655E 24V. The power supply is protected via a diode in series with the absorber motor, which effectively keeps the absorber in open circuit until the power supply overcomes the back EMF of the absorber, and then (at least from my understanding) the DC motor starts generating torque proportional to the forward current. Inside the variable power supply is a rectifier and buck converter capable of closed loop voltage and current control. It's dangerous to drive large inductive loads (like motors) with switching power supplies because of [flyback](https://en.wikipedia.org/wiki/Flyback_diode), and so there are two diodes oriented as shown below, where D1 keeps the absorber's windings (while being driven) in an effectively open circuit, and D2 is insurance in case that diode fails.

Because the power supply can only be controlled to 24V with our 3v3 analog outputs, a non-inverting op amp (OPA2337) was used to achieve the full 0-5v range. Because most of the micros that I use operate at 3v3 I am planning to permanently adhesive the breadboard that I used to do this to the back of the power supply (also convenient because the power supply has both the 0 and 5V rail voltages required.

![alt_text](images/dyno/nonInverting.png "image_tooltip")

102
# Pre-HTMS: Stall Condition Motor Test Rig
David Preiss's avatar
initial  
David Preiss committed
103

David Preiss's avatar
David Preiss committed
104
105
106
107
108
109
### 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
David Preiss's avatar
David Preiss committed
110
* Complement a [real dynamometer](https://build-its.blogspot.com/2019/12/motor-dynamometer.html) to acheive higher fidelity at stall condition
David Preiss's avatar
initial  
David Preiss committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

### [Link to motor testing data](https://docs.google.com/spreadsheets/d/1aPr13svrutCMsQIfM--7oKSVCTAup2I7W5gBSr05Mjo/edit#gid=883650838)

This rig allows for peak torque measurements at stall for a variety of actuators, and precise measurements of torque ripple (in motors with less/no reduction). It also allows for measurement of torque required for backdrivability, particularly in motors with significant amounts of reduction, as well as angular jitter from the motor's feedback loop.

Measurements include torque and rotational position and a 5kg (interchangeable) load cell with an [HX711 amplifier](https://www.sparkfun.com/products/13879) and an [AMS 5047D](https://ams.com/as5047d) rotary encoder measuring 14 bits of shaft rotation. The stepper shown below is just a shell for mounting the shaft, and has had its rotor removed and replaced with a dummy stainless shaft (to eliminate cogging). The EDM'd 1-piece shaft coupler shown in the photo below added a ton of torsional elasticity to the measurement and was later replaced with a spider'd shaft coupling.  


![alt_text](images/image1.png "image_tooltip")


![alt_text](images/image2.png "image_tooltip")


![alt_text](images/image3.png "image_tooltip")