UltrasonicPlayer: Difference between revisions

From RevSpace
Jump to navigation Jump to search
mNo edit summary
 
(73 intermediate revisions by the same user not shown)
Line 13: Line 13:
The player emulates (social) bat calls which attracts the bats to the net, increasing the chance for them to be caught.
The player emulates (social) bat calls which attracts the bats to the net, increasing the chance for them to be caught.


The ultrasonic player acts as a USB sound card with high sampling rate plus a speaker to turn it into actual ultrasonic audio.
Another use case is to use it as an educational tool, to train people in the use of a bat detector.
You have to provide a device with a media player yourself, like a tablet or a laptop.
The player makes it easy to play the exact same sound again and again, allowing people to experiment with finding the best setting for their equipment and to improve their determination skills.
 
The ultrasonic player consists of a USB sound card with high sampling rate plus a speaker to turn it into actual ultrasonic audio.
A built-in Linux single-board-computer (something like a Raspberry Pi) controls playback of audio files.
The idea is that you prepare one or more USB sticks with bat calls and just plug one in the player, then the player automatically plays them in a loop


== Status ==
== Status ==
2016-10-11: received the amplifier boards.
 
2016-10-02: ordered the parts (USB audio, amplifier, a few step-up circuits).
=== Where this project could use some help with ===
 
Help wanted:
* put it in a robust practical box with batteries
* find a practical way to put files on it
* find a practical way to start/stop playback
* marketing
 
