please dont rip this site

Servo Motor Control With Audio Waveforms or Files

Any device that can play music (PC, SmartPhone, MP3 player, etc...) can be used to reproduce arbitrary waveforms within the limitations of the electronic system that drives the analog output. Long periods of maximum or minimum signal level may not be coupled if the electronics don't reproduce low frequencies well. Other than that, there is no reason why PWM Servo control signals can't be encoded in a sound and then played back to move a motor.

Connecting a PC or SmartPhone audio headphone jack to a pair of servos requires no more than an 0.1uF decoupling capacitor in line from each stereo channel to the servo PWM input. Some have found that the cap's cause distortion and should be bypassed. ^ This may cause damage so take care.

Schematics of GlueMotor Cable

Note: This circuit will only work with devices that have a very loud audio output. In most cases, a simple transistor amplifier will be required.

An app or HTML5 web app could provide cross platform, programmable, motion control via cheap RC servoes and this simple hardware. For more complex transmission of data from a web page see: Unidirectional I2C (2 wire) via Images

The most basic use is to simply record and play back a series of motions via a single huge audio file. There is no programatic control, just a simple repeitition of the movement for each play. Generating the wave file has been accomplished with MatLab and should be possible from other programming environments.

Many Files

To give the playback device, such as a web browser or SmartPhone, the ability to change the waveform as directed by a program, multiple files, each with a different position encoded, could be loaded and played, as desired. Obviously, that means having a HUGE number of files, for all possible combinations of each channel. Even for a single channel, single degree control would mean having 180 seperate files. The advangate of this approach is that it doesn't require HTML5 <audio> tag support. Any Javascript enabled device should be able to programatically select different files and play them. But before making those files, the hardware needs to be improved. The "Generate" approach below can be used until then.

One File, Multiple Waveform "sprites"

With Javascript control over the position of the playback via the .currentTime property, a single sound file, incoded with a series of different PWM position signals at different times in the playback, can provide servo control from an HTML5 web (or smartphone) app. The .currentTime value is expressed in seconds, so playback position can not be selected any finer than 1 second. As a result, each PWM value must be repeated in the file for one full second. This increases the required file size, but the advantage of loading only one file may make that worth while.

// UNTESTED sample code

<audio id="PWM" ontimeupdate='updatePWMTime(this);'>
  <source src="PWM.wav">

