Some more realistic OpenFOAM runs

As a first test, I am trying to reproduce the graphs of coefficient of lift \(C_l\) and coefficient of drag \(C_d\) as functions of angle of attack \(\alpha\) from http://airfoiltools.com/airfoil/details?airfoil=naca2408-il. The airfoil is 1m long, the airspeed is 10m/s, and the kinematic viscosity \(\nu\) is 1E-5 for a Reynolds number of 1E6. \(C_l\) and \(C_d\) are measured for \(\alpha = \{-5,0,5,10,15,20\}\). I am unclear on the reference length and area in \(C_l\) and \(C_d\), but that will be obvious as a constant factor between the graphs.

On the recommendation of a friend (I do not want to get stuck down any rabbit holes) these use the SST k-omega turbulence model. The constants for incoming turbulence intensity are taken from: k-Omega-SST-DES-Report. At high angles of attack the airfoil sheds vortices:

And the plot of \(C_l\) and \(C_d\) vs \(\alpha\):

Error bars are given from the standard deviation of the forces. The vortex shedding causes periodic changes in each coefficient. I am bothered that \(C_l\) doesn’t turn over at \(\alpha\approx 15^{\circ}\) as for the airfoil tools database, and am now trying to figure out what causes the difference.

OpenFOAM Airfoils

I’ve been playing with OpenFOAM recently and ended up writing my own mesher. It’s been educational to work with a code which uses unstructured meshes for once. See https://github.com/garthwhelan/openfoam-mesher-stuff for details. So far all it does is generate hexahedral meshes with Cartesian coordinates, and merge boundary faces/points if two boundary patches share the same coordinate. It’s pretty straightforward to build more complicated meshes by deforming and combining Cartesian ones. For example, C meshes for airfoils can be made by deforming a rectangular Cartesian mesh so that the right edge surrounds an airfoil and then combining the interface behind the airfoil (automatically removing the duplicate faces and faces that are now internal). O meshes would involve doing the same thing, but using the entire right edge around the airfoil and merging what were the top and bottom edges.

Ultimately, I would like to build an RC plane and be able to say some of the design was inspired by CFD simulations, but this is a tall order. I think I will make sure that I can match the information on www.airfoiltools.com for \(C_l\) and \(C_d\) for a named airfoil and then use OpenFOAM to motivate the design of the control structures.

After going through some tutorials, I tried a (very nonphysical) run with an airfoil. The graph below was generated with icoFoam using a 1m airfoil at 1m/s, and with a realistic air viscosity. The boundary conditions are probably something nonphysical. Since then I’ve moved to using the freestream boundary conditions, pisoFoam, and RANS.

Paraview is actually really nice

Biofeedback Smartwatch Update

I’ve been busy recently, with finishing my doctorate and a month long trip. However, I now have a fully wireless biofeedback smartwatch prototype.

The picture is not fully assembled, but everything works other than the lack of a power switch, usb plug, and IC for charging the Li+ battery on the back. I’ve switched from using a naked nRF52810 IC to a TAIYO YUDEN module, it is more expensive, but I was having a lot of trouble getting antennas to work. The wires to the right are for programming with SWD, and the pair of magnet wires soldered to the board itself are for power so I don’t rundown the battery in testing. To the right of the module are two holes for debugging with UART; it’s been really helpful to use that and the logic analyzer to test things during development.

On the finger strap are two electrodes for the GSR voltage bridge, and the MAX30102 SPO2 sensor, which is soldered onto a PCB out of view.

I’m using the following program to activate the ADC and SPO2 sensor and broadcast data over bluetooth. I’m using the nordic UART profile, which contains two characteristics, a read and a write one. I’ve had to learn a lot more about bluetooth than I wanted to for this project.

https://github.com/garthwhelan/NRF-smartwatch/tree/master

You can see in the above picture I can stream to my laptop, which live plots the data with matplotlib. I’ve had issues with plot update speeds… it sounds like pyqtgraph is a lot faster but not what I want. I’m probably going to try gnuplot if this is still an issue.

On the plotting side, it’s the same as usual, except with the source of data being:


subprocess.Popen("sudo gatttool -i hci0 -t random -b (nrf mac address) --char-write-req -a 0x10 -n 0100 --listen",shell=True,stdout=subprocess.PIPE)

