Hackers – Connect 4 Mechanical Design

This week we looked at the mechanical design for our Connect 4 robot. We need a way to hold the tokens and drop one into a slot when the game-playing AI decides what to play.
We started with two ideas for holding the tokens:

  1. A vertical magazine with 21 tokens held in place by two pins.
  2. A disc holding the tokens at the edge.

The photo below shows an illustration of the magazine idea.

magazine3

The magazine would move across the board and drop a token into a slot by pulling out the lower pin. The upper pin would hold the rest of the tokens in place so that the wouldn’t drop into the board. Once the bottom token was dropped, the lower pin would be pushed back and the upper pin pulled out to allow the tokens to drop down one step.

The disc idea involved it rotating into place over the board and dropping a token into the board as needed.

We decided that both ideas were impractical on size grounds: the magazine and disc would be very high and hard to support.

We eventually settled on a modification of the magazine idea: 3 magazines with 7 tokens each. This would be smaller and more stable. It does require us to keep track of the number of tokens in each magazine. That’s something our code should be able to manage.

We decided to keep the position of the magazines fixed. A carrier (think cup) could move under the magazine, collect a token and drop it into the board. The magazine and carrier would both need a single pin at the bottom to hold the tokens in place. The carrier should be the height of a single token, so that only one can drop into it. The carrier would have an arm (like a handle) that sits on the magazine side and holds the other tokens in position.

We spent some time discussing how to move the pins in and out before one ninja had a great idea: the pin should be the arm of a servo motor. The servo can rotate the arm through 90° to allow a token to drop.

We then considered how to move the carrier back and forth. We settled on having a single stepper motor drive a gear on a rack that holds the carrier. Turning the gear moves the rack and the carrier into position. Keeping track of the carrier position might be difficult. The easiest way would be to measure the time it takes to reach a particular slot and then power the motor for that amount of time. The problem with that is that it depends on the motor always taking the same amount of time to reach a slot. The motor might slow down as the battery driving it runs down. Mentor Declan suggested using a beam sensor to locate the correct position. We could put a marker above each board position and stop the motor when the sensor reaches the marker. That marker could be something as simple as a small hole. If the beam shines through the hole instead of reflecting, the mark has been found.

Lastly, we considered how to hold everything in place. We think that a large piece of plywood should do the job. We can also attach a sheet of paper to the plywood behind the board to help the vision system see the empty slots. Mentor Kevin pointed out that anything in the background of the board with the same colour as the tokens could confuse the vision system.

The photo below shows a sketch of the final design.

final_design

So, where will the parts from our design come from?
We have an old flatbed scanner that we can scavenge parts from. It has a gear and rack system to move the scan head. It should be long enough to meet our needs. We haven’t looked at the motor that drives the gear yet. We will have to figure out if we can power it and control it. If not, we have motors from previous projects that we can use. The gear probably won’t fit one of the old motors, so we will have to modify it. Or, we can 3D-print a part that will allow us to fit the gear to the motor. That worked well for us last year when we made axles to allow us fit wheels to the motors we had for our hide and seek robots.
We will have to 3D-print the carrier. It will probably take a few iterations to get something that works. It will need to be the right size to hold only one token, and be shaped to stop tokens from dropping lightly and getting wedged. Some experimentation will be needed. We can 3D-print the magazines as well, or maybe make something from plywood strips and cardboard.
We will also need to make a camera mount for our vision system. The mount will need to sit in front of the board, out of the way of the human player. It will need to be in a fixed position so that it covers the whole board and allows us to reliably identify token positions. This will probably be a mix of a 3D-printed part and plywood.
We will tackle these tasks at our next session.

Hackers – Programming in Python

CoderDojo-Hackers-IntroToPython

As we plan our AI robot to play Connect-4, we have decided that Python would be a good programming language for the job, as it is widely used for many of the tasks we will need to do:

  • Computer vision
  • Artificial intelligence
  • Hardware control

Therefore, we spent time this week brushing up on Python. Following the same approach that we had used previously to move from Scratch to C, we looked at how we would move from programming in Scratch to Python.

Here is the full set of notes (PDF): CoderDojo-Hackers-IntroToPython

Kevin then spent time explaining how to write a basic Python program to read an image from a webcam. Here is the code:


# We are using OpenCV
import cv2

# Capture webcam image
camera=cv2.VideoCapture(0)
val, img = camera.read()

# Display the image
cv2.imshow("Window display", img)

# Stop using the camera
camera.release

