Home > Electronic Gadgets > Vibrator Controller

Vibrator Controller

This is a simple Arduino Diecimilia based controller for a vibrator I build some time ago. The vibrator doesn’t life any more. It destructed itself within minutes due to the strong vibrations (R.I.P). It drives a 12V (or any other voltage between 6V to 20V) electro motor with pulse width modulation (PWM). Further it offers a couple of other options:

  1. PC-Mode: Lets the PC control the vibrator over USB. Also lets you store some custom wavetables in the EEPROM
  2. Const: Just controls the speed.
  3. Ramp: Ramps the speed to the set value. Very much like a saw-tooth.
  4. Throb: Increases and decreases the speed.
  5. Wavetable 1
  6. Wavetable 2
  7. Wavetable 3
  8. Wavetable 4
  9. Wavetable 5

The first knob lets you choose the program, the second knob controls the speed (except in PC-Mode) and the third knob controls the time from one step to the next.

Hardware

The brain is a very widely used Arduino Board. The other hardware to get the thing running is maximal simple.

On Pin 6 there is a Logic Level n-Channel MOSFET IRL1404 driven through a 10Ohm resistor. Beside that the motor needs a free running diode like the used Schottky-type PBYR1645. That’s basically all the magic. This combination should work even for beefy motors. Don’t forget heat sinks even though I never noticed any increase in temperature (except for the cables :-) ).

Setting the different programs is an even simpler task. I went with a simple rotary switch and a resistor cascade with 1k each. They act pretty much as a potentiometer but with defined switch points. The Arduino reads this with Analog Pin 0 and runs the appropriate function of the code.

Last but no least there are two 10k potentiometers as voltage dividers to set the intensity and a timing constant for the different programs and wavetables. They are wired to the Analog Pins 1 and 2.

Software

Since the Arduino sports a FTDI-Chip I thought of using this to make the gadget USB-controlled if desired. This works pretty fine if you type in the commands into a serial terminal, since there is no software written (yet). Beside that there is also some major bug in the read and write function of the EEPROM over the serial connection. I think it has something to do with some buffer size. At the moment I did a dirty hack and splited  the 100 bytes for each wavetable into small packets and send them packet by packet. I think there might be a more elegant solution for this problem, but it works for me since I momentary don’t use that feature anyway.

Firmware

#include <EEPROM.h>
#include <Messenger.h>

/* VIBROCONTROLLER  v0.1
 by elims - elims@gmx.net 

Mode 0: PC-Mode
Mode 1: const
Mode 2: ramp
Mode 3: fade
Mode 4 - 8: Read wavetable from EEPROM

*/

// ### globals ####################################################
Messenger message = Messenger();         //Instantiate the remote access

int pwmpin = 6;                           // PWM for vibrator
int indloadpin = 5;                       // Inductive load

int modepin = 0;                          // Resistor kaskade (7x 1k) for mode selection
int powerpin = 1;                         // 10k variable resistor for power
int freqpin = 2;                          // 10k variable resistor for time

int value = 0;                            // temporal value
int address = 0;                          // global iterator
int modevalue = 0;                        //
float strength = 0;                       // variable to keep the actual PWM value (0-255)
boolean rampup = true;                    // goes ramp up or down in
byte mode = 0;                            // Stores the current Mode

// ### functions ###################################################
void fade(){
 strength = float(analogRead(powerpin))/1024.0;
 if(value >= 255){
 rampup = false;
 }
 if(value <= 0){
 rampup = true;
 }
 if(rampup==true){
 value += 5;
 } else {
 value -= 5;
 }
 analogWrite(pwmpin, int(float(value)*strength));          
 delay(analogRead(freqpin)/2+5);                            
}

void ramp(){
 strength = float(analogRead(powerpin))/1024.0;
 if(value >= 255){
 value = 0;
 } else {
 value += 5;
 }
 analogWrite(pwmpin, int(float(value)*strength));          
 delay(analogRead(freqpin)/2+5);
}

/* inverse ramp
void iramp(){
 strength = float(analogRead(powerpin))/1024.0;
 if(value <= 0){
 value = 255;
 } else {
 value -= 5;
 }
 analogWrite(pwmpin, int(float(value)*strength));          
 delay(analogRead(freqpin)/2+5);
}
*/

void tablelookup(int table){
 strength = float(analogRead(powerpin))/1024.0;
 value = EEPROM.read(address + table*100);
 if(address >= 99){
 address = 0;
 } else {
 address += 1;
 }
 analogWrite(pwmpin, int(float(value)*strength));          
 delay(analogRead(freqpin)/2+5);
}

// Create the callback function
void messageReady() {
 if (message.available()) { // Checks to see if the message is complete and erases any previous messages
 if (mode > 0) {
 Serial.print('i');
 Serial.print(' ');
 Serial.print(mode, DEC);
 Serial.println();
 } else {
 switch (message.readChar()) { // Gets the first word as a character
 case 'r': // Read pins (analog or digital)
 readeeprom(); // Call the readpins function
 break; // Break from the switch
 case 'w': // Write pin
 writeeeprom(); // Call the writepin function
 break;
 case 's':
 setoutput();
 break;
 case 'i':
 Serial.print('i');
 Serial.print(' ');
 Serial.print(mode, DEC);
 Serial.println();
 }
 }
 }
}

void readeeprom() { // Read pins (analog or digital)
 int table = 0;
 int add = 0;
 switch (message.readChar()) { // Gets the next word as a character
 case 'e':
 Serial.print('e');
 Serial.print(' ');
 add = message.readInt();
 Serial.print(add);
 Serial.print(' ');
 Serial.print(EEPROM.read(address), DEC);
 break;
 case 'p':
 Serial.print('p');
 Serial.print(' ');
 table = message.readInt();
 Serial.print(table);
 Serial.print(' ');
 for(int i = 0; i < 100; i++) {
 Serial.print(EEPROM.read(i + table*100), DEC);
 Serial.print(' ');
 }      
 break;
 case 'a': // READ analog pins
 Serial.print('a');  // Echo what is being read
 Serial.print(' ');
 Serial.print(analogRead(powerpin));
 Serial.print(' ');
 Serial.print(analogRead(freqpin));
 Serial.print(' ');
 }
 Serial.println();
}

void writeeeprom() { // Write pin
 int table = 0;
 int batch = 0; //multipurpose integer (adresse, batchadresse, formatvalue)
 switch (message.readChar()) { // Gets the next word as a character
 case 'e' :
 batch = message.readInt();
 EEPROM.write(batch, message.readInt());
 Serial.println('d');
 break;    
 case 'p':
 table = message.readInt();
 batch = message.readInt();
 for(byte i = 0; i < 10; i++) {
 EEPROM.write(i + batch * 10 + table*100, message.readInt());
 }
 Serial.println('d');
 break;
 case 'f':
 table = message.readInt();
 batch = message.readInt();
 for(byte i = 0; i < 100; i++) {
 EEPROM.write(i + table*100, batch);
 }
 Serial.println('d');
 }
}

void setoutput() {
 switch (message.readChar()) {
 case 'a' :
 analogWrite(pwmpin, message.readInt()); //Sets the PWM of the pwmpin
 break;  // Break from the switch
 case 'b' :
 analogWrite(indloadpin, message.readInt());   //Sets the PWM of the indloadpin
 }
}

// ### main ###########################################
void setup()
{
 Serial.begin(9600); // 115200
 message.attach(messageReady);
 pinMode(pwmpin, OUTPUT);
 pinMode(indloadpin, OUTPUT);
} 

void loop()
{
 while (Serial.available())  message.process(Serial.read());
 modevalue = analogRead(modepin)/4;
 if(modevalue >= 0 && modevalue < 16) {
 value = 0;  //make sure ramp and fade start with 0
 mode = 0;
 }
 if(modevalue >= 16 && modevalue < 48) {
 analogWrite(pwmpin, analogRead(powerpin)/4);
 mode = 1;
 }
 if(modevalue >= 48 && modevalue < 80) {
 mode = 2;
 ramp();
 }
 if(modevalue >= 80 && modevalue < 112) {
 mode = 3;
 fade();
 }
 if(modevalue >= 112 && modevalue < 144) {
 mode = 4;
 tablelookup(0);
 }
 if(modevalue >= 144 && modevalue < 176) {
 mode = 5;
 tablelookup(1);
 }
 if(modevalue >= 176 && modevalue < 208) {
 mode = 6;
 tablelookup(2);
 }
 if(modevalue >= 208 && modevalue < 240) {
 mode = 7;
 tablelookup(3);
 }
 if(modevalue >= 240 && modevalue < 257) {
 mode = 8;
 tablelookup(4);
 }
}

Protocoll

A simple character based protocol is used to control the intensity, read the values from the analog inputs and perform r/w cycles on the EEPROM. Check the source code to find the different commands.

Software

Should be straight forward, but is not yet written.

Categories: Electronic Gadgets Tags: ,
  1. ratseal
    May 1, 2012 at 12:11 | #1

    Nice build. What dimensions do you get? Also, if you wanted to go wireless, does it shrink or grow?

  2. thean0nway
    September 5, 2012 at 07:41 | #2

    Could something like this be incorporated in to building an arduino controlled e-stim box?

    • elims
      September 5, 2012 at 22:06 | #3

      One certainly could, but squeezing some estim out of an arduino is no easy task. But there is a very small company in Germany which offers a very similar device. Unfortunately their Homepage is german-only. http://www.radiotoy.de They soon will release a python library for their system so anyone can play with it.

  3. techno
    September 16, 2013 at 17:25 | #4

    Nice! As soon as I figure out how to construct an appropriate housing (for a mini arduino _and_ the motor!), I will check this out. Can you please publish the wavetables as well, so that there is something to start with?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: