Introduction: Automated Ball Roller With Arduino and One Servo

About: I am an American teaching English at Shangluo University, Shaanxi. I like making machines that do interesting but fairly useless things - I call them Quixotic Machines.

This is a simple little Arduino and servo project that takes about two hours to complete. It uses a servo to lift one end of a jar cap so as to spin a steel ball around the inside circumference. It is self starting, can change speed and can spin two (or more?) balls at once. Fun to build and get working. The timing parameters can be played with for probably even faster speeds. A few hall effect sensors with a magnetic ball could be used to make it a smarter machine that can figure out the best parameters.

I should mention that someone here at instructables.com has a more sophisticated ball roller machine: https://www.instructables.com/id/Perpetual-Ball-Ro...

Materials needed:

Arduino Uno (or any Arduino)

Servo shield (optional)

9g servo

jar cap

steel ball

some scrap wood

Step 1: Make Base and Hinged Cap Holder

The base is just a hunk of wood to mount the hinged piece of wood on. The hinged wood should be larger than a jar cap that you will use and have enough room for the hinges and to mount the servo.

I used little plastic rc aircraft hinges and just hotglued them to the hinged wood and the base.

Step 2: Make Longer Servo Arm and Attach Servo

To make a longer servo arm I just attached a 5 centimeter piece of wood to the servo arm with a couple of small screws and nuts. The servo arm should be at 90 degrees on the servo when it is horizontal to the base.

I just hot glued the servo to the hinged wood holder but I found that if you let it run for longer than a few minutes, the servo will heat up the hot glue and let go from the wood. So a better attachment method is warranted.

Step 3: Load and Run Sketch

I attached my servo to pin 7 using a shield because it is just convenient and they only cost a few bucks. If you don't have a shield then attach the servo signal wire to pin 7 on the Arduino, the red wire to 5v on the Arduino and the ground wire to GND on the Arduino. The arduino should provide enough current to operate the servo. I use the shield because it is easy to use an external voltage just for the servo.

Here is the sketch. I wrote a servo speed controller routine so as to alter the speed of the servo because it probably won't work well at full speed.

You can alter the timingDelay to get different speeds of ball rolling. You could also alter the third parameter of the myServo() function to change speed as well.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// created by Jim Demello, Shangluo University, 2017

// you are free to use, manipulate, do whatever you wish with this code, my name is not required

// This routine allows any number of servos to be interpolated, just add new lines if number of servos exceeds 4

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <Servo.h>

Servo myservo1,myservo2; // create servo object to control a servo

int servoRead(int servoNumber) {

int servoCurrent;

if (servoNumber== 1) { servoCurrent = myservo1.read(); }

if (servoNumber== 2) { servoCurrent = myservo2.read(); }

return servoCurrent;

}

void servoWrite(int servoNumber, int offset) {

if (servoNumber==1) { myservo1.write(offset); }

if (servoNumber==2) { myservo2.write(offset); }

}

void myServo(int newAngle,int angleInc,int incDelay,int servoNum) {

int curAngle;

if (servoNum== 1) { curAngle = myservo1.read(); }

if (servoNum== 2) { curAngle = myservo2.read(); }

if (curAngle < newAngle) {

for(int angle=curAngle;angle < newAngle;angle += angleInc) {

if (servoNum == 1) myservo1.write(angle);

if (servoNum == 2) myservo2.write(angle);

delay(incDelay); }

}

else if (curAngle > newAngle) {

for(int angle=curAngle;angle > newAngle;angle -= angleInc) {

if (servoNum == 1) myservo1.write(angle);

if (servoNum == 2) myservo2.write(angle);

delay(incDelay); }

}

}