Brainstorming a new Hackers project – an AI robot to play Connect-4

conn4

The Goal

In this session, we started planning how we will build an intelligent robot that can play the game of Connect-4. Our aim is that it will be like playing against a human, with a physical Connect-4 set, not just a computer game. This is the plan we had come up with during our brainstorming the previous week, so this week we started to figure out how we can achieve this.

This will be a challenging project that the whole group will work on together. It will require lots of teamwork, collaboration, and learning.

C4-MainPlans

The Major Components

We spent time thinking about the major components that our system will need, and planning the major tasks for these components on the whiteboard. They will include:

  1. A robot mechanism to play a move, which will involve moving to one of the positions 1-7 at the top of the board and dropping in a token, then reloading for the next time.
  2.  A camera to view the board and analyse what it sees, to figure out which spaces have a red token, which have a yellow token, which are free, and whether anyone has won (4 in a row) or has a promising state (one or more 3-in-a-row).
  3. An AI decision-making system (see below)
  4. A software version of the game that we will find online and modify so that our AI can play it, so that we can work on the AI before the physical robot is ready.

For each component, we identified some major tasks and people volunteered to work on 2 major components each.

We also agreed that Python is a good programming language for the task, so we will have to brush up on Python next.

C4-AI

The Artificial Intelligence

The group spent some time playing rounds of Connect-4 against each other, in order to get us thinking about how we would design a computer strategy to play the game. Then we returned to the whiteboard, where people gave their ideas about the main strategies to be followed – these are on the right side of the whiteboard.

Some of the strategy ideas people proposed:

  • Work towards 4 in a row (obvious but important!)
  • recognise states with the potential for 4 in a row
  • have multiple paths to win
  • try to block your opponent.

This made me think of a general AI algorithm for playing 2-person games, called the Minimax Algorithm. This is based on constructing a game tree of all possible future moves, by yourself and by your opponent, for a number of steps into the future (called the lookahead or depth limit). Then, we evaluate all possible future game states using a utility function (also called fitness function): this will return a low value (e.g. -20) if we lose, a high value (20) if we win, or some other intermediate score if the game is not over, such as a count of the number of 3-in-a-rows we have, minus the count of our opponent’s (this will definitely be between 20 and -20). We will then pick the move that should lead to us a state with as high a utility as possible. Also, if we assume our opponent is rational, they will pick the move that will give us as low a utility as possible, so we can use the game tree to predict what their best possible move is, and be prepared for them! Each time they take a move, we can re-calculate the game tree to plan a new best move.

We then looked at the strategy ideas people had proposed, and saw how they are achieved by the Minimax algorithm, even though it’s a general algorithm, not just for Connect-4!

There are some good videos and tutorials about the minimax algorithm on line. Here are two that I liked:

 

SketchUp in a Can

This week we modelled a soft-drinks can in SketchUp.  A typical can is 135mm high and has a diameter of 66mm.
We made the model in two halves with overlapping edges that can be pushed together.
This model could be 3D-printed and used to hold components for one of our electronics projects.  It gave us a feel for using SketchUp and designing our own models.

We drew a profile of one half of a can and extruded that profile around a circle to make the can. We included a lip on the inside of the shell in the profile. The detailed instructions to make the model are here.
One thing we discovered was that we need to delete the face in the circle, leaving just the outline, before extruding.  If you leave the face intact, the extruded model will be missing its bottom face.

Then we made a profile of the other half, with a lip on the outside.  We put the two together in SketchUp to see how they fitted.  Section planes are helpful for this: insert a  section in the vertical plane and move it in and out using the Move tool to see that the lips touch, but don’t overlap.

One ninja had a great idea:  SketchUp allows us to apply materials to faces.  So, he applied a glass texture to the model so that he could see through it and check that it was correct.

The method of drawing the profile in the instructions above is quite laborious.  The intention is to give us an understanding of SketchUp’s inferencing system for drawing in a particular plane and snapping to end-points and mid-points.  Our ninjas were able to construct the profile much quicker by drawing two touching rectangles, and then removing a section (to make the lip) with a third rectangle.

Next week, hopefully, we will try printing our models on the 3D printer to see how they look.  Our 3D printer software needs a file in STL format to print.  SketchUp doesn’t support STL out of the box. There is an extension in the 3D Warehouse that lets us export our model to STL, so we have to install that first.

Hackers – Components of a Desktop PC and a Raspberry Pi

pc+pi

At CoderDojo Athenry, the Hackers spent some time examining the components of a desktop PC and a Raspberry Pi 3+ and a Raspberry Pi Zero.