function setServoPosition(degrees) {
	var pwm = document.getElementById("PWM");
	pwm.desired = degrees + 90;

function updatePWMTime(pwm) {
	//if (pwm.currentTime>pwm.desired) { //not needed
		pwm.currentTime = pwm.desired;
	//	} //ontimeupdate is only called once a second.

<input type="range" name="degrees" min="-90" max="90" value="0" step="1" onchange='setServoPosition(this.value)';>

.WAV files are (ironically) not supported in Internet Explorer before version 9. They are supported in all other standard PC browsers (Chrome, Safari, Firefox). The Audio tag is supported in all modern browsers. Support on mobile devices may be buggy:

Although the .WAV file format allows almost any value for samples per second, in practice, the systems that play .WAV files back expect certain specific sample rates and depths. e.g. 96.000kHz (DVD), 48.000kHz (DAT), 44.100kHz - (CD, DAT, Mac, PC), 22.050kHz - (Mac, PC), 11.025kHz - (Mac, PC, Web).

For single degree resolution, the PWM signal needs to have 180 different duty cycles (allowing -90 to +90 degree movement in 1 degree intervals) from 1ms to 2ms. This requires a wavelength with enough samples to make 180 changes between those two values. The distance of 1ms (from 1 to 2) divided by 180 gives 5.55~degrees/ms. There must be 180 samples from 0 to 1ms, and another 180 from 1ms to 2ms, then some number of additional samples to complete the waveform in the low side. So more than 360 samples are required.

At 22050, each sample is ~0.0453ms so 1ms is abut 22 samples ~8' steps. 0.5MB file.

At 44100, each sample is ~0.0227ms so 1ms is about 44 samples ~4' steps. 2MB file

At 96000, a sample is ~0.0104ms so 1ms is about 96 samples ~2' steps. 9MB file

Obviously, there is no reasonable way to get single degree resolution. 2' isn't bad, but a 96KHz file would be very large. More than 9Mb. Perhaps it would compress well into an MP3?

Generate Waveform on Demand

In browsers that support the <audio> tag^ and .getChannelData(0)^ we can generate a high speed PWM wav on the fly^ and completely avoid the need for an audio file: Chrome for Andriod does support this as of version 18^

html4audiopwm.html (try it hint: use Chrome)

  <!-- AP: Last modified: 21-Jan-2016 -->
var sampleRate = 96000;
var samplesPerMilliSecond = sampleRate*0.001;
var samplesPerCycle = samplesPerMilliSecond * 3;
var bufferLength = samplesPerCycle; //buffer one cycle
var context = new AudioContext(); //used to be webkitAudioContext();
var buffer = context.createBuffer(2, bufferLength, sampleRate);
var data = buffer.getChannelData(0);
var data2 = buffer.getChannelData(1);
// Done: adjust samplesPerCycle to be an even multiple of the bufferLength
var degrees = 0;

function buildPWMWav(degrees, samplesPerMilliSecond, data) {
var pwm = (degrees+90)/180*samplesPerMilliSecond+samplesPerMilliSecond;
for (var i = 0; i < data.length; i++) {
/* Prepare data */
//data[i] = (Math.random() - 0.5) * 2; // Noise
//data[i] = (i>=samplesPerMilliSecond && i<pwm)? 2 : 0;
//data[i] = (i%samplesPerCycle<pwm)? 2 : 0
data[i] = (i<pwm)? 2 : 0

onPWMChange = function (degrees) {    
buildPWMWav(degrees, samplesPerMilliSecond, data);

onPWMChange2 = function (degrees) {    
buildPWMWav(degrees, samplesPerMilliSecond, data2);

onPWMChange(0); //start in the center.
onPWMChange2(45); //start offcenter.

var source = context.createBufferSource();
source.loop = true; // Make sure that sound will repeat over and over again
source.buffer = buffer; // Assign our buffer to the source node buffer

gainNode = context.createGain();

//connect the source to the gainNode, and the gainNode to the destination.

scale2log = function (x) {
  let x0 = 0, x1 = 1
  let offset = 0.0125
  let y0 = 0+offset, y1 = 1+offset
  let y1l = Math.log(y1)
  let y0l = Math.log(y0)
  let y = Math.exp((x * y0l - x * y1l + x0 * y1l - x1 * y0l) / (x0 - x1))
  y = y-offset //remove the offset
  y = Math.round(y * 1000) / 1000 //round off
  //console.log("x",x,"y",y ,"y1l",y1l,"y0l",y0l)
  return y

onVolumeChange = function (vol) {
gainNode.gain.value = scale2log(vol);
//console.log(Math.floor(gainNode.gain.value * 100));

onVolumeChange(0); //set initial volumn to zero

//Just start immediatly with zero volume. 
//Set volume to 0 to stop. If you use noteOff to stop, 
//you have to recreate the source.

displayWave = function(data,canvas) {
  var ctx = canvas.getContext('2d');
  var amp = Math.min(64*gainNode.gain.value,99)+10;
  canvas.width = data.length+10;
  ctx.fillStyle = 'white';
  ctx.strokeStyle = 'red';
  for (var i = 0; i < data.length; i++) {

--> </SCRIPT>
  <A HREF="">HTML5 web app</A>
  <A HREF="">PWM</A> 
  <A HREF="">audio generator</A>
  for <A HREF="">Servo</A> 
  <A HREF="">Motors</A>
<INPUT type="range" min=0 max=100 oninput="
	onVolumeChange(parseInt(this.value, 10) / 100);
	" value=2>
<INPUT type="button" value="On" onclick="onVolumeChange(1);
<INPUT type="button" value="Off" onclick="onVolumeChange(0);
Ch1 Degrees: -90
<INPUT type="range" min=-90 max=90 oninput="
	onPWMChange(parseInt(this.value, 10));
	" value=0>+90
<INPUT type="text" min=-90 max=90 size=3 onchange="
	onPWMChange(parseInt(this.value, 10));
	" value=0> <BR>
Ch2 Degrees: -90
<INPUT type="range" min=-90 max=90 oninput="
	onPWMChange2(parseInt(this.value, 10));
	" value=0>+90
<INPUT type="text" min=-90 max=90 size=3 onchange="
	onPWMChange2(parseInt(this.value, 10));
	" value=0>
<DIV id="degree">
<canvas id="scope" width="200" height="100"></canvas>
<DIV id="degree2">
<canvas id="scope2" width="200" height="100"></canvas>

Given the lack of support for HTML5 <audio> in SmartPhone Browsers, it might be necessary to use a set of seperate .wav or .mp3 files, each one encoding a different PWM position.

See also:

The ability to control a motor could then be combined with Javascript based object recognition to turn a cell phone into an object following device. +


file: /Techref/io/servo/wav.htm, 16KB, , updated: 2024/2/2 15:28, local time: 2024/7/15 04:34,

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF=""> Servo Motor, .Wav file, Hobby Servo, IOT</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.

Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?


Welcome to!


Welcome to!