=== Time line ===
  2018-04-01: I have a box with the piezo speaker mounted in it. Still a bit stuck on the auto-play-on-USB-plugin stuff. First, I could just play back audio from a specific directory first.
  2017-10-10: basically I'm stuck on the software part, unable to decide how I should solve how to play audio files on USB stick plugin, I've got several hints but no definite solution. Getting more hints like "why *don't* you try X" are confusing the issue more. Also a bit stuck on the construction part (housing, etc.)
  2017-06-24: successfully played audio back from a raspberry pi 3, running the amplifier from one of the USB ports. The rpi3 shows a little lightning bolt indicating undervoltage while playing.
  2017-06-18: realized that an orange pi zero is not going to work: it doesn't have enough USB ports
  2017-06-16: playing a bit with udev scripts to automate actions upon USB stick plugin: I can do short actions (like mount/unmount) but no longer running actions from udev!
  2017-05-01: replaced a feedback resistor on the amplifier, to reduce the gain from about 30 to 3, this also makes it easier to adjust the gain using the potmeter
  2017-04-30: found the schematic for the amplifier, plan to modify it for lower gain (better level control and higher bandwidth)
  2017-04-16: created a [https://www.youtube.com/watch?v=1oRPJGr89Nc video of current progress].
  2016-10-11: received the amplifier boards.
  2016-10-02: ordered the parts (USB audio, amplifier, a few step-up circuits).


Next steps:
Next steps:
* <del>measure the frequency range of the USB audio card, using artificial waveform(s), like sweeps and fixed-frequency tones. I can create these waveform in Audacity (which supports the 384 kHz sample rate).</del>
* just play back stuff in a loop from a fixed directory on the sd card, using [https://github.com/bertrik/batplayer/blob/master/play.py this script] that is started on boot (using systemd or an @boot cronjob)
* <del>measure the frequency range of the amplifier circuit</del>
* file transfer can be done using winscp?
* <del>connect the 5V-12V step-up circuit and use it to power the amplifier</del>
* <del>measure the current consumption of the amplifier</del> -> about 200 mA
* <del>connect the speaker and verify sound production using a bat detector</del> -> works, but audio is not really loud yet. Making it louder introduces a lot of distortion.
* check whether devices can actually play ultrasonic audio over this sound card: my laptop, perhaps some cheapish android tablets (using an OTG cable). Bus load is 1536 kB/s (stereo 16-bit @ 384 kHz). Can a Raspberry Pi do it too? -> works fine on laptop


== Hardware ==
== Hardware ==
[[File:UltrasonicPlayer_block_diagram.svg|thumb|right|block diagram]]
[[File:50khz.jpg|thumb|right|50 kHz sine wave]]
[[File:100khz.jpg|thumb|right|100 kHz sine wave]]
[[File:150khz.jpg|thumb|right|150 kHz sine wave]]
[[File:tda2030amp.png|thumb|right|TDA2030 amplifier schematic]]
[[File:xt25sc90-04.png|thumb|right|speaker dimensions]]
The hardware consists of the following parts:
The hardware consists of the following parts:
# Some kind of media player which takes care of the storage and playback of the ultrasonic files, this can be a tablet or laptop
# Some kind of media player which takes care of the storage and playback of the ultrasonic files, for example a single-board computer like a Raspberry Pi
# A USB audio card to create the analog ultrasonic signal
# A USB audio card to create the analog ultrasonic signal
# An amplifier to amplify the ultrasonic signal
# An amplifier to amplify the ultrasonic signal
Line 36: Line 61:


=== media player ===
=== media player ===
This is currently the greatest unknown where requirements are most vague.
As a media player, I'm using a raspberry pi, in particular a raspberry pi 3.


This could be some kind of Linux mini computer (e.g. a Raspberry Pi) working as follows:
The player hardware needs at least two high-speed USB 2.0 ports, one for the USB stick containing the wav files and another one for the USB audio card.
* the user puts in a USB stick (formatted as FAT32 for windows compatibility) with some wav files, and possibly a playlist file (.m3u)
Bandwidth needed over USB is equivalent to 2-channel 16-bit audio at 384 kHz, which is 12.28 mbps, exceeding USB 1.0 full-speed throughput of 12 mbps.
* the player mounts the USB stick as a read-only device, e.g. using udev
 
* the player first looks for a playlist file and attempts to play files from the playlist, on repeat
The main use case of the entire player is as follows:
* if no playlist file is found, it just plays all files in undefined order, on repeat
* user switches on the ultrasonic player
* when done playing, the user pulls out the USB stick, the playback process is stopped automatically
* the user plugs in a USB stick (formatted as FAT32 for windows compatibility) with some wav files
* the player automatically mounts the USB stick as a <strong>read-only</strong> device, e.g. using udev. Mounting it read-only should prevent corruption of file data on the USB stick.
* the player automatically plays all files from the USB stick, on repeat.
* when done playing, the user just pulls out the USB stick, the playback process is stopped automatically.
* user switches the ultrasonic player off


See also:
See also:
* http://www.monperrus.net/martin/automounting+usb+flash+drives+on+linux+with+udev+and+pmount
* http://www.monperrus.net/martin/automounting+usb+flash+drives+on+linux+with+udev+and+pmount
* https://unix.stackexchange.com/questions/28548/how-to-run-custom-scripts-upon-usb-device-plug-in
* https://unix.stackexchange.com/questions/28548/how-to-run-custom-scripts-upon-usb-device-plug-in
* https://coreos.com/os/docs/latest/using-systemd-and-udev-rules.html
* http://blog.fraggod.net/2012/06/16/proper-ish-way-to-start-long-running-systemd-service-on-udev-event-device-hotplug.html


Challenges:
Challenges:
* Starting playback upon USB stick plugin, using udev?
* Starting playback upon USB stick plugin, using udev, udisk, systemd?
* Stopping playback upon USB stick plugout, using udev?
* Stopping playback upon USB stick plugout, using udev?
* Linux experts saying: "You can't pull the stick without unmounting! That would be bad!"
* Linux experts saying: "You can't pull the stick without unmounting! That would be bad!". Careful with this, they get VERY excited about this.


=== USB sound card ===
=== USB sound card ===
[[File:50khz.jpg|thumb|right|50 kHz sine wave]]
I'm using this one:
[[File:100khz.jpg|thumb|right|100 kHz sine wave]]
[[File:150khz.jpg|thumb|right|150 kHz sine wave]]
 
I'm considering this one:
[https://nl.aliexpress.com/item/SA9227-PCM5102A-32BIT-384KHZ-USB-DAC-HIFI-Asynchronous-Decoder/32722112944.html USB sound card based on a SA9227+PCM5102 chip].
[https://nl.aliexpress.com/item/SA9227-PCM5102A-32BIT-384KHZ-USB-DAC-HIFI-Asynchronous-Decoder/32722112944.html USB sound card based on a SA9227+PCM5102 chip].


It allows a maximum sample rate of up to 384 kHz, or equivalently audio op to about 170 kHz. Price: about E30,-
It allows a maximum sample rate of up to 384 kHz, or equivalently audio up to about 170 kHz. Price: about E30,-
 
On the right, from top to bottom: the signal at 50 kHz, 100 kHz, 150 kHz respectively
To play back the audio file noise.wav:
<pre>
aplay -D plughw:CARD=Audio,DEV=0 noise.wav -v
</pre>
 
On the right, rom top to bottom: the signal at 50 kHz, 100 kHz, 150 kHz respectively


Measurements of amplitude vs frequency:
Measurements of amplitude vs frequency:
* on the scope you can clearly see the sampling steps: at 100 kHz one wave is sampled using only 3.84 samples.
* on the scope you can clearly see the sampling steps: at 100 kHz one wave is sampled using only 3.84 samples.
* the amplitude drops a bit when going higher, but only like 30% at 150 kHz compared to 50 kHz
* the amplitude drops a bit when going higher, but only like 30% at 150 kHz compared to 50 kHz
Modifications:
* removed the yellow audio connector, soldered on a simple 3-pin 2.54 mm pin header.


=== Amplifier ===
=== Amplifier ===
I'm considering this one:
I'm considering this TDA2030-based module:
[http://nl.aliexpress.com/item/Power-Supply-TDA2030-Audio-Amplifier-Board-Module-TDA2030A-6-12V-Single/32652837701.html amplifier board based on a TDA2030 chip].
[http://nl.aliexpress.com/item/Power-Supply-TDA2030-Audio-Amplifier-Board-Module-TDA2030A-6-12V-Single/32652837701.html amplifier board based on a TDA2030 chip].


Line 84: Line 108:
* seems to be able to handle 50 kHz and 150 kHz audio input equally
* seems to be able to handle 50 kHz and 150 kHz audio input equally
* additionally, it seems the amplifier still works down to 5 or 6V power supply voltage.
* additionally, it seems the amplifier still works down to 5 or 6V power supply voltage.
Modification: replace R5 (150k) with a 15k resistor.
This reduces the gain of the amplifier from about 30 to 3 times, making adjustment of input level easier and also improves bandwidth.
We don't need a gain of 30, the input signal is already at about 1V level.


=== Speaker ===
=== Speaker ===
I'm considering this one:
I'm considering this one:
[http://www.parts-express.com/peerless-by-tymphany-xt25sc90-04-1-dual-ring-radiator-tweeter--264-1014 Vifa/Tymphany XT25SC90-04].
[http://www.parts-express.com/peerless-by-tymphany-xt25sc90-04-1-dual-ring-radiator-tweeter--264-1014 Vifa/Tymphany XT25SC90-04].
This speaker is also used in other products that produce ultrasonic audio.
This speaker is also used in other products that produce ultrasonic audio.
Price: about E22,-


Price: about E22,-
Apparently this very inexpensive piezo horn tweeter from Maplin also works quite well:
https://www.maplin.co.uk/p/wide-dispersion-piezo-horn-tweeter-wf56l


=== Power ===
=== Power ===
For the power source, there are two options:
[[File:al697.jpg|right|thumb|Waveform of AL697 running into 1 kOhm load]]
# draw power from the USB port from the tablet/laptop
I'm thinking of using a 5V USB battery. There are plenty of models to choose from, in varying capacity ranges and prices.
# use our own power from a separate battery


In the first case, I'll have to consider the maximum current that an average USB port can supply, which is 500 mA typically. 
To supply the amplifier with 12V, I'm considering this voltage converter:  
In the second case, I'm thinking of just using a 5V USB battery. There are plenty of models to choose from, in varying capacity ranges and prices.
 
If we're powering everything from 5V, we may need some kind of step-up converter to supply the amplifier with 12V.
I'm considering this one:  
[https://nl.aliexpress.com/item/2PCS-USB-DC-5V-To-12V-Step-up-Module-Converter-2-1x5-5mm-Male-Connector/32703956336.html 5V-to-12V step-up cable] or possibly
[https://nl.aliexpress.com/item/2PCS-USB-DC-5V-To-12V-Step-up-Module-Converter-2-1x5-5mm-Male-Connector/32703956336.html 5V-to-12V step-up cable] or possibly
[https://nl.aliexpress.com/item/5W-USB-5V-to-12V-DC-DC-Converter-Step-Up-Boost-Module-for-LED-Moter-Wireless/32326312565.html this USB 5V to 12V converter].
[https://nl.aliexpress.com/item/5W-USB-5V-to-12V-DC-DC-Converter-Step-Up-Boost-Module-for-LED-Moter-Wireless/32326312565.html this USB 5V to 12V converter].
An important consideration for the step-up converter is that the switching frequency is considerably higher than any ultrasonics frequencies we are interested in.
A consideration for the step-up converter is that the switching frequency is considerably higher than any ultrasonics frequencies we are interested in.


Measurement results for AL519, running into a 1 kOhm load:
Measurement results for the "AL519" converter, running into a 1 kOhm load:
* switching period is about 134 us
* switching period is about 134 us (7.5 kHz)
* peak-peak ripple of about 200 mV
* peak-peak ripple of about 200 mV


 
Measurement for board with "AL697"-chip into a 1 kOhm load
Measurement for board with AL697-chip (I've got three of these):
* switching frequency is about 15 kHz
* TODO
* peak-peak ripple of about 200 mV
 


Current measurement (total current over USB)
Current measurement (total current over USB)
* normally 0.36A (USB audio + step-up + amplifier)
* normally 0.36A (USB audio + step-up + amplifier)
* when playing: 0.39A
* when playing: 0.39A
* current consumed by USB audio: 0.18A idle, 0.19 when playing
== Mounting it in a case ==
[[File:batplayerparts.jpg|right|thumb|parts to be integrated]]
The various parts have the following dimensions (length x width x height) approximately:
* USB battery: 111x68x?? mm (without plugs)
* USB audio: 66x51 mm (PCB only), 77x51 mm (including connectors, without plugs)
* speaker: 66 mm (outside diameter), 53 mm (mounting hole diameter). Hole coordinates (mm): (0, 53) / (45.9, -26.5) / (-45.9, -26.5), big mounting hole: 47 mm diameter
* raspberry pi 3
* amplifier: 32x25x24mm
* step-up converter: 42x15x12 mm (without plugs)
Challenges:
* Put it all in a practical case. For the first prototype, I'm thinking about just laser-cutting a basic enclosure, then use zip-ties to tie stuff to the inside of the box. Make part of the USB battery stick out, so we can use it as an on/off switch and allow access to the charge port.
Perhaps I can use a raspberry pi to solve the USB port problem, see [https://en.wikipedia.org/wiki/Raspberry_Pi this table on wikipedia] for comparison.
For example the model B, generation 1+ has four USB port. Also it has modest power requirements.
== Software ==
As an operating system, I prefer Debian Linux, because I'm familiar with it on the desktop.
This distribution allows a small basic minimal image without a graphical environment and systemd support.
Software will be added to my [https://github.com/bertrik/batplayer batplayer] github archive, things like:
* udev/systemd plugin script: mounts the USB stick (read-only), invokes the playback script
* udev/systemd plugout script: stops the playback script, forces unmount of USB stick
* playback script, probably written in python, gets the mounted path as argument, scans the path for wav files and tries to play each file using aplay.
* [https://www.freedesktop.org/software/systemd/man/udev.html udev] scripts, to automatically mount and unmount USB sticks
* etc.
To play back an audio file, I just use aplay (from package alsa-utils), for example:
<pre>
aplay -D plughw:CARD=Audio,DEV=0 noise.wav -v
</pre>
Current plan:
* use udev to detect when a USB stick is inserted, automatically mount it read-only and run an 'at' command
* the 'at' command is started at time 'now+0' (as soon as possible) and starts a python script
* the python script takes as argument the path to the mounted stick, it recursively searches for wav-files and runs 'aplay' on each wav-file.
* use udev to detect when the USB stick in removed, force kill the python script + any child commands, automatically force unmount it
Can we use systemd to automate part of the steps above?
A plan that might actually work:
* consider the following use case:
** user puts in USB stick
** user turns on the raspberry pi
** the USB stick is mounted read-only on bootup
** a systemd service starts the python playback script and automatic playback starts
** if the user wants to play another set of files, he/she replaces the USB stick and reboots
* arrange for the USB stick to be automatically mounted on bootup: read-only and at a fixed location in the file system (/etc/fstab ?)
* add a systemd script to start the python playback script with the fixed location as argument
* profit!
== Various dumps ==
The dumps below show what happens on my laptop, helping to clarify what happens when and where I can put my own scripts for mounting, playing, unmounting a USB stick.
=== udev dump ===
Events detected by udevadm monitor when plugging in a USB stick into my laptop:
<pre>
KERNEL[1792.773451] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1 (usb)
KERNEL[1792.773723] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0 (usb)
KERNEL[1792.774053] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2 (scsi)
KERNEL[1792.774231] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/scsi_host/host2 (scsi_host)
KERNEL[1792.774317] bind    /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0 (usb)
KERNEL[1792.774417] bind    /devices/pci0000:00/0000:00:14.0/usb1/1-1 (usb)
UDEV  [1792.780766] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1 (usb)
UDEV  [1792.786816] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0 (usb)
UDEV  [1792.786872] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2 (scsi)
UDEV  [1792.787432] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/scsi_host/host2 (scsi_host)
UDEV  [1792.789019] bind    /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0 (usb)
UDEV  [1792.790123] bind    /devices/pci0000:00/0000:00:14.0/usb1/1-1 (usb)
KERNEL[1793.789325] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0 (scsi)
KERNEL[1793.789431] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0 (scsi)
KERNEL[1793.789537] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_disk/2:0:0:0 (scsi_disk)
KERNEL[1793.789599] bind    /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0 (scsi)
KERNEL[1793.789635] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_device/2:0:0:0 (scsi_device)
KERNEL[1793.789958] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_generic/sg1 (scsi_generic)
KERNEL[1793.790118] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/bsg/2:0:0:0 (bsg)
KERNEL[1793.790712] add      /devices/virtual/bdi/8:16 (bdi)
UDEV  [1793.791661] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0 (scsi)
UDEV  [1793.792455] add      /devices/virtual/bdi/8:16 (bdi)
UDEV  [1793.793191] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0 (scsi)
UDEV  [1793.794019] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_disk/2:0:0:0 (scsi_disk)
UDEV  [1793.794587] bind    /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0 (scsi)
UDEV  [1793.796165] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_device/2:0:0:0 (scsi_device)
UDEV  [1793.796387] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_generic/sg1 (scsi_generic)
UDEV  [1793.796528] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/bsg/2:0:0:0 (bsg)
KERNEL[1793.796590] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb (block)
KERNEL[1793.796630] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb/sdb1 (block)
UDEV  [1793.913501] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb (block)
UDEV  [1794.008034] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb/sdb1 (block)
</pre>
=== system log dump ===
What I see in the system log when plugging in a USB stick into my laptop:
<pre>
Nov  4 23:46:01 zenbook kernel: [ 3550.158592] usb 1-1: new high-speed USB device number 14 using xhci_hcd
Nov  4 23:46:02 zenbook kernel: [ 3550.307449] usb 1-1: New USB device found, idVendor=08ec, idProduct=0020
Nov  4 23:46:02 zenbook kernel: [ 3550.307454] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Nov  4 23:46:02 zenbook kernel: [ 3550.307457] usb 1-1: Product: Store'n'go
Nov  4 23:46:02 zenbook kernel: [ 3550.307460] usb 1-1: Manufacturer: Verbatim
Nov  4 23:46:02 zenbook kernel: [ 3550.307463] usb 1-1: SerialNumber: 0E21E5708251F9A3
Nov  4 23:46:02 zenbook kernel: [ 3550.308029] usb-storage 1-1:1.0: USB Mass Storage device detected
Nov  4 23:46:02 zenbook kernel: [ 3550.308281] scsi host2: usb-storage 1-1:1.0
Nov  4 23:46:02 zenbook upowerd[1116]: unhandled action 'bind' on /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0
Nov  4 23:46:02 zenbook upowerd[1116]: unhandled action 'bind' on /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1
Nov  4 23:46:03 zenbook kernel: [ 3551.311276] scsi 2:0:0:0: Direct-Access    VBTM    Store'n'go      6.51 PQ: 0 ANSI: 0 CCS
Nov  4 23:46:03 zenbook kernel: [ 3551.311935] sd 2:0:0:0: Attached scsi generic sg1 type 0
Nov  4 23:46:03 zenbook kernel: [ 3551.312081] sd 2:0:0:0: [sdb] 1952767 512-byte logical blocks: (1000 MB/953 MiB)
Nov  4 23:46:03 zenbook kernel: [ 3551.312258] sd 2:0:0:0: [sdb] Write Protect is off
Nov  4 23:46:03 zenbook kernel: [ 3551.315984]  sdb: sdb1
Nov  4 23:46:03 zenbook kernel: [ 3551.317012] sd 2:0:0:0: [sdb] Attached SCSI removable disk
</pre>
=== udisk dump ===
<pre>
bertrik@zenbook:/etc/udev/rules.d$ udisksctl monitor
Monitoring the udisks daemon. Press Ctrl+C to exit.
09:22:56.973: The udisks-daemon is running (name-owner :1.5).
09:23:00.864: Added /org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3
  org.freedesktop.UDisks2.Drive:
    CanPowerOff:                true
    Configuration:              {}
    ConnectionBus:              usb
    Ejectable:                  true
    Id:                        VBTM-Store'n'go-0E21E5708251F9A3
    Media:                     
    MediaAvailable:            true
    MediaChangeDetected:        true
    MediaCompatibility:       
    MediaRemovable:            true
    Model:                      Store'n'go
    Optical:                    false
    OpticalBlank:              false
    OpticalNumAudioTracks:      0
    OpticalNumDataTracks:      0
    OpticalNumSessions:        0
    OpticalNumTracks:          0
    Removable:                  true
    Revision:                  6.51
    RotationRate:              -1
    Seat:                      seat0
    Serial:                    0E21E5708251F9A3
    SiblingId:                  /sys/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0
    Size:                      999816704
    SortKey:                    01hotplug/1509870180862880
    TimeDetected:              1509870180862880
    TimeMediaDetected:          1509870180862880
    Vendor:                    VBTM
    WWN:                       
09:23:00.865: Added /org/freedesktop/UDisks2/block_devices/sdb
  org.freedesktop.UDisks2.Block:
    Configuration:              []
    CryptoBackingDevice:        '/'
    Device:                    /dev/sdb
    DeviceNumber:              2064
    Drive:                      '/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3'
    HintAuto:                  true
    HintIconName:             
    HintIgnore:                false
    HintName:                 
    HintPartitionable:          true
    HintSymbolicIconName:     
    HintSystem:                false
    Id:                       
    IdLabel:                   
    IdType:                   
    IdUUID:                   
    IdUsage:                   
    IdVersion:                 
    MDRaid:                    '/'
    MDRaidMember:              '/'
    PreferredDevice:            /dev/sdb
    ReadOnly:                  false
    Size:                      999816704
    Symlinks:                  /dev/disk/by-id/usb-VBTM_Store_n_go_0E21E5708251F9A3-0:0
                                /dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0
  org.freedesktop.UDisks2.PartitionTable:
    Partitions:        []
    Type:              dos
09:23:00.960: Added /org/freedesktop/UDisks2/block_devices/sdb1
  org.freedesktop.UDisks2.Block:
    Configuration:              []
    CryptoBackingDevice:        '/'
    Device:                    /dev/sdb1
    DeviceNumber:              2065
    Drive:                      '/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3'
    HintAuto:                  true
    HintIconName:             
    HintIgnore:                false
    HintName:                 
    HintPartitionable:          true
    HintSymbolicIconName:     
    HintSystem:                false
    Id:                        by-uuid-5F04-1AF7
    IdLabel:                   
    IdType:                    vfat
    IdUUID:                    5F04-1AF7
    IdUsage:                    filesystem
    IdVersion:                  FAT32
    MDRaid:                    '/'
    MDRaidMember:              '/'
    PreferredDevice:            /dev/sdb1
    ReadOnly:                  false
    Size:                      998244352
    Symlinks:                  /dev/disk/by-id/usb-VBTM_Store_n_go_0E21E5708251F9A3-0:0-part1
                                /dev/disk/by-partuuid/ecd1c11c-01
                                /dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0-part1
                                /dev/disk/by-uuid/5F04-1AF7
  org.freedesktop.UDisks2.Filesystem:
    MountPoints:       
  org.freedesktop.UDisks2.Partition:
    Flags:              0
    IsContained:        false
    IsContainer:        false
    Name:             
    Number:            1
    Offset:            1048576
    Size:              998244352
    Table:              '/org/freedesktop/UDisks2/block_devices/sdb'
    Type:              0x0b
    UUID:              ecd1c11c-01
</pre>
=== DBUS events for UDisks2 ===
<pre>
bertrik@zenbook:/etc/udev/rules.d$ dbus-monitor --system "path='/org/freedesktop/UDisks2'"
dbus-monitor: unable to enable new-style monitoring: org.freedesktop.DBus.Error.AccessDenied: "Rejected send message, 1 matched rules; type="method_call", sender=":1.113" (uid=1000 pid=32250 comm="dbus-monitor --system path='/org/freedesktop/UDisk") interface="org.freedesktop.DBus.Monitoring" member="BecomeMonitor" error name="(unset)" requested_reply="0" destination="org.freedesktop.DBus" (bus)". Falling back to eavesdropping.
signal time=1509870902.036078 sender=org.freedesktop.DBus -> destination=:1.113 serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
  string ":1.113"
signal time=1509870909.476409 sender=:1.5 -> destination=(null destination) serial=202 path=/org/freedesktop/UDisks2; interface=org.freedesktop.DBus.ObjectManager; member=InterfacesAdded
  object path "/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3"
  array [
      dict entry(
        string "org.freedesktop.UDisks2.Drive"
        array [
            dict entry(
              string "Vendor"
              variant                  string "VBTM"
            )
            dict entry(
              string "Model"
              variant                  string "Store'n'go"
            )
            dict entry(
              string "Revision"
              variant                  string "6.51"
            )
            dict entry(
              string "Serial"
              variant                  string "0E21E5708251F9A3"
            )
            dict entry(
              string "WWN"
              variant                  string ""
            )
            dict entry(
              string "Id"
              variant                  string "VBTM-Store'n'go-0E21E5708251F9A3"
            )
            dict entry(
              string "Configuration"
              variant                  array [
                  ]
            )
            dict entry(
              string "Media"
              variant                  string ""
            )
            dict entry(
              string "MediaCompatibility"
              variant                  array [
                  ]
            )
            dict entry(
              string "MediaRemovable"
              variant                  boolean true
            )
            dict entry(
              string "MediaAvailable"
              variant                  boolean true
            )
            dict entry(
              string "MediaChangeDetected"
              variant                  boolean true
            )
            dict entry(
              string "Size"
              variant                  uint64 999816704
            )
            dict entry(
              string "TimeDetected"
              variant                  uint64 1509870909475067
            )
            dict entry(
              string "TimeMediaDetected"
              variant                  uint64 1509870909475067
            )
            dict entry(
              string "Optical"
              variant                  boolean false
            )
            dict entry(
              string "OpticalBlank"
              variant                  boolean false
            )
            dict entry(
              string "OpticalNumTracks"
              variant                  uint32 0
            )
            dict entry(
              string "OpticalNumAudioTracks"
              variant                  uint32 0
            )
            dict entry(
              string "OpticalNumDataTracks"
              variant                  uint32 0
            )
            dict entry(
              string "OpticalNumSessions"
              variant                  uint32 0
            )
            dict entry(
              string "RotationRate"
              variant                  int32 -1
            )
            dict entry(
              string "ConnectionBus"
              variant                  string "usb"
            )
            dict entry(
              string "Seat"
              variant                  string "seat0"
            )
            dict entry(
              string "Removable"
              variant                  boolean true
            )
            dict entry(
              string "Ejectable"
              variant                  boolean true
            )
            dict entry(
              string "SortKey"
              variant                  string "01hotplug/1509870909475067"
            )
            dict entry(
              string "CanPowerOff"
              variant                  boolean true
            )
            dict entry(
              string "SiblingId"
              variant                  string "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0"
            )
        ]
      )
  ]
signal time=1509870909.477243 sender=:1.5 -> destination=(null destination) serial=203 path=/org/freedesktop/UDisks2; interface=org.freedesktop.DBus.ObjectManager; member=InterfacesAdded
  object path "/org/freedesktop/UDisks2/block_devices/sdb"
  array [
      dict entry(
        string "org.freedesktop.UDisks2.Block"
        array [
            dict entry(
              string "Device"
              variant                  array of bytes "/dev/sdb" + \0
            )
            dict entry(
              string "PreferredDevice"
              variant                  array of bytes "/dev/sdb" + \0
            )
            dict entry(
              string "Symlinks"
              variant                  array [
                    array of bytes "/dev/disk/by-id/usb-VBTM_Store_n_go_0E21E5708251F9A3-0:0" + \0
                    array of bytes "/dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0" + \0
                  ]
            )
            dict entry(
              string "DeviceNumber"
              variant                  uint64 2064
            )
            dict entry(
              string "Id"
              variant                  string ""
            )
            dict entry(
              string "Size"
              variant                  uint64 999816704
            )
            dict entry(
              string "ReadOnly"
              variant                  boolean false
            )
            dict entry(
              string "Drive"
              variant                  object path "/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3"
            )
            dict entry(
              string "MDRaid"
              variant                  object path "/"
            )
            dict entry(
              string "MDRaidMember"
              variant                  object path "/"
            )
            dict entry(
              string "IdUsage"
              variant                  string ""
            )
            dict entry(
              string "IdType"
              variant                  string ""
            )
            dict entry(
              string "IdVersion"
              variant                  string ""
            )
            dict entry(
              string "IdLabel"
              variant                  string ""
            )
            dict entry(
              string "IdUUID"
              variant                  string ""
            )
            dict entry(
              string "Configuration"
              variant                  array [
                  ]
            )
            dict entry(
              string "CryptoBackingDevice"
              variant                  object path "/"
            )
            dict entry(
              string "HintPartitionable"
              variant                  boolean true
            )
            dict entry(
              string "HintSystem"
              variant                  boolean false
            )
            dict entry(
              string "HintIgnore"
              variant                  boolean false
            )
            dict entry(
              string "HintAuto"
              variant                  boolean true
            )
            dict entry(
              string "HintName"
              variant                  string ""
            )
            dict entry(
              string "HintIconName"
              variant                  string ""
            )
            dict entry(
              string "HintSymbolicIconName"
              variant                  string ""
            )
        ]
      )
      dict entry(
        string "org.freedesktop.UDisks2.PartitionTable"
        array [
            dict entry(
              string "Partitions"
              variant                  array [
                  ]
            )
            dict entry(
              string "Type"
              variant                  string "dos"
            )
        ]
      )
  ]
signal time=1509870909.571078 sender=:1.5 -> destination=(null destination) serial=204 path=/org/freedesktop/UDisks2; interface=org.freedesktop.DBus.ObjectManager; member=InterfacesAdded
  object path "/org/freedesktop/UDisks2/block_devices/sdb1"
  array [
      dict entry(
        string "org.freedesktop.UDisks2.Block"
        array [
            dict entry(
              string "Device"
              variant                  array of bytes "/dev/sdb1" + \0
            )
            dict entry(
              string "PreferredDevice"
              variant                  array of bytes "/dev/sdb1" + \0
            )
            dict entry(
              string "Symlinks"
              variant                  array [
                    array of bytes "/dev/disk/by-id/usb-VBTM_Store_n_go_0E21E5708251F9A3-0:0-part1" + \0
                    array of bytes "/dev/disk/by-partuuid/ecd1c11c-01" + \0
                    array of bytes "/dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0-part1" + \0
                    array of bytes "/dev/disk/by-uuid/5F04-1AF7" + \0
                  ]
            )
            dict entry(
              string "DeviceNumber"
              variant                  uint64 2065
            )
            dict entry(
              string "Id"
              variant                  string "by-uuid-5F04-1AF7"
            )
            dict entry(
              string "Size"
              variant                  uint64 998244352
            )
            dict entry(
              string "ReadOnly"
              variant                  boolean false
            )
            dict entry(
              string "Drive"
              variant                  object path "/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3"
            )
            dict entry(
              string "MDRaid"
              variant                  object path "/"
            )
            dict entry(
              string "MDRaidMember"
              variant                  object path "/"
            )
            dict entry(
              string "IdUsage"
              variant                  string "filesystem"
            )
            dict entry(
              string "IdType"
              variant                  string "vfat"
            )
            dict entry(
              string "IdVersion"
              variant                  string "FAT32"
            )
            dict entry(
              string "IdLabel"
              variant                  string ""
            )
            dict entry(
              string "IdUUID"
              variant                  string "5F04-1AF7"
            )
            dict entry(
              string "Configuration"
              variant                  array [
                  ]
            )
            dict entry(
              string "CryptoBackingDevice"
              variant                  object path "/"
            )
            dict entry(
              string "HintPartitionable"
              variant                  boolean true
            )
            dict entry(
              string "HintSystem"
              variant                  boolean false
            )
            dict entry(
              string "HintIgnore"
              variant                  boolean false
            )
            dict entry(
              string "HintAuto"
              variant                  boolean true
            )
            dict entry(
              string "HintName"
              variant                  string ""
            )
            dict entry(
              string "HintIconName"
              variant                  string ""
            )
            dict entry(
              string "HintSymbolicIconName"
              variant                  string ""
            )
        ]
      )
      dict entry(
        string "org.freedesktop.UDisks2.Filesystem"
        array [
            dict entry(
              string "MountPoints"
              variant                  array [
                  ]
            )
        ]
      )
      dict entry(
        string "org.freedesktop.UDisks2.Partition"
        array [
            dict entry(
              string "Number"
              variant                  uint32 1
            )
            dict entry(
              string "Type"
              variant                  string "0x0b"
            )
            dict entry(
              string "Flags"
              variant                  uint64 0
            )
            dict entry(
              string "Offset"
              variant                  uint64 1048576
            )
            dict entry(
              string "Size"
              variant                  uint64 998244352
            )
            dict entry(
              string "Name"
              variant                  string ""
            )
            dict entry(
              string "UUID"
              variant                  string "ecd1c11c-01"
            )
            dict entry(
              string "Table"
              variant                  object path "/org/freedesktop/UDisks2/block_devices/sdb"
            )
            dict entry(
              string "IsContainer"
              variant                  boolean false
            )
            dict entry(
              string "IsContained"
              variant                  boolean false
            )
        ]
      )
  ]
</pre>
In short:
* a signal org.freedesktop.DBus.NameAcquired on path /org/freedesktop/DBus
* a signal org.freedesktop.DBus.ObjectManager.InterfacesAdded on path /org/freedesktop/UDisks2, object path "/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3" with information about the physical USB stick
* a signal org.freedesktop.DBus.ObjectManager.InterfacesAdded on path /org/freedesktop/UDisks2, object path "/org/freedesktop/UDisks2/block_devices/sdb" with information about the /dev/sdb partition
* a signal org.freedesktop.DBus.ObjectManager.InterfacesAdded on path /org/freedesktop/UDisks2, object path "/org/freedesktop/UDisks2/block_devices/sdb1" with information about the /dev/sdb1 partition
== Audio files ==
Suitable audio files for playback:
* the 'synthesized' versions from [http://www.batcalls.com/ batcalls.com] by AviSoft, these are mostly mono 16-bit PCM, sampled at 250000 Hz

Latest revision as of 13:39, 21 July 2019

Project UltrasonicPlayer
Sa9227.jpg
An inexpensive DIY ultrasonic audio player
Status In progress
Contact bertrik
Last Update 2019-07-21

Introduction

This project is about a do-it-yourself portable ultrasonic audio player, built out of inexpensive modules available on sites like AliExpress.

A typical use case for this is a kind of "lure" for biology researchers to improve the results of trying to catch bats in a net. The player emulates (social) bat calls which attracts the bats to the net, increasing the chance for them to be caught.

Another use case is to use it as an educational tool, to train people in the use of a bat detector. The player makes it easy to play the exact same sound again and again, allowing people to experiment with finding the best setting for their equipment and to improve their determination skills.

The ultrasonic player consists of a USB sound card with high sampling rate plus a speaker to turn it into actual ultrasonic audio. A built-in Linux single-board-computer (something like a Raspberry Pi) controls playback of audio files. The idea is that you prepare one or more USB sticks with bat calls and just plug one in the player, then the player automatically plays them in a loop

Status

Where this project could use some help with

Help wanted:

  • put it in a robust practical box with batteries
  • find a practical way to put files on it
  • find a practical way to start/stop playback
  • marketing

Time line

 2018-04-01: I have a box with the piezo speaker mounted in it. Still a bit stuck on the auto-play-on-USB-plugin stuff. First, I could just play back audio from a specific directory first.
 2017-10-10: basically I'm stuck on the software part, unable to decide how I should solve how to play audio files on USB stick plugin, I've got several hints but no definite solution. Getting more hints like "why *don't* you try X" are confusing the issue more. Also a bit stuck on the construction part (housing, etc.)
 2017-06-24: successfully played audio back from a raspberry pi 3, running the amplifier from one of the USB ports. The rpi3 shows a little lightning bolt indicating undervoltage while playing.
 2017-06-18: realized that an orange pi zero is not going to work: it doesn't have enough USB ports
 2017-06-16: playing a bit with udev scripts to automate actions upon USB stick plugin: I can do short actions (like mount/unmount) but no longer running actions from udev!
 2017-05-01: replaced a feedback resistor on the amplifier, to reduce the gain from about 30 to 3, this also makes it easier to adjust the gain using the potmeter
 2017-04-30: found the schematic for the amplifier, plan to modify it for lower gain (better level control and higher bandwidth)
 2017-04-16: created a video of current progress.
 2016-10-11: received the amplifier boards.
 2016-10-02: ordered the parts (USB audio, amplifier, a few step-up circuits).

Next steps:

  • just play back stuff in a loop from a fixed directory on the sd card, using this script that is started on boot (using systemd or an @boot cronjob)
  • file transfer can be done using winscp?

Hardware

block diagram
50 kHz sine wave
100 kHz sine wave
150 kHz sine wave
TDA2030 amplifier schematic
speaker dimensions

The hardware consists of the following parts:

  1. Some kind of media player which takes care of the storage and playback of the ultrasonic files, for example a single-board computer like a Raspberry Pi
  2. A USB audio card to create the analog ultrasonic signal
  3. An amplifier to amplify the ultrasonic signal
  4. A speaker to turn the signal into actual ultrasonic audio

media player

As a media player, I'm using a raspberry pi, in particular a raspberry pi 3.

The player hardware needs at least two high-speed USB 2.0 ports, one for the USB stick containing the wav files and another one for the USB audio card. Bandwidth needed over USB is equivalent to 2-channel 16-bit audio at 384 kHz, which is 12.28 mbps, exceeding USB 1.0 full-speed throughput of 12 mbps.

The main use case of the entire player is as follows:

  • user switches on the ultrasonic player
  • the user plugs in a USB stick (formatted as FAT32 for windows compatibility) with some wav files
  • the player automatically mounts the USB stick as a read-only device, e.g. using udev. Mounting it read-only should prevent corruption of file data on the USB stick.
  • the player automatically plays all files from the USB stick, on repeat.
  • when done playing, the user just pulls out the USB stick, the playback process is stopped automatically.
  • user switches the ultrasonic player off

See also:

Challenges:

  • Starting playback upon USB stick plugin, using udev, udisk, systemd?
  • Stopping playback upon USB stick plugout, using udev?
  • Linux experts saying: "You can't pull the stick without unmounting! That would be bad!". Careful with this, they get VERY excited about this.

USB sound card

I'm using this one: USB sound card based on a SA9227+PCM5102 chip.

It allows a maximum sample rate of up to 384 kHz, or equivalently audio up to about 170 kHz. Price: about E30,- On the right, from top to bottom: the signal at 50 kHz, 100 kHz, 150 kHz respectively

Measurements of amplitude vs frequency:

  • on the scope you can clearly see the sampling steps: at 100 kHz one wave is sampled using only 3.84 samples.
  • the amplitude drops a bit when going higher, but only like 30% at 150 kHz compared to 50 kHz

Modifications:

  • removed the yellow audio connector, soldered on a simple 3-pin 2.54 mm pin header.

Amplifier

I'm considering this TDA2030-based module: amplifier board based on a TDA2030 chip.

The TDA2030 chip has a claimed audio bandwidth of up to 140 kHz. Price: about E1,-

Measurements with a separate power supply for the amplifier:

  • seems to be able to handle 50 kHz and 150 kHz audio input equally
  • additionally, it seems the amplifier still works down to 5 or 6V power supply voltage.

Modification: replace R5 (150k) with a 15k resistor. This reduces the gain of the amplifier from about 30 to 3 times, making adjustment of input level easier and also improves bandwidth. We don't need a gain of 30, the input signal is already at about 1V level.

Speaker

I'm considering this one: Vifa/Tymphany XT25SC90-04. This speaker is also used in other products that produce ultrasonic audio. Price: about E22,-

Apparently this very inexpensive piezo horn tweeter from Maplin also works quite well: https://www.maplin.co.uk/p/wide-dispersion-piezo-horn-tweeter-wf56l

Power

Waveform of AL697 running into 1 kOhm load

I'm thinking of using a 5V USB battery. There are plenty of models to choose from, in varying capacity ranges and prices.

To supply the amplifier with 12V, I'm considering this voltage converter: 5V-to-12V step-up cable or possibly this USB 5V to 12V converter. A consideration for the step-up converter is that the switching frequency is considerably higher than any ultrasonics frequencies we are interested in.

Measurement results for the "AL519" converter, running into a 1 kOhm load:

  • switching period is about 134 us (7.5 kHz)
  • peak-peak ripple of about 200 mV

Measurement for board with "AL697"-chip into a 1 kOhm load

  • switching frequency is about 15 kHz
  • peak-peak ripple of about 200 mV

Current measurement (total current over USB)

  • normally 0.36A (USB audio + step-up + amplifier)
  • when playing: 0.39A
  • current consumed by USB audio: 0.18A idle, 0.19 when playing

Mounting it in a case

parts to be integrated

The various parts have the following dimensions (length x width x height) approximately:

  • USB battery: 111x68x?? mm (without plugs)
  • USB audio: 66x51 mm (PCB only), 77x51 mm (including connectors, without plugs)
  • speaker: 66 mm (outside diameter), 53 mm (mounting hole diameter). Hole coordinates (mm): (0, 53) / (45.9, -26.5) / (-45.9, -26.5), big mounting hole: 47 mm diameter
  • raspberry pi 3
  • amplifier: 32x25x24mm
  • step-up converter: 42x15x12 mm (without plugs)

Challenges:

  • Put it all in a practical case. For the first prototype, I'm thinking about just laser-cutting a basic enclosure, then use zip-ties to tie stuff to the inside of the box. Make part of the USB battery stick out, so we can use it as an on/off switch and allow access to the charge port.

Perhaps I can use a raspberry pi to solve the USB port problem, see this table on wikipedia for comparison. For example the model B, generation 1+ has four USB port. Also it has modest power requirements.

Software

As an operating system, I prefer Debian Linux, because I'm familiar with it on the desktop. This distribution allows a small basic minimal image without a graphical environment and systemd support.

Software will be added to my batplayer github archive, things like:

  • udev/systemd plugin script: mounts the USB stick (read-only), invokes the playback script
  • udev/systemd plugout script: stops the playback script, forces unmount of USB stick
  • playback script, probably written in python, gets the mounted path as argument, scans the path for wav files and tries to play each file using aplay.
  • udev scripts, to automatically mount and unmount USB sticks
  • etc.

To play back an audio file, I just use aplay (from package alsa-utils), for example:

aplay -D plughw:CARD=Audio,DEV=0 noise.wav -v

Current plan:

  • use udev to detect when a USB stick is inserted, automatically mount it read-only and run an 'at' command
  • the 'at' command is started at time 'now+0' (as soon as possible) and starts a python script
  • the python script takes as argument the path to the mounted stick, it recursively searches for wav-files and runs 'aplay' on each wav-file.
  • use udev to detect when the USB stick in removed, force kill the python script + any child commands, automatically force unmount it

Can we use systemd to automate part of the steps above?

A plan that might actually work:

  • consider the following use case:
    • user puts in USB stick
    • user turns on the raspberry pi
    • the USB stick is mounted read-only on bootup
    • a systemd service starts the python playback script and automatic playback starts
    • if the user wants to play another set of files, he/she replaces the USB stick and reboots
  • arrange for the USB stick to be automatically mounted on bootup: read-only and at a fixed location in the file system (/etc/fstab ?)
  • add a systemd script to start the python playback script with the fixed location as argument
  • profit!

Various dumps

The dumps below show what happens on my laptop, helping to clarify what happens when and where I can put my own scripts for mounting, playing, unmounting a USB stick.

udev dump

Events detected by udevadm monitor when plugging in a USB stick into my laptop:

KERNEL[1792.773451] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1 (usb)
KERNEL[1792.773723] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0 (usb)
KERNEL[1792.774053] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2 (scsi)
KERNEL[1792.774231] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/scsi_host/host2 (scsi_host)
KERNEL[1792.774317] bind     /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0 (usb)
KERNEL[1792.774417] bind     /devices/pci0000:00/0000:00:14.0/usb1/1-1 (usb)
UDEV  [1792.780766] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1 (usb)
UDEV  [1792.786816] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0 (usb)
UDEV  [1792.786872] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2 (scsi)
UDEV  [1792.787432] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/scsi_host/host2 (scsi_host)
UDEV  [1792.789019] bind     /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0 (usb)
UDEV  [1792.790123] bind     /devices/pci0000:00/0000:00:14.0/usb1/1-1 (usb)
KERNEL[1793.789325] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0 (scsi)
KERNEL[1793.789431] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0 (scsi)
KERNEL[1793.789537] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_disk/2:0:0:0 (scsi_disk)
KERNEL[1793.789599] bind     /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0 (scsi)
KERNEL[1793.789635] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_device/2:0:0:0 (scsi_device)
KERNEL[1793.789958] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_generic/sg1 (scsi_generic)
KERNEL[1793.790118] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/bsg/2:0:0:0 (bsg)
KERNEL[1793.790712] add      /devices/virtual/bdi/8:16 (bdi)
UDEV  [1793.791661] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0 (scsi)
UDEV  [1793.792455] add      /devices/virtual/bdi/8:16 (bdi)
UDEV  [1793.793191] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0 (scsi)
UDEV  [1793.794019] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_disk/2:0:0:0 (scsi_disk)
UDEV  [1793.794587] bind     /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0 (scsi)
UDEV  [1793.796165] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_device/2:0:0:0 (scsi_device)
UDEV  [1793.796387] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/scsi_generic/sg1 (scsi_generic)
UDEV  [1793.796528] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/bsg/2:0:0:0 (bsg)
KERNEL[1793.796590] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb (block)
KERNEL[1793.796630] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb/sdb1 (block)
UDEV  [1793.913501] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb (block)
UDEV  [1794.008034] add      /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/host2/target2:0:0/2:0:0:0/block/sdb/sdb1 (block)

system log dump

What I see in the system log when plugging in a USB stick into my laptop:

Nov  4 23:46:01 zenbook kernel: [ 3550.158592] usb 1-1: new high-speed USB device number 14 using xhci_hcd
Nov  4 23:46:02 zenbook kernel: [ 3550.307449] usb 1-1: New USB device found, idVendor=08ec, idProduct=0020
Nov  4 23:46:02 zenbook kernel: [ 3550.307454] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Nov  4 23:46:02 zenbook kernel: [ 3550.307457] usb 1-1: Product: Store'n'go
Nov  4 23:46:02 zenbook kernel: [ 3550.307460] usb 1-1: Manufacturer: Verbatim
Nov  4 23:46:02 zenbook kernel: [ 3550.307463] usb 1-1: SerialNumber: 0E21E5708251F9A3
Nov  4 23:46:02 zenbook kernel: [ 3550.308029] usb-storage 1-1:1.0: USB Mass Storage device detected
Nov  4 23:46:02 zenbook kernel: [ 3550.308281] scsi host2: usb-storage 1-1:1.0
Nov  4 23:46:02 zenbook upowerd[1116]: unhandled action 'bind' on /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0
Nov  4 23:46:02 zenbook upowerd[1116]: unhandled action 'bind' on /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1
Nov  4 23:46:03 zenbook kernel: [ 3551.311276] scsi 2:0:0:0: Direct-Access     VBTM     Store'n'go       6.51 PQ: 0 ANSI: 0 CCS
Nov  4 23:46:03 zenbook kernel: [ 3551.311935] sd 2:0:0:0: Attached scsi generic sg1 type 0
Nov  4 23:46:03 zenbook kernel: [ 3551.312081] sd 2:0:0:0: [sdb] 1952767 512-byte logical blocks: (1000 MB/953 MiB)
Nov  4 23:46:03 zenbook kernel: [ 3551.312258] sd 2:0:0:0: [sdb] Write Protect is off
Nov  4 23:46:03 zenbook kernel: [ 3551.315984]  sdb: sdb1
Nov  4 23:46:03 zenbook kernel: [ 3551.317012] sd 2:0:0:0: [sdb] Attached SCSI removable disk

udisk dump

bertrik@zenbook:/etc/udev/rules.d$ udisksctl monitor
Monitoring the udisks daemon. Press Ctrl+C to exit.
09:22:56.973: The udisks-daemon is running (name-owner :1.5).
09:23:00.864: Added /org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3
  org.freedesktop.UDisks2.Drive:
    CanPowerOff:                true
    Configuration:              {}
    ConnectionBus:              usb
    Ejectable:                  true
    Id:                         VBTM-Store'n'go-0E21E5708251F9A3
    Media:                      
    MediaAvailable:             true
    MediaChangeDetected:        true
    MediaCompatibility:         
    MediaRemovable:             true
    Model:                      Store'n'go
    Optical:                    false
    OpticalBlank:               false
    OpticalNumAudioTracks:      0
    OpticalNumDataTracks:       0
    OpticalNumSessions:         0
    OpticalNumTracks:           0
    Removable:                  true
    Revision:                   6.51
    RotationRate:               -1
    Seat:                       seat0
    Serial:                     0E21E5708251F9A3
    SiblingId:                  /sys/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0
    Size:                       999816704
    SortKey:                    01hotplug/1509870180862880
    TimeDetected:               1509870180862880
    TimeMediaDetected:          1509870180862880
    Vendor:                     VBTM
    WWN:                        
09:23:00.865: Added /org/freedesktop/UDisks2/block_devices/sdb
  org.freedesktop.UDisks2.Block:
    Configuration:              []
    CryptoBackingDevice:        '/'
    Device:                     /dev/sdb
    DeviceNumber:               2064
    Drive:                      '/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3'
    HintAuto:                   true
    HintIconName:               
    HintIgnore:                 false
    HintName:                   
    HintPartitionable:          true
    HintSymbolicIconName:       
    HintSystem:                 false
    Id:                         
    IdLabel:                    
    IdType:                     
    IdUUID:                     
    IdUsage:                    
    IdVersion:                  
    MDRaid:                     '/'
    MDRaidMember:               '/'
    PreferredDevice:            /dev/sdb
    ReadOnly:                   false
    Size:                       999816704
    Symlinks:                   /dev/disk/by-id/usb-VBTM_Store_n_go_0E21E5708251F9A3-0:0
                                /dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0
  org.freedesktop.UDisks2.PartitionTable:
    Partitions:         []
    Type:               dos
09:23:00.960: Added /org/freedesktop/UDisks2/block_devices/sdb1
  org.freedesktop.UDisks2.Block:
    Configuration:              []
    CryptoBackingDevice:        '/'
    Device:                     /dev/sdb1
    DeviceNumber:               2065
    Drive:                      '/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3'
    HintAuto:                   true
    HintIconName:               
    HintIgnore:                 false
    HintName:                   
    HintPartitionable:          true
    HintSymbolicIconName:       
    HintSystem:                 false
    Id:                         by-uuid-5F04-1AF7
    IdLabel:                    
    IdType:                     vfat
    IdUUID:                     5F04-1AF7
    IdUsage:                    filesystem
    IdVersion:                  FAT32
    MDRaid:                     '/'
    MDRaidMember:               '/'
    PreferredDevice:            /dev/sdb1
    ReadOnly:                   false
    Size:                       998244352
    Symlinks:                   /dev/disk/by-id/usb-VBTM_Store_n_go_0E21E5708251F9A3-0:0-part1
                                /dev/disk/by-partuuid/ecd1c11c-01
                                /dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0-part1
                                /dev/disk/by-uuid/5F04-1AF7
  org.freedesktop.UDisks2.Filesystem:
    MountPoints:        
  org.freedesktop.UDisks2.Partition:
    Flags:              0
    IsContained:        false
    IsContainer:        false
    Name:               
    Number:             1
    Offset:             1048576
    Size:               998244352
    Table:              '/org/freedesktop/UDisks2/block_devices/sdb'
    Type:               0x0b
    UUID:               ecd1c11c-01

DBUS events for UDisks2

bertrik@zenbook:/etc/udev/rules.d$ dbus-monitor --system "path='/org/freedesktop/UDisks2'"
dbus-monitor: unable to enable new-style monitoring: org.freedesktop.DBus.Error.AccessDenied: "Rejected send message, 1 matched rules; type="method_call", sender=":1.113" (uid=1000 pid=32250 comm="dbus-monitor --system path='/org/freedesktop/UDisk") interface="org.freedesktop.DBus.Monitoring" member="BecomeMonitor" error name="(unset)" requested_reply="0" destination="org.freedesktop.DBus" (bus)". Falling back to eavesdropping.
signal time=1509870902.036078 sender=org.freedesktop.DBus -> destination=:1.113 serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
   string ":1.113"
signal time=1509870909.476409 sender=:1.5 -> destination=(null destination) serial=202 path=/org/freedesktop/UDisks2; interface=org.freedesktop.DBus.ObjectManager; member=InterfacesAdded
   object path "/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3"
   array [
      dict entry(
         string "org.freedesktop.UDisks2.Drive"
         array [
            dict entry(
               string "Vendor"
               variant                   string "VBTM"
            )
            dict entry(
               string "Model"
               variant                   string "Store'n'go"
            )
            dict entry(
               string "Revision"
               variant                   string "6.51"
            )
            dict entry(
               string "Serial"
               variant                   string "0E21E5708251F9A3"
            )
            dict entry(
               string "WWN"
               variant                   string ""
            )
            dict entry(
               string "Id"
               variant                   string "VBTM-Store'n'go-0E21E5708251F9A3"
            )
            dict entry(
               string "Configuration"
               variant                   array [
                  ]
            )
            dict entry(
               string "Media"
               variant                   string ""
            )
            dict entry(
               string "MediaCompatibility"
               variant                   array [
                  ]
            )
            dict entry(
               string "MediaRemovable"
               variant                   boolean true
            )
            dict entry(
               string "MediaAvailable"
               variant                   boolean true
            )
            dict entry(
               string "MediaChangeDetected"
               variant                   boolean true
            )
            dict entry(
               string "Size"
               variant                   uint64 999816704
            )
            dict entry(
               string "TimeDetected"
               variant                   uint64 1509870909475067
            )
            dict entry(
               string "TimeMediaDetected"
               variant                   uint64 1509870909475067
            )
            dict entry(
               string "Optical"
               variant                   boolean false
            )
            dict entry(
               string "OpticalBlank"
               variant                   boolean false
            )
            dict entry(
               string "OpticalNumTracks"
               variant                   uint32 0
            )
            dict entry(
               string "OpticalNumAudioTracks"
               variant                   uint32 0
            )
            dict entry(
               string "OpticalNumDataTracks"
               variant                   uint32 0
            )
            dict entry(
               string "OpticalNumSessions"
               variant                   uint32 0
            )
            dict entry(
               string "RotationRate"
               variant                   int32 -1
            )
            dict entry(
               string "ConnectionBus"
               variant                   string "usb"
            )
            dict entry(
               string "Seat"
               variant                   string "seat0"
            )
            dict entry(
               string "Removable"
               variant                   boolean true
            )
            dict entry(
               string "Ejectable"
               variant                   boolean true
            )
            dict entry(
               string "SortKey"
               variant                   string "01hotplug/1509870909475067"
            )
            dict entry(
               string "CanPowerOff"
               variant                   boolean true
            )
            dict entry(
               string "SiblingId"
               variant                   string "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0"
            )
         ]
      )
   ]
signal time=1509870909.477243 sender=:1.5 -> destination=(null destination) serial=203 path=/org/freedesktop/UDisks2; interface=org.freedesktop.DBus.ObjectManager; member=InterfacesAdded
   object path "/org/freedesktop/UDisks2/block_devices/sdb"
   array [
      dict entry(
         string "org.freedesktop.UDisks2.Block"
         array [
            dict entry(
               string "Device"
               variant                   array of bytes "/dev/sdb" + \0
            )
            dict entry(
               string "PreferredDevice"
               variant                   array of bytes "/dev/sdb" + \0
            )
            dict entry(
               string "Symlinks"
               variant                   array [
                     array of bytes "/dev/disk/by-id/usb-VBTM_Store_n_go_0E21E5708251F9A3-0:0" + \0
                     array of bytes "/dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0" + \0
                  ]
            )
            dict entry(
               string "DeviceNumber"
               variant                   uint64 2064
            )
            dict entry(
               string "Id"
               variant                   string ""
            )
            dict entry(
               string "Size"
               variant                   uint64 999816704
            )
            dict entry(
               string "ReadOnly"
               variant                   boolean false
            )
            dict entry(
               string "Drive"
               variant                   object path "/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3"
            )
            dict entry(
               string "MDRaid"
               variant                   object path "/"
            )
            dict entry(
               string "MDRaidMember"
               variant                   object path "/"
            )
            dict entry(
               string "IdUsage"
               variant                   string ""
            )
            dict entry(
               string "IdType"
               variant                   string ""
            )
            dict entry(
               string "IdVersion"
               variant                   string ""
            )
            dict entry(
               string "IdLabel"
               variant                   string ""
            )
            dict entry(
               string "IdUUID"
               variant                   string ""
            )
            dict entry(
               string "Configuration"
               variant                   array [
                  ]
            )
            dict entry(
               string "CryptoBackingDevice"
               variant                   object path "/"
            )
            dict entry(
               string "HintPartitionable"
               variant                   boolean true
            )
            dict entry(
               string "HintSystem"
               variant                   boolean false
            )
            dict entry(
               string "HintIgnore"
               variant                   boolean false
            )
            dict entry(
               string "HintAuto"
               variant                   boolean true
            )
            dict entry(
               string "HintName"
               variant                   string ""
            )
            dict entry(
               string "HintIconName"
               variant                   string ""
            )
            dict entry(
               string "HintSymbolicIconName"
               variant                   string ""
            )
         ]
      )
      dict entry(
         string "org.freedesktop.UDisks2.PartitionTable"
         array [
            dict entry(
               string "Partitions"
               variant                   array [
                  ]
            )
            dict entry(
               string "Type"
               variant                   string "dos"
            )
         ]
      )
   ]
signal time=1509870909.571078 sender=:1.5 -> destination=(null destination) serial=204 path=/org/freedesktop/UDisks2; interface=org.freedesktop.DBus.ObjectManager; member=InterfacesAdded
   object path "/org/freedesktop/UDisks2/block_devices/sdb1"
   array [
      dict entry(
         string "org.freedesktop.UDisks2.Block"
         array [
            dict entry(
               string "Device"
               variant                   array of bytes "/dev/sdb1" + \0
            )
            dict entry(
               string "PreferredDevice"
               variant                   array of bytes "/dev/sdb1" + \0
            )
            dict entry(
               string "Symlinks"
               variant                   array [
                     array of bytes "/dev/disk/by-id/usb-VBTM_Store_n_go_0E21E5708251F9A3-0:0-part1" + \0
                     array of bytes "/dev/disk/by-partuuid/ecd1c11c-01" + \0
                     array of bytes "/dev/disk/by-path/pci-0000:00:14.0-usb-0:3:1.0-scsi-0:0:0:0-part1" + \0
                     array of bytes "/dev/disk/by-uuid/5F04-1AF7" + \0
                  ]
            )
            dict entry(
               string "DeviceNumber"
               variant                   uint64 2065
            )
            dict entry(
               string "Id"
               variant                   string "by-uuid-5F04-1AF7"
            )
            dict entry(
               string "Size"
               variant                   uint64 998244352
            )
            dict entry(
               string "ReadOnly"
               variant                   boolean false
            )
            dict entry(
               string "Drive"
               variant                   object path "/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3"
            )
            dict entry(
               string "MDRaid"
               variant                   object path "/"
            )
            dict entry(
               string "MDRaidMember"
               variant                   object path "/"
            )
            dict entry(
               string "IdUsage"
               variant                   string "filesystem"
            )
            dict entry(
               string "IdType"
               variant                   string "vfat"
            )
            dict entry(
               string "IdVersion"
               variant                   string "FAT32"
            )
            dict entry(
               string "IdLabel"
               variant                   string ""
            )
            dict entry(
               string "IdUUID"
               variant                   string "5F04-1AF7"
            )
            dict entry(
               string "Configuration"
               variant                   array [
                  ]
            )
            dict entry(
               string "CryptoBackingDevice"
               variant                   object path "/"
            )
            dict entry(
               string "HintPartitionable"
               variant                   boolean true
            )
            dict entry(
               string "HintSystem"
               variant                   boolean false
            )
            dict entry(
               string "HintIgnore"
               variant                   boolean false
            )
            dict entry(
               string "HintAuto"
               variant                   boolean true
            )
            dict entry(
               string "HintName"
               variant                   string ""
            )
            dict entry(
               string "HintIconName"
               variant                   string ""
            )
            dict entry(
               string "HintSymbolicIconName"
               variant                   string ""
            )
         ]
      )
      dict entry(
         string "org.freedesktop.UDisks2.Filesystem"
         array [
            dict entry(
               string "MountPoints"
               variant                   array [
                  ]
            )
         ]
      )
      dict entry(
         string "org.freedesktop.UDisks2.Partition"
         array [
            dict entry(
               string "Number"
               variant                   uint32 1
            )
            dict entry(
               string "Type"
               variant                   string "0x0b"
            )
            dict entry(
               string "Flags"
               variant                   uint64 0
            )
            dict entry(
               string "Offset"
               variant                   uint64 1048576
            )
            dict entry(
               string "Size"
               variant                   uint64 998244352
            )
            dict entry(
               string "Name"
               variant                   string ""
            )
            dict entry(
               string "UUID"
               variant                   string "ecd1c11c-01"
            )
            dict entry(
               string "Table"
               variant                   object path "/org/freedesktop/UDisks2/block_devices/sdb"
            )
            dict entry(
               string "IsContainer"
               variant                   boolean false
            )
            dict entry(
               string "IsContained"
               variant                   boolean false
            )
         ]
      )
   ]

In short:

  • a signal org.freedesktop.DBus.NameAcquired on path /org/freedesktop/DBus
  • a signal org.freedesktop.DBus.ObjectManager.InterfacesAdded on path /org/freedesktop/UDisks2, object path "/org/freedesktop/UDisks2/drives/VBTM_Store_27n_27go_0E21E5708251F9A3" with information about the physical USB stick
  • a signal org.freedesktop.DBus.ObjectManager.InterfacesAdded on path /org/freedesktop/UDisks2, object path "/org/freedesktop/UDisks2/block_devices/sdb" with information about the /dev/sdb partition
  • a signal org.freedesktop.DBus.ObjectManager.InterfacesAdded on path /org/freedesktop/UDisks2, object path "/org/freedesktop/UDisks2/block_devices/sdb1" with information about the /dev/sdb1 partition

Audio files

Suitable audio files for playback:

  • the 'synthesized' versions from batcalls.com by AviSoft, these are mostly mono 16-bit PCM, sampled at 250000 Hz