Even though the Pis are much smaller than a desktop PC, they are functionally equivalent – as we saw, you can plug the Pi into the keyboard, mouse and screen of the desktop PC and use it like one.

We identified the major components of a desktop PC, and saw where each of them appear on the Raspberry Pi also:

  • CPU – the central processing unit that does all calculations and processing. All data in a PC gets represented as numbers, so all data processing ends up as calculations.
  • GPU – a dedicated processing unit just for graphics, that specialises in multiplying and adding matrices (pixels on a screen are represented as a matrix). Not all PCs have one, but they are important for high-performance graphics.
  • RAM – the short-term memory of the computer, used by the CPU to store data.
  • Hard Drive – this might be a hard disk drive or a solid-state drive. This is for long-term storage. It holds much more than RAM and the data remains when the PC is powered off, but it is much slower for the CPU to get data from the hard drive than from RAM.
  • DVD Drive – not all PCs have this. DVDs or CDs allow permanent storage that can be removed. Some are read-only and some allow reading and writing.
  • Motherboard – the circuit board on which everything else is mounted.
  • Power Supply – this is built into a desktop PC. For a Pi, this is a 5-volt supply such as a phone charger.
  • Networking – ethernet for wired networks and/or wifi for wireless networks.
  • Controller chips and connection ports (such USB and HDMI) for peripherals.
  • Case – Pis don’t always have these.

We noted that the Pi has a single chip that has its CPU, a basic GPU and up to 1GB of RAM all stacked in layers on top of each other. While its CPU is lower power than a standard PC CPU, it benefits from having a really short distance that data has to travel from RAM to CPU. CPUs run so fast that having electrons travel a few centimetres is a significant delay!

PCs and the Pi also have connections for peripherals, which is anything that can be connected to it, using USB, Bluetooth, HDMI, or other connection types:

  • Keyboard and mouse
  • Screen

The Raspberry Pi Zero has micro-USB and micro-HDMI connectors to keep everything as small as possible, and it has wifi only, no ethernet port (though it is possible to get a micro-USB to ethernet adapter).

A couple of members of the group have built their own desktop PCs, which is an impressive feat!

Hackers – Soldering LED Circuits

At Hackers this week, we learned how to solder. Group members stripped wires and then soldered them together, and they made LED circuits by soldering them onto stripboard, and tested them with Arduino programs.

As we discussed, it is important to build your circuits temporarily with a breadboard (where you just push the wires in, and can easily move them) before moving onto soldering them on to stripboard. Stripboard (also called Veroboard) has holes every 2.5mm in a grid, and has copper strips on one side connecting the holes in one direction. You mount the component (such as an LED on the side with no copper, and solder its pins to the copper strip. Then, you can solder a pin of a different component somewhere else along the same copper strip, and current can flow through the copper strip.

There are plenty of videos on YouTube  to demonstrate soldering technique. Here is one by Emer Cahill of GMIT:

Hackers – Getting started with Python programming on Arduino

circuit2

In the past two weeks in the Hackers group at CoderDojo Athenry, we have started Python programming on the Raspberry Pi.

The Pi is about the same size as the Arduino that we used earlier, and the Pi Zero is about the size of the Arduino Nano, and both Pi and Arduino have input/output pins for physical computing. However, they have significant differences.

Unlike the Arduino which is a microcontroller (which means it is designed to run a single program that was uploaded onto it), the Raspberry Pi has a full computer operating system, so it is more like a PC to use. It can be programmed in many languages, but Python is a popular choice as it is clear to read and there are lots of libraries to make tasks easier. Because it’s a full computer, you can write and run your programs all on the Pi, without connecting it to a laptop.

The first step in programming is to figure out how to do loops, variables and decisions, as these are fundamental. Here is our first Python program to try out these:

# Python comments start with #

age = 14 # a variable holding an int
name = "Michael" # variable holding a string

# Output
print ("My name is", name, "and my age is ", age)

# Loop
for x in range (1, 5):
    print ("This is line ", x)

# Decision
if (age  17):
    print("Adult")
else:
    print("Teenager")

Next we moved on to using the GPIOZero libraries for controlling lights and buttons. We will continue to explore this in the coming weeks.

The documentation is here: https://gpiozero.readthedocs.io/en/stable/

 

Hackers – Distance Sensor

Some of our Hackers have projects of their own that they are working on, to possibly submit to BT Young Scientists or elsewhere. Last Saturday, those people were focused on working on their own project, with occasional help from peers or mentors where needed.

Those who were not working on their own projects extended last week’s Arduino project to add an ultrasonic distance sensor, replacing the variable resistor that they used last week.

Ultrasonic distance sensors are interesting: like sonar in a submarine or how bats navigate, they send out a short sound pulse (ultrasonic – too high for humans to hear) and then see how long it takes for an echo to come back. Since the speed of sound in air is known, we can calculate the distance to the nearest object based on the time for the round trip.

Here is a good tutorial on how it works: https://howtomechatronics.com/tutorials/arduino/ultrasonic-sensor-hc-sr04/

Above is a circuit designed by mentor Kevin for an ultrasonic distance sensor and a buzzer, to work like a car parking sensor that beeps faster as you get closer to an obstacle.

Below is Kevin’s Arduino program to control the distance sensor and print out the distance. Some people in the group modified this to use buzzers, others turned on 1, 2 or 3 LEDs depending on distance. #

const int triggerPin = 12;
const int echoPin = 10;

// The speed of sound in air at standard temperature and pressure is 343m/s.
// The range of the sensor is 4m.  It takes 2*4/343 seconds for an ultrasonic
// pulse to travel that far and back.
// We'll use that as a timeout later.  There's no point in waiting any longer
// than the time it takes to read an object at the maximum range of the sensor.
unsigned long echo_timeout = 2*4000000/343;

void setup() {
 Serial.begin(9600);
 pinMode(triggerPin, OUTPUT);
 pinMode(echoPin, INPUT);
 pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  unsigned long duration;
  float distance;

  // Begin by resetting the distance sensor 
  digitalWrite(triggerPin, LOW);
  delayMicroseconds(2);
  // Write out a short pulse for 10 microseconds
  digitalWrite(triggerPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggerPin, LOW);
  
  // pulseIn will wait for the input on echoPin to go HIGH.  Then it will
  // time how long it takes to go LOW.
  // The duration in microseconds is returned.
  // We'll wait, at most, echo_timeout microseconds for a pulse. 
  duration = pulseIn(echoPin, HIGH, echo_timeout);
  Serial.print("duration = ");
  Serial.print(duration);
  Serial.print(" microseconds;  ");
  
  // Convert duration to distance. Note decimal point here, needed to get floating point calculation.
  distance = duration * 343.0 / 1000 / 2;
  Serial.print("distance = ");
  Serial.print(distance);
  Serial.println(" mm");
}

Hackers – Basic Arduino inputs and outputs

Rheostat_bb

This week in the Hackers group at CoderDojo Athenry, we built on last week’s work on blinky lights, in which we made a simple circuit involving LEDs and resistors connected to an Arduino, and wrote code to get the LEDs to blink.

An LED is an example of an output from our microcontroller. We would also like to have inputs. Examples of circuit inputs are:

  • Switches
  • Dials
  • Sensors that measure something

We focused on dials, specifically a variable resistor or rheostat. This is the kind of knob or dial you find on dimmer switches, volume controls on old radios, electric guitars, and many others.

A variable resistor has 3 connectors: the two outer ones connect across a voltage source (e.g. 5V and ground pins on the Ardiuno) and the voltage at the middle pin can be adjusted from 0 to 5V by turning the knob.

We connected the middle pin of the variable resistor to Analog input 2 of the Arduino. The connections are shown above.

Then, the code to read its value is:

potValue = analogRead(potPin);

where potValue and potPin are ints that were defined already.

The value that you get is in the range 0-1024, and changes as you turn the dial.

Here is a full Arduino program to read a value and display it on the Serial Monitor window if you have a computer connected to your Arduino:

int potPin = 2;    // select the input pin for the potentiometer
int potValue = 0;  // value to read from potentiometer

void setup() {
  Serial.begin(9600);  // need for print commands later
}

void loop() {
  potValue = analogRead(potPin);    // read the value from the sensor
  Serial.println(potValue);
}

In the group, we used this as the basis to improve last week’s program. This time, the speed at which the LED blinks is controlled by turning the potentiometer dial.

The previous code to control how long the LED blinks for was:

delay(one_second);

We changed this to:

delay(potValue);

Of course, we also had to add the code to read the potentiometer value at the top of the loop() function.

Hackers – blinky lights

Today we built our first circuits on a breadboard.

A breadboard is used to try out electronic circuits and figure out what works.  Once we are happy with a circuit we can make a permanent version on something like strip-board.

Breadboards have blue and red lines across the top and bottom.  A wire strip runs across the board under each line.  If we connect a power source to any point on the lines, all of the points (holes) on the line receive the power.

The middle area of the board has wire strips running vertically.  A wire strip runs down the board under each line of holes.  If we connect a power source to any point on the lines, all of the points (holes) above or below receive power.

The first circuit was one to power a single LED:

circuit01_bb.png
We used the Arduino here as a simple 5V battery.  Current flows from the 5V pin on the Arduino, through the resistor, then the LED, and on to the GND pin on the Arduino.  We should always used a resistor with an LED to protect it.  It doesn’t take much current to damage an LED.

This has the LED on permanently – not very exciting, but good to get started with.  It’s a good idea to start with a minimal circuit and build up to the more complicated circuit we actually want.  That way, we can test and verify as we go, so that we don’t have too much testing and backtracking to do if something goes wrong.

It took a while to get everyone’s circuit working.  Some of the LEDs had legs that were the same length, and there was no obvious way to see which one was the anode or cathode, so we had to guess and test.
Some of the resistors we took at random from the box were too high:  200 kΩ, for example, so the LEDs wouldn’t light up.  We found some 220 Ω (red-red-brown) and 330Ω (orange-orange-brown) resistors to get us going.
Some of the LEDs were very dim.  180 Ω resistors (brown-grey-brown) helped there.
We did a quick calculation to see what value of resistor we really needed:

According to the spec sheet, our LEDs had a forward voltage of 2.2 V and a forward current of 20 mA. In other words, the voltage drop across the LED is 2.2 V, and they can draw up to 0.02 A without burning out.
If our supply is 5 V, then the voltage across the resistor is 5 – 2.2 = 2.8 V.  This is Kirchoff’s Voltage Law.
Applying Ohm’s Law (V = RI), 2.8 = R*0.02, so R = 2.8/0.02 = 140 Ω.
A 140 Ω resistor will make our LED as bright as possible. Less than that will burn out the LED. More than that will produce a dimmer light. So, 180, 220, and 330 Ω are all fine.
Different LEDs have different forward voltages and currents, so it’s important to keep and consult the specification sheets before using them.

The next step in our circuit building was to connect the Arduino’s ground pin to the ground rail on the breadboard.  Then we connected the negative (cathode) pin of the LED to the ground rail.  This is an important step in circuit building:  using a common ground for all our circuits on one board.  It allows us to only have one wire running back to the Arduino ground, instead of one for each circuit.  We would run out of space on the Arduino very quickly otherwise.
Next we did the same on the positive side. This isn’t necessarily as useful as the common ground as we’ll see later.

Once we were happy that we all had a working circuit, we moved on to use the Arduino to control the LED.
We did this by taking the wire that went to the 5V pin on the Arduino and plugging it into digital pin 12 instead.  We went back to our Arduino sketches and defined a new integer variable, ledPin, and gave it a value of 12 to match where we plugged it in.
Then we changed every occurrence of LED_BUILTIN in our sketches from last week to ledPin instead.  The Find (Replace with) function on the Edit menu of the IDE was helpful here.

Once we compiled the sketch and uploaded it to the Arduino, we had the LED on
the breadboard blinking our messages, just like the internal LED was last week.

Next, we added a second LED and resistor to the board, and wired it up the same as the first.  The positive side of the resistor was connected to the positive power rail, and from there on to the Arduino. Now both LEDs blinked together.
To get them to blink separately, we took the wire from our second LED going to the positive rail and plugged it into digital pin 8 on the Arduino.

circuit06_bb.png

Then we created a new variable in our sketch, led2Pin, with a value of 8.
We added setup code for pin 8.  Finally, we added two more lines to the loop, to have the output to LED 2 go low after LED 1 was set high, and vice versa.
The outcome was LED 2 was on when LED 1 was off and LED 2 was off when LED 1 was on.
Some demonstration code is shown below.

// Blink 2 LEDs: one on, one off
// Demonstration for CoderDojo Athenry

int led1Pin = 12;
int led2Pin = 8;

int one_second = 1000;  // delay() function expects milliseconds

void setup() {
  pinMode(led1Pin, OUTPUT);
  pinMode(led1Pin, OUTPUT);
}

void loop() {
  digitalWrite(led1Pin, HIGH);  // on
  digitalWrite(led2Pin, LOW);
  delay(one_second);
  digitalWrite(led1Pin, LOW);  // off
  digitalWrite(led2Pin, HIGH);
  delay(one_second);
}