void interpolate2Servos( int servo1,int servo1Position,

int servo2,int servo2Position,

int numberSteps,int timeDelay){

int servo1Current,servo2Current;

servo1Current = servoRead(servo1);

servo2Current = servoRead(servo2);

// Serial.print("Servo3Pos and Current "); Serial.print(servo3Position); Serial.print(" "); Serial.println(servo3Current);

// Serial.print("Servo4Pos and Current "); Serial.print(servo4Position); Serial.print(" "); Serial.println(servo4Current);

// Serial.print("Servo5Pos and Current "); Serial.print(servo5Position); Serial.print(" "); Serial.println(servo5Current);

// Serial.print("Servo6Pos and Current "); Serial.print(servo6Position); Serial.print(" "); Serial.println(servo6Current);

// Serial.println(" ");

int cOffset = (servo1Position - servo1Current); cOffset = abs(cOffset)/numberSteps;

int dOffset = (servo2Position - servo2Current); dOffset = abs(dOffset)/numberSteps;

int cOffsetTotal=0,dOffsetTotal=0;

cOffsetTotal = servo1Current;

dOffsetTotal = servo2Current;

for (int x=0; x

if (servo1Position > servo1Current) { cOffsetTotal = cOffsetTotal + cOffset; }

else { cOffsetTotal = cOffsetTotal - cOffset; }

if (servo2Position > servo2Current) { dOffsetTotal = dOffsetTotal + dOffset; }

else { dOffsetTotal = dOffsetTotal - dOffset; }

if (servo1Position != servo1Current) servoWrite(servo1,cOffsetTotal);

if (servo2Position != servo2Current) servoWrite(servo2,dOffsetTotal);

// Serial.print(" a and b Offset "); Serial.print(aOffsetTotal); Serial.print(" ");Serial.println( bOffsetTotal); delay(10);

delay(timeDelay);

}// end for

//////////////////////////////////////

// take care of modulo remainders //

/////////////////////////////////////

if (servo1Position != servo1Current) servoWrite(servo1,servo1Position);

if (servo2Position != servo2Current) servoWrite(servo2,servo2Position);

}

int timingDelay = 100;

int servoDelay = 100;

int degGap = 10;

// This is the starting degree (must be less than end degree)

int degStart = 0;

// This is the ending degrees (must be greater than start degree)

int degEnd = 360;

//This is the circle radius

int radius = 8;

void setup()

{

Serial.begin(9600);

delay(100);

myservo1.attach(7); // attaches the servo on pin 7 to the servo object

myservo1.write(90);

myservo2.attach(8); // attaches the servo on pin 8 to the servo object

myservo2.write(90);

delay(1000); // waits for the servo to get there

interpolate2Servos( 1,90,2,90,10,60); // neutral

delay(1000);

}

void loop() {

timingDelay = 15; // works at 10

servoDelay = 4;

spin4();

//interpolate2Servos( 1,90,2,90,1,60); // neutral

//delay(1000);

// exit(0); //pause program - hit reset to continue

}

void spin3() {

interpolate2Servos( 1,90,2,110,1,60); // neutral

delay(timingDelay);

interpolate2Servos( 1,90,2,80,1,60); // neutral

delay(timingDelay);

}

void spin2() {

//interpolate2Servos( 1,80,2,90,1,50); // neutral

delay(timingDelay);

interpolate2Servos( 1,80,2,80,1,60); // neutral

delay(timingDelay);

interpolate2Servos( 1,110,2,80,1,60); // neutral

delay(timingDelay);

//interpolate2Servos( 1,110,2,110,1,60); // neutral

delay(timingDelay);

}

void spin1() {

// int deg = (degStart / (180 / 3.14));

float deg = (degStart * 3.141592 / 180); // convert degrees to radians

float xPos = 90 + (cos(deg) * radius);

// xPos = round(xPos);

float yPos = 90 + (sin(deg) * radius);

// yPos = round(yPos);

Serial.print("degGap=");Serial.print(degGap);Serial.print(" deg=");Serial.print(deg);Serial.print(" cos=");Serial.print(cos(deg));Serial.print(" degStart=");Serial.print(degStart);Serial.print("x=");Serial.print(xPos);Serial.print(" y=");Serial.println(yPos);

// interpolate2Servos( 1,xPos,2,yPos,1,servoDelay); // neutral

myservo1.write(xPos );

myservo2.write(yPos);

delay(timingDelay);

if (degStart >= degEnd) {

degStart = 0;

if (degGap > 180)

degGap = 180;

//degGap = 0;

else

degGap = degGap + 2;

degGap = degGap - 2;

// degStart = degStart +degGap;

}

degStart = degStart + degGap;

}

void spin4() {

for(int i=0; i<=360; i++){

float j = 20 * (cos ((3.14 * i)/180)) + 90;

float k = 20 * (sin ((3.14 * i)/180)) + 90;

myservo1.write(j);

myservo2.write(k);

Serial.print(j);

Serial.print(",");

Serial.println(k);

delay(100);

}

}