Last weekend I was at the hackathon hosted by NTU called http://intuition.ieeentu.com/. We had decided to make a super ambitious project in this by creating a ping pong playing robot in just 24 hours.

We made this:

Here is a video of it working (Stupid wordpress doesnt embed it!) https://drive.google.com/open?id=0B1qzwqel-rknbWs0MDNRYWhDLW8

This hackathon turned out to be quite tiring, and unfortunately rather poorly executed. We were put into small rooms rather than a large hall, which sort of made me lose the energy which carries over from other people working hard around me. The food also was terrible, and it almost ran out by the time I got to the end of the massive line!

Anyways enough talk about how bad the hackathon was, let me get into how this robot worked.

The first step was being able to track the ball, I covered this before in a tutorial here: https://robotaweek.wordpress.com/2017/07/24/ball-tracking-algorithm-using-opencv/ . The major difference was that I didn’t use Hough’s Transform but rather the find Contour function and plotted an circle around that instead. This seemed to work much better since the camera would see the ball more like a squished ellipse rather than an actual ball. I would upload a picture but forgot to take any 😛

The next step was to find the distance of the ball from the screen using the radius of the ball. To do this we basically pulled out a ruler and measured the radius of the circle created. We then just plotted this on an excel sheet and found an exponential relationship and used that formula to predict the distance from the camera.

Here is the graph we made with the radius on the X and the distance in cm is on the Y. The formula we got was: Y = 114 * e^(-0.016 * x). As you can see the fit isn’t that good, this was because of the jumpiness of the circle we drew around the balls position. However given we only had 24 hours, we just stuck with this!

So now what we have is the coordinates of the ball in 3D space, so now we used this to analyze the trajectory of the ball. This required tons of math, but thankfully we had whiteboards in the room. They looked a bit like this in the end:

It looks so cool I swear, especially given how we did this at 3:30 am!

I will bore you by analyzing the math of it in a later post, but basically using projectile motion and basic physics we calculated the position of the ball of when it will be in the hitting range of the robot arm.

So now I had the position of where the ball will be when the arm hits it, and I just needed to make the arm point the ping pong racket over there at the correct time. To solve this I did the inverse kinematics of the arm. This was basically solving a bit of trigonometry to find the final position of the ball. I will cover this in more depth in a later post too… wanna keep this one rather short :p. But to basically find the angles for the motor that I need to get the racket to where the ball is, I modelled the arm in 2D like this:

What I did was have the robot arm originally be in a base hitting positon where the racket was held backwards, as it received the position of the ball, it moved into the positon as shown by the inverse kinematics above and then it went into a follow through pose. I know that this wasn’t the best solution since the arm didnt have a smooth trajectory as it moved, but in only 24 hours I had no other option. Here is the code for the inverse kinematics of the arm (in Processing):

int nLinks = 3;

int nGripperAngles = 5;

int GripperAngle[] = {0, -45, -90, 45, 90};

int linkStrokeW[] = {28, 18, 12};

int linkColor[] = {#00D000, #0000FF, #FF0000};

int l[] = {0, 100, 100, 80};

int h0 = 180;

int v0 = 360;

int currGripper = 0;

float[] w = new float[nLinks];

float[] z = new float[nLinks];

float[] a = new float[nLinks];

float tw, tz;

float tw0, tz0;

float l12;

float a12;

void setup() {

size(480, 560);

smooth();

w[0] = 0;

z[0] = 0;

tw0=100;

tz0=100;

}

void draw() {

background(240);

checkMouseInMenu(mouseX, mouseY);

drawGripperMenu();

drawAxes();

tw = mouseX – h0;

tz = v0 – mouseY ;

calcP2();

if (l12>l[1]+l[2]){

textAlign(CENTER);

fill(#FF0000);

tw=tw0;

tz=tz0;

calcP2();

}

calcP1();

drawLinks();

tw0=tw;

tz0=tz;

}

void drawAxes(){

strokeWeight(1);

stroke(0);

line(h0, v0, h0+259,v0);

line(h0, v0, h0,v0-259);

}

void checkMouseInMenu(float hin, float vin){

int H = 120;

if((vin>436) && (vin<454)) {

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

if((hin>H-20) && (hin<H+20)) {

currGripper=i;

}

H=H+44;

}

}

}

void drawGripperMenu() {

textAlign(CENTER);

int H = 60;

int V = 424;

fill(0);

H = 120;

V = 450;

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

if(i == currGripper) {

fill(0);

}else {

fill(180);

}

text(GripperAngle[i], H, V);

H = H+44;

}

}

void calcP2(){

w[2]=tw-cos(radians(GripperAngle[currGripper]))*l[3];

z[2]=tz-sin(radians(GripperAngle[currGripper]))*l[3];

l12 = sqrt(sq(w[2])+sq(z[2]));

}

void calcP1(){

a12=atan2(z[2],w[2]);

a[1]=acos((sq(l[1])+sq(l12)-sq(l[2]))/(2*l[1]*l12))+a12;

w[1]=cos(a[1])*l[1];

z[1]=sin(a[1])*l[1];

}

void drawLinks(){

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

strokeWeight(linkStrokeW[i]);

stroke(linkColor[i]);

line(h0+w[i], v0-z[i],h0+w[i+1], v0-z[i+1]);

}

strokeWeight(linkStrokeW[2]);

stroke(linkColor[2]);

line(h0+w[2], v0-z[2],h0+ tw,v0- tz);

fill(0);

strokeWeight(0);

stroke(0);

ellipse(h0+ tw,v0- tz,70,70);

}

In terms of the actual construction of the arm itself, we did have a big challenge in terms of weight. This was because the arm was much heavier than what the base motors could lift. To fix this we had decided to add 2 motors to help handle the load of the base at the last moment. This was not so fun as we were drilling at 4:30 am of the night!

Overall however….. the robot only worked 10 – 15% of the time, but for something built in 24 hours with cheap parts and only a webcam I would say thats pretty good 😛

I am quite proud of what we managed to acheive in such a short time as this was a rather complex problem that went from building an arm from scratch to also hitting a ball tracked from a camera. In improvements to this, I plan to be able to predict the coordinates of the ball better and do this using 2 cameras.