Which writes 1 (0100 reverse endian) to the handle of the characteristic to enable notifications (0x10). Again, there’s a better way to do this with the actual gatt libraries.

In the end I’m pretty happy with everyting. The GSR data is a lot better since switching to a TI adc (ads1246), and the setup is not that encumbering overall. I plan on working on more data analysis for biofeedback (e.g. getting actual SPO2 values, heart rate counters,…) before doing anything with a phone app.

HX711 – Dynamometer part 1

Grip strength can be used as a measure of overtraining.

There are ADC + strain gauge meters on ebay for hobby bodyweight scales (HX711) that should be good for measuring up to around 200kgs. I ordered one and plan to put the gauges between a pair of half cylinders of wood to measure grip strength.

The HX711 can communicate with microcontrollers with a 2 wire interface like I2C. I’ve gotten this working with the Nucleo and tested it by having the Nucleo output a sin wave and reading the voltage that the HX711 measured.

project stuff here, remember that all the Nucleo stuff is compiled using the mbed compiler

Voltage measured by the HX711. Output is in two’s complement, which is why the sin wave is split between top and bottom. You can see the quantization in the DACs output because there’s a minimum 64 fold amplification for the HX711. This means that even a tiny voltage swing will saturate the output.

Galvinic Skin Response and Hand Temperature

Two biofeedback sensors I can probably get working faster than the EEG are hand temperature and galvinic skin response. Hand temperature biofeedback is mostly used to train relaxation. Adrenaline restricts bloodflow to the skin and hands, so by training yourself to warm your hands you can learn to reduce adrenaline levels. Galvinic skin response is similar. People sweat more when nervous, filling sweat ducts with sweat. This is most pronounced on the hands and feet. Sweating reduces skin resistance by providing a conductive channel into the skin. This effect happens in seconds, and is used in polygraphs to detect lies.

For the most part, the resistance inside the body is low enough not to matter when measuring galvinic skin response. The simplest way to measure skin resistance is to put a current through two electrodes in contact with the skin and measure the voltage difference. This is usually done with electrodes on the index and ring fingers.

(For much more detail on measuring galvinic skin response, see Electrodermal Activity by Wolfram Boucsein)

While high temperature measurements usually use thermocouples, the easiest way to measure hand temperature is by using thermistors. The thermistors linked go between about 80k-100k Ohms around 70-100F. They are incredibly small, which gives them really fast response times and makes it easy to keep them around skin temperature.

For measuring each of these resistances, I constructed voltage bridges with instrumentation amplifiers to increase the voltage range. I then used the integrated ADCs in the Nucleo microcontroller I have to measure the voltage.

Set up the voltage bridge with R3/R4 to be a bit below the lowest voltage between R1/R5. Select gain resistor so that Vout is below 3.3V when R1 at its highest. This setup can be used with both GSR and hand temp, but will require different resistors. GSR would probably benefit with variable resistors to set gain and comparison voltage.

See https://github.com/garthwhelan/Nucleo-ADC/tree/master for example which reads the ADC 10 times a second and communicates it to a python program on a host which plots the output.

Plot of voltage measured for thermistor as I grabbed an icepack at t=50 and t=110.
Voltage for skin resistance, again grabbing an icepack at T=220

Like the EEG project, actually having a wearable probe is difficult. For GSR, I used the following copper coils:

I also tried mounting the thermistors in sections of pipe which I could use as GSR electrodes. While it looks neat, I think it will require rings which fit better.

Getting a Nucleo to work

Nucleos are very nice little dev boards for STM32 microcontrollers. I’ve been using a Nucleo-f446 for some embedded projects over the last two years, but always reluctantly because it would only work with my worst laptop which I keep around specifically for this purpose. They have integrated ST-Link programmers/debuggers which I’ve had issues using due to USB bugs. After a long time I’ve finally gotten it working.

When plugged in over USB, the Nucleo should register as both a 88k block device and as a serial console (/dev/ttyACM[0-9]). The Nucleo is programmed just by moving files onto the block device, and can be interacted with over the serial terminal. On some machines it would just show up as a block device, and on others it would not show up at all. When plugged in, the following would be outputted to dmesg:


[  555.818115] usb 5-2: new full-speed USB device number 5 using xhci_hcd
[  555.989838] usb 5-2: New USB device found, idVendor=0483, idProduct=374b
[  555.989840] usb 5-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  555.989842] usb 5-2: Product: STM32 STLink
[  555.989844] usb 5-2: Manufacturer: STMicroelectronics
[  555.989845] usb 5-2: SerialNumber: 0669FF515056805087142030
[  555.990035] xhci_hcd 0000:0a:00.3: ERROR: unexpected command completion code 0x11.
[  555.990320] usb 5-2: can't set config #1, error -22

I initially thought the kernel was responsible with cdc-acm. I’m not going to describe all the things I’ve tried and instead skip right to the solution. The Nucleo only properly registers when I plug it into my only USB3.1 port instead of any of the USB3.0 ports.

Edit: It also appears not always enumerate unless there are no periphereals plugged into it.

Edit2: I’ve moved to using SW4STM32, and the automatic stlink firmwire update allowed me to use it with any usb plug on my desktop.

Software I use

I’m a big fan of various interfaces which are meant to be exclusively keyboard driven:

urxvt – Replacement for xterm. See the stumpwm config file below to see what options I use.

sxiv – Simple lightweight image viewer with vim-like bindings

zathura – PDF/PS/DjVu viewer with vim-like bindings

emacs – my first IDE and now I’m too old to change. I’veĀ  used vim, but I just enjoy pressing 3 keys at once more than having modal editing. Emacs lisp sucks so I tried climacs, a common lisp emacs port, but it’s not finished yet.

qutebrowser – Internet browser in Qt with vim-like bindings. Works a ton better than pentadactyl/vimperator/tridactyl as far as being keyboard driven and not incredibly slow. Those are also very frustrating with firefox/chrome because addons break regularly. Surprisingly, given that it’s meme software, qutebrowser actually works with almost every site I’ve tried.

stumpwm – Tiling window manager, a common lisp port of ratpoison. Wastes no screen space and is entirely keyboard driven. Can also be significantly changed when running live because it’s in common lisp. Again, it works surprisingly well, I’ve done terrible terrible things and I think I’ve only had it crash once. I’ve also had weird experiences with fullscreen stuff with games or streaming sites on other linux window managers, and stumpwm has always worked how I want. Here’s my .stumpwmrc config file:

https://github.com/garthwhelan/dotfiles/blob/master/.stumpwmrc

Some excerpts:

A sys-show-info that displays ram use, battery use, sound levels, and screen brightness when invoked:


(defun sys-show-info ()
  (defparameter temp-string1 (run-shell-command "free -h | grep Mem: | sed s/' \\+'/' '/g" t))
  (defparameter positions1 (all-positions #\Space temp-string1))
  (defparameter temp-string2 (run-shell-command "acpi" t))
  (defparameter positions2 (all-positions #\Space temp-string2))
  (echo-string (current-screen) (concatenate 'string (subseq temp-string2 (caddr positions2) (- (length temp-string2) 1)) " | Volume: " (subseq (run-shell-command "amixer get Master | sed "\
s/ /\\n/g" | grep -m 1 %" t) 1 4) " | Mem: " (subseq temp-string1 (cadr positions1) (cadddr positions1)) " | " (time-format *time-format-string-default*) " | Brightness: " (subseq (run-shel\
l-command "cat /sys/class/backlight/intel_backlight/brightness" t) 0 4)))); " | " (run-shell-command "iw dev wlp1s0 link | grep SSID" ))))

(define-key *root-map* (kbd "a") "sys-info")

Taking screenshots with scrot:


(define-key *root-map* (kbd "h") "exec scrot -u /home/dont/stumpwm_screenshots/%Y-%m-%d-%T-screenshot.png")

Opening urxvt with desired options:


(define-key *root-map* (kbd "c") "exec urxvt -bg 'black' -fg 'white' +sb -sl 65535 -b 0 -w 0 -letsp -1 -fn "xft:bitstream vera sans mono:size=8:antialias=True,xft:unifont"")

You can also do stuff with ratclick to move the mouse pointer and click. I played with some stuff for that but it never worked satisfactorily. For example one thing I tried was to bring up an overlaid grid and have the pointer move to the grid depending on what button you pressed. After this finer stuff could be done with relative motion. I’m not sure if there is actually a way to completely replace the mouse in a way that I would be happy with.

Ubuntu – I worked from Ubuntu->Fedora->Arch->Gentoo and stayed there for several years before moving back. Gentoo made me learn a ton of stuff about linux, but at this point I want software to ‘just werk’ instead of needing fixes/configuration.