Pages: [1]   Go Down
Author Topic: Arduino Guitar Pickup Winder  (Read 3603 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 68
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

New project in the works.

A guitar pickup winder. Specs are:

1. Input total winds
2. LCD display
3. RPM display
4. Turns display
5. Shutoff after # of turns are reached

Here's a short video. Sorry for the shakey hand, but it's hard to hold a camera while touching buttons.

Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 68
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

And here's the code if anyone wants to pick through it.

Code:
/*

 Title: Willy Winder v1.0
 Author: William Begg
 Website: www.willyguitars.com 
 Date: 01-20-2012
 
 sketch for counting turns with optointerruptor for pickup
 winder. Uses interrupt on pin 2 to increment counts and
 displays pertinent information on a 20 x 4 LCD Display.
 
 Thanks to the Arduino community for their help, and to Pete Mills at
 petemills.blogspot.com for supplying some code I was able to use.
 
 */
#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);


// Global Variables

volatile unsigned int M_SEC_0 = 0;        // for rpm
volatile unsigned int M_SEC_1 = 0;        // for rpm
volatile unsigned long CUR_WINDS = 0;      // current count of winds
volatile unsigned int RPM_CNT = 0;        // revolution increment for RPM calc


// pin map

const int tachPin = 0;    // infrared tachometer input. Pin 2 for interrupt.
const int motorEng = 4;   // pin for motor relay
const int pwmIn = A5;     // Potentiometer pin to set motor speed pwm
const int pwmOut = 3;     // PWM out for motor speed
const unsigned int A_SW = A0;       // analog switch

void setup()
{
  lcd.begin(20,4);          // 20x4 HD44780 compatible LCD display (JHD204A)

  pinMode(tachPin, INPUT);  // input pin for calculating winds and rpm
  pinMode(motorEng, OUTPUT); // connected to motor relay
  pinMode(pwmIn, INPUT);
  pinMode(pwmOut, OUTPUT);
  digitalWrite(tachPin, HIGH);
  digitalWrite(motorEng, HIGH);

  // Attach the Interrupt

  attachInterrupt(tachPin, tachometer, RISING);  // interrupt for counting. Connected to optointerrupter on digital pin 2 (interrupt 0) 
}


// Interrupt function

void tachometer()
{
  CUR_WINDS++;        // increment # of winds cnt
  RPM_CNT++;          // increment count for RPM calculation
}


// function set to read switches from resistor array to save analog inputs on arduino

int read_ana_switch()
{

  /*
  reads analog switch and returns integer val 1::n
   This is done to save digital inputs.  Here we can have numerous switches on
   one analog pin.
   
   switch    int val
   UP_SW      1
   DN_SW      2
   LT_SW      3 (not currently used)
   RT_SW      4 (not currently used)
   RED_SW     5
   GRN_SW     6
   */


  const int HYS = 4;           // Hysteresis for selection +/- adc counts
  const int UP_SW = 51;        // adc counts for up switch
  const int DN_SW = 61;        // adc counts for down switch
  const int LT_SW = 71;        // adc counts for left switch
  const int RT_SW = 84;        // adc counts for right switch
  const int RED_SW = 128;      // adc counts for red arcade button
  const int GRN_SW = 108;      // adc counts for green arcade button

  int adc = 0;           // raw adc counts
  int which_switch = 0;  // which switch was pressed

  adc = analogRead(A_SW);  // dummy read for multiplex settling
  delay(10);
  adc = analogRead(A_SW);

  if( ( adc >= UP_SW - HYS ) && ( adc <= UP_SW + HYS ) )
  {
    which_switch = 1;
  }
  else if( ( adc >= DN_SW - HYS ) && ( adc <= DN_SW + HYS ) )
  {
    which_switch = 2;
  }
  else if( ( adc >= LT_SW - HYS ) && ( adc <= LT_SW + HYS ) )
  {
    which_switch = 3;
  }
  else if( ( adc >= RT_SW - HYS ) && ( adc <= RT_SW + HYS ) )
  {
    which_switch = 4;
  }
  else if( ( adc >= RED_SW - HYS ) && ( adc <= RED_SW + HYS ) )
  {
    which_switch = 5;
  }
  else if( ( adc >= GRN_SW - HYS ) && ( adc <= GRN_SW + HYS ) )
  {
    which_switch = 6;
  }

  return which_switch;
}


void spinit()
{
  /*
 
   Turns motor and counts total turns and calculates RPM 
   
   */

  static unsigned int num_winds = 100;  // default number of winds to perform
  unsigned int wind_inc = 1;             // increment num_winds by...
  unsigned int ms_elapsed = 0;           // number of milliseconds elapsed when counting to 1 second for rpm calc
  unsigned int rpm = 0;                  // average speed of guitar pickup
  int ana_sw = 0;
  int prev_ana_sw = 0;

  lcd.clear();

  while( ana_sw != 5 )
  {
    if(num_winds >= (CUR_WINDS+1))
      digitalWrite(motorEng, HIGH);
    else digitalWrite(motorEng, LOW);
    int sensorValue = analogRead(pwmIn); // read speed potentiometer
    int outputValue = map(sensorValue, 0, 1023, 0, 255); // map the sensor value to a range from 0 - 255:
    analogWrite(pwmOut, outputValue); // use that to control the transistor

    long winds_rem = (num_winds - CUR_WINDS);
    ana_sw = read_ana_switch();      // read the analog switch

      if( ana_sw == 1 | ana_sw == 2 )  // inc/dec faster if sw is held down
    {
      if( ana_sw == prev_ana_sw )
      {
        wind_inc++;
      }
      else
      {
        wind_inc = 1;
      }
    }

    if( ana_sw == 1 )
    {
      lcd.clear();
      num_winds += wind_inc;  // if the up switch is pressed, increment the number of winds to do
    }
    if( ana_sw == 2 )
    {
      lcd.clear();
      num_winds -= wind_inc;  // if the down switch is pressed, decrement the number of winds to do
    }
    prev_ana_sw = ana_sw;   
    // calculate RPM in 1hz intervals

    M_SEC_1 = millis();                 // get elapsed time
    ms_elapsed = M_SEC_1 - M_SEC_0;

    if( ms_elapsed >= 1000 ) 
    {
      rpm = ( ( 60000 / ms_elapsed ) * RPM_CNT );          // calculate rpm

      M_SEC_0 = millis();    //reset counters
      M_SEC_1 = M_SEC_0;
      RPM_CNT = 0;
    }


    if (CUR_WINDS >= num_winds)
    {
      lcd.setCursor(0,3);
      lcd.print("Winding is Complete!");
    }
    lcd.setCursor(0,0);
    lcd.print("# Winds: ");
    lcd.print(num_winds);
    lcd.setCursor(0,1);
    lcd.print("RPM: ");
    lcd.print(rpm);
    lcd.setCursor(0,2);
    lcd.print("Total Winds: ");
    lcd.print(CUR_WINDS);
    lcd.setCursor(0,3);

  }

  lcd.clear();
  digitalWrite(motorEng, LOW);
  CUR_WINDS = 0;
  delay(400);

}


void loop()

{
  int start_sw = read_ana_switch();

  lcd.setCursor(0,0);
  lcd.print("  WILLY WINDER v1.0");
  lcd.setCursor(0,1);
  lcd.print("  Lower Motor Speed");
  lcd.setCursor(0,2);
  lcd.print("   And Press Enter");
  lcd.setCursor(0,3);
  lcd.print("      To Begin");
  if (start_sw == 6 && (analogRead(pwmIn)) < 1) // enables motor only if speed is turned down at start.
    spinit();

}
Logged

Cairns - Green Island for Winter
Offline Offline
Full Member
***
Karma: 2
Posts: 148
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

WTF is a willy winder?
Logged

Governments should do what they were designed to do only.
Manage the larger issues best done by Government.
My Family and my Property are no

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 94
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Cool project wbegg

Interesting how you calculate the RPM once per second, I would have done it based on the period of each pulse.
I've got lots of questions.
What kind of opto interuptor are you using, did you make it yourself?
Also what kind of motor are you using ? Are you stopping it to prevent overwinding?
What about issues like moving the wire back and forth so it winds evenly? Is that a problem?
Most importantly how do your pickups sound!

Cheers!
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 68
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the questions, emdee.

The optointerruptor I stole off an old printer. It's pretty much just a phototransistor driven with an LED in a contained package with a slot. I use a clear  CD blank with a black stripe to trigger the count. It's driven with a schmitt trigger circuit. I could have used an actual schmitt trigger chip, but I used what I had on hand (See attached pic).

The motor is a 12V also out of a printer. It's driven PWM by the arduino to control speed through a 30N06L Mosfet. The motor stops automatically when the desired # of turns is reached. I did have the motor controlled with a relay (as in picture attached), but figured if I had PWM, I could just send digital pin Low to stop motor.

Currently, there is no auto-traversing, and all layers traversed by hand. I have not wound any pickups yet as I am still building the final box for the monster. I'll also have a guide rail to manually set stops at the ends of the bobbin.

All of the buttons are controlled via a resistor network to limit input pins to the arduino.

I cannot take full credit. I borrowed alot of ideas from Pete Mills, who has a great blog here. http://petemills.blogspot.com/2011/08/guitar-pickup-winder.html





* Motor Driver.JPG (46.99 KB, 903x543 - viewed 98 times.)

* schmitt trigger.JPG (41.76 KB, 635x428 - viewed 84 times.)
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 68
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Optointerruptor similar to this.



* Opto.JPG (24.73 KB, 412x313 - viewed 61 times.)
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 68
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've designed a standalone arduino for this application, and included the motor driver section on the board. If anyone is interested, I've attached a pic and the Eagle PCB file.



* ArduinoPUWinder.JPG (85.83 KB, 575x537 - viewed 100 times.)
* ArduinoStandalone.brd (104.93 KB - downloaded 34 times.)
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 68
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Board is done and tested. Here's a pic.



* 2012-01-25 18.29.03.jpg (426.61 KB, 1200x952 - viewed 111 times.)
Logged

Pages: [1]   Go Up
Jump to: