Introduction: Ball and Beam W/LabVIEW & Arduino

This was a school project, the assignment was to construct a ball and beam control system.

A ping pong ball sits on top of the beam rolling forwards and backwards according to the pitch of the beam. The pitch is controlled by a servo that is connected to an Arduino. The position of the ball is measured by a distance sensor mounted at the end of the beam.

An PID controller is used to control the position of the ball on the beam.

Step 1: Parts

Electronics

  • Distance sensor - SHARP 2Y0A21
  • Parallax Standard Servo (#900-00005)
  • Arduino
  • 5V powersupply

3D printed parts

Infill - 20%
Resolution - 0.15mm
Filament Material - PLA

  • Arm
  • Servo arm
  • Servo holder
  • Endplate with sensor
  • Endplate without sensor
  • Hinge

Mechanicall

  • 6x - M4x5mm
  • 1x - M3x45mm
  • 1x - M3x35mm
  • 1x - M3x10mm
  • 4x - 1,5x5mm wood screw
  • 4x - 3,5x15mm woood screw
  • Aluminum profile angle 520mm 15x15x2mm
  • Flanged bearings - 4mm Radial Ball Bearing 8mm O.D
  • 650x95x30mm wood board
  • 145x30x47mm wood stud
  • Ping pong ball

Step 2: Assembling

The design was 3D modelled with Fusion 360

Step 3: Electrical

You need to use an external 5 volt power supply to supply power the servo and distance sensor.

Step 4: PID Controller

LabVIEW

Using the LINX in LabVIEW to connect to the arduino.

Arduino

Using a modified version of SharpIR.h library, originaly by Dr. Marcal Casas-Cartagena

Step 5: LabVIEW Code

Select the COM port to the arduino and the servo and sensor pin.

Step 6: Arduino Code

// Libraries
#include <SharpIR.h> #include <Servo.h>

// Defines #define PIN_SERVO 3 #define PIN_SENSOR 0 #define PIN_LED 13 #define DEBUG_ACTIVE 1 #define IR_MODEL 1080

// Running average const int numReadings = 3; int readings[numReadings]; // The readings from the analog input int readIndex = 0; // The index of the current reading double total = 0; // The running total int sensorRunningAverage = 0;

// Constants const double Kp = 1; const double Ki = 0.1; const double Kd = 15; const double sampleTime = 100; // ms const double setpoint = 20; // cm const int sensorMax = 57; // cm

// Floating variables double error = 0; double oldError = 0; double diffError = 0; double sumError = 0; unsigned long lastTime = 0; unsigned long standbyTime = 0; unsigned long runningTime = 0; double u = 0; // Output of the PID controller int servoOutput = 0; // Output to the servo double dis = 0;

// Functrions Servo servo; SharpIR SharpIR(sensorRunningAverage, IR_MODEL);

void setup() { servo.attach(PIN_SERVO); pinMode(OUTPUT, PIN_LED);

startup();

for (int thisReading = 0; thisReading < numReadings; thisReading++) { readings[thisReading] = 0; } lastTime = millis();

if (DEBUG_ACTIVE) { Serial.begin(9600); }

}

void loop() { sensorRunningAverage = getSensorRunningAverage(analogRead(PIN_SENSOR)); dis = SharpIR.distance(); // this returns the distance to the object you're measuring

/*How long since we last calculated*/ unsigned long now = millis(); double timeChange = (double)(now - lastTime); lastTime = now;

if (dis >= sensorMax) { error = 0; sumError = 0; diffError = 0;

standbyTime = millis() + 2000; } else if (standbyTime < now) { error = dis - setpoint; sumError += (error * (timeChange / 1000)); diffError = error - oldError; oldError = error; }

if (sampleTime + runningTime < now) { if (!(error <= 1 && error >= -1 && servoOutput == 26 && diffError <=0.5 && diffError >=-0.5)) { //tweaking of the regulator so that it stands still if the ball is within +-1 Cm. u = (Kp * error) + (Ki * sumError) + (Kd * diffError); } servoOutput = constrain(-u + 26, 0, 65); servo.write(servoOutput);

runningTime = millis(); } if (DEBUG_ACTIVE) { printStatus(); } }

void startup() { for (int i = 75; i >= 15; i--) { servo.write(i);

if ((i / 2 & 1) == 0) { ledPinOn(PIN_LED); } else { ledPinOff(PIN_LED); } delay(50); } }

int getSensorRunningAverage(int sensorValue) { total = total - readings[readIndex]; readings[readIndex] = sensorValue; // read from the sensor: total = total + readings[readIndex]; // add the reading to the total: readIndex = readIndex + 1; // advance to the next position in the array: if (readIndex >= numReadings) { // if we're at the end of the array... readIndex = 0; // ...wrap around to the beginning: } float average = total / numReadings; // calculate the average: return average; }

void printStatus() { Serial.print("Distance: "); Serial.print(dis); Serial.print("\t");

Serial.print("Error: "); Serial.print(error); Serial.print("\t");

Serial.print("Sum error: "); Serial.print(sumError); Serial.print("\t");

Serial.print("Diff error: "); Serial.print(diffError); Serial.print("\t");

Serial.print("u(t): "); Serial.print(u); Serial.print("\t");

Serial.print("Output: "); Serial.println(servoOutput); }

void ledPinOn(int led) { digitalWrite(led, HIGH); }

void ledPinOff(int led) { digitalWrite(led, LOW); }