themixedsignal
Published © GPL3+

Automated Pickup Winder Using an Arduino Uno

Project uses an Arduino Uno and a pair of stepper motors to wind tonewheel organ pickups.

AdvancedShowcase (no instructions)8 hours7,201

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
NEMA17 Stepper
×2
LM8UU Bearing
×2
8mmx150mm Rods
×2
M3 Screws, Nuts, Heated Inserts
×20
Laser-Cut Base Plate
×1
Misc 3D Printed Parts
×6
OPB815WZ Sensor
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Laser cutter (generic)
Laser cutter (generic)

Story

Read more

Custom parts and enclosures

Files for Printing and Laser Cutting

Schematics

Optical Sensor Hookup

Code

Arduino Uno Sketch

Arduino
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <https://www.gnu.org/licenses></https:>.

#define MAX_XPOS 64000  // Start of pickup
#define MIN_XPOS 15000  // End of pickup

#define ARLEN 32 //Length of ADC read buffer from potentiometer

#define ANALOGPIN A4
#define FLAGPIN A5

#define ENABLE 8
#define X_STEP 2
#define X_DIR 5
#define STEP 3
#define DIRECT 6
#define READLOOP 5
#define STEPLOOP 800

boolean toggle0 = 0;
boolean toggle1 = 0;
boolean toggle2 = 0;
boolean step1 = 0;
volatile int steps = 0;
volatile int turns = 0;
volatile boolean turnflag = 0;
bool flagVal = false;
bool xstepFlagHigh=false;
bool xstepFlagLow=true;



unsigned long xPos;
unsigned long timeA;
unsigned long timeMicros;
int xIncrement = 1;
int aRead;
int readbuffer[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned int buffi = 0;

boolean readflag = 0;



void setup(){
  //setup will initialize serial, timers, and run a "homing" protocol

  Serial.begin(115200);
  Serial.write("begin");
  
  //set pins as outputs
  pinMode(ENABLE, OUTPUT);
  pinMode(DIRECT, OUTPUT);
  pinMode(STEP, OUTPUT);
  pinMode(X_STEP,OUTPUT);
  pinMode(X_DIR,OUTPUT);
  pinMode(ANALOGPIN, INPUT);
  pinMode(FLAGPIN, INPUT);
  digitalWrite(ENABLE,LOW);
  digitalWrite(DIRECT,LOW);

  
  digitalWrite(X_DIR, HIGH);

  long initSteps = 100000;

  //move_forward to get out of any flags
  for(int i = 0; i<3200; i++)
  {
    digitalWrite(X_STEP, HIGH);
    delayMicroseconds(350);
    digitalWrite(X_STEP,LOW);
    delayMicroseconds(350);
  }

  //change direction and back into the flag
  digitalWrite(X_DIR,LOW);
  delay(500);

  while(flagVal == false && initSteps>0)
  {
    flagVal = digitalRead(FLAGPIN);
    digitalWrite(X_STEP, HIGH);
    delayMicroseconds(350);
    digitalWrite(X_STEP,LOW);
    delayMicroseconds(350);
    initSteps--;
  }

  xPos=0;

  digitalWrite(X_DIR,HIGH);

  //Move to start of pickup (MIN_XPOS)

  for(int i = 0; i<MIN_XPOS; i++)
  {
    digitalWrite(X_STEP, HIGH);
    delayMicroseconds(350);
    digitalWrite(X_STEP,LOW);
    delayMicroseconds(350);
    xPos+=xIncrement;
  }

  digitalWrite(X_DIR,LOW);

cli();//stop interrupts

//Configure timer
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  OCR1A = 24;
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS11) | (0 << CS10);  
  TIMSK1 |= (1 << OCIE1A);


sei();//allow interrupts

}//end setup


ISR(TIMER1_COMPA_vect)
//Timer ISR --> try to keep this uncomplicated
{
  if (toggle1 && step1){
    digitalWrite(3,HIGH);
    toggle1 = 0;
  }
  else{
    digitalWrite(3,LOW);
    toggle1 = 1;
    steps++;
  }
  if(steps>=3200)
  {
    if(step1)
    {
    turns++;
    steps = 0;
    turnflag = true;
    }
  }
}

//averages the array of past ADC values to length n  
int average (int *readbuffer, unsigned int n)
{
  int cumul = 0;
  for(int i = 0; i<n; i++)
  {
    cumul += readbuffer[i];
    
  }

  return (int)(cumul/n);
}

void loop(){

  timeA = millis();
  timeMicros = micros();

  int avg = average(readbuffer, 32);
  
  flagVal = digitalRead(FLAGPIN);

  //deadzone between 950 and 1024 = "off".
  //This means the spindle won't wind.
  
  if(avg>=950)
  {
    step1=false;
  }

  else
  {
    step1 = true;
  }

  //Verify that it's the right time to step, verify no limit is flagged,
  //and then take a step in the right direction

  if(timeMicros%STEPLOOP <= STEPLOOP/2 && xstepFlagHigh == true)
  {
     
     flagVal=digitalRead(FLAGPIN);
     if(flagVal==1 || xPos <= MIN_XPOS)
     {
      digitalWrite(X_DIR,HIGH);
      xIncrement = 1;
     }
     else if(xPos >= MAX_XPOS)
     {
      digitalWrite(X_DIR,LOW);
      xIncrement = -1;
     }

     
     digitalWrite(X_STEP,HIGH);
     xPos+= xIncrement;

     xstepFlagHigh = false;
     xstepFlagLow = true;

  }

  //Toggle line low if scheduled
  if(timeMicros%STEPLOOP > STEPLOOP/2 && xstepFlagLow == true)
  {
    digitalWrite(X_STEP,LOW);
    xstepFlagLow = false;
    xstepFlagHigh = true;
  }

  //Adjust speed of motor by tweaking timer interrupt
  //Take a new ADC reading and stuff into bufer

  if(timeA%READLOOP==0 && readflag)
  {
    cli();
    OCR1A = (int)(avg/4+36);
    aRead = analogRead(ANALOGPIN);
    readbuffer[buffi]=aRead;
    buffi = (buffi+1)%ARLEN;
    sei();
    readflag = false;
  }

  //debounces read schedule
  if(timeA%READLOOP>=READLOOP/2)
  {
    readflag = true;
  }

  //if a turn has completed, shoot out the total number of turns completed
  if(turnflag)
  {
    turnflag = false;
    Serial.print(turns);
    Serial.print(" ");
    Serial.print(flagVal);
    Serial.print("\n");
  }
  
}

Credits

themixedsignal
2 projects • 4 followers
Contact

Comments

Please log in or sign up to comment.