Home > DIY Playthings > 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 10 Ohm 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: DIY Playthings Tags: ,
  1. ratseal
    May 1, 2012 at 12:11

    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

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

    • elims
      September 5, 2012 at 22:06

      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

    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?

  4. Pm
    September 16, 2015 at 08:45

    Hi! I have tried to copy your project, but I noticed that you have int indloadpin 5 => where to connect this? There is no explanation and in picture you have 10 ohm resistor, but in text you say it is 100 ohms?
    Otherwise this seems really interesting projectūüôā

    • elims
      September 18, 2015 at 17:36

      Hi Peeta,

      this is a 10 Ohm resistor. Ths indloadpin is not taken account for in the schematic. This would be Pin 5 of the Arduino. I’ve never actually used it. It could be a second vibrator. You can ignor it. The code will work the way it is.

      Cheers

  1. No trackbacks yet.

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

%d bloggers like this: