[January 2022] Due to some experience using the board some software updates were added. As ARDUINO declared usage of the TFT library as "RETIRED" I switched to the Adafruit library. You will find all the updates at the end of the article. And in the attachments you will find the ZIP file of the project. The update also enables you to select probabilities other than 50 per cent.
While there are a many mechanical boards with lots of balls and nails to show how a random process creates a binomial distribution, a computer simulation can run much faster and present better results, and even noiseless.
Just connect your Arduino to the TFT in the usual manner.
/*
Galton board
see also:
https://www.edumedia-sciences.com/de/media/905-galtonbrett
speed select:
wire from A0 to any other Ax.
read the results in each compartment from top to bottom.
*/
#include <TFT.h>
#define cs 10
#define dc 9
#define rst 8
TFT tft = TFT(cs, dc, rst);
int w, h, mx, my, r;
const int N = 13;
long cnt[N];
void setup() {
Serial.begin(115200);
Serial.println(__FILE__);
// speed control:
pinMode(A0, OUTPUT); // GND
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
pinMode(A4, INPUT_PULLUP);
pinMode(A5, INPUT_PULLUP);
tft.begin();
tft.setRotation(2);
tft.background(0);
w = tft.width();
h = tft.height();
mx = w / 2;
r = 1;
tft.drawRect(0, 0, w, h, ST7735_WHITE);
tft.setTextColor(ST7735_GREEN);
tft.setCursor(2, 2);
tft.print("Galton");
for (int i = 0; i < N + 1; i++) {
int i1 = 8 * i;
for (int j = 1; j < i; j++)
tft.drawCircle(mx + 8 * j - 4 * i, i1, r, ST7735_WHITE);
// collecting compartments:
i1 = i1 + 2 * r + 10;
tft.drawLine(i1, 105, i1, h - 2, 12345);
printCnt(i);
}
}
void loop() {
int x = w / 2;
int y = 10;
int p = 0;
tft.drawCircle(x, y, r, ST7735_CYAN);
int dt = getDelay();
for (int i = 1; i < N; i++) {
delay(dt);
tft.fillRect(x - 1, y - 1, 4, 4, 0);
int w = random(2);
x = x - 4 + 8 * w;
y = y + 8;
tft.drawCircle(x, y, r, ST7735_CYAN);
p = p + w;
}
cnt[p]++;
delay(dt);
tft.fillRect(x - 1, y - 1, 4, 4, 0);
printCnt(p);
}
int getDelay() {
if (digitalRead(A1) == 0) return 500;
if (digitalRead(A2) == 0) return 100;
if (digitalRead(A3) == 0) return 50;
if (digitalRead(A4) == 0) return 10;
if (digitalRead(A5) == 0) return 5;
return 0;
}
void printCnt(int i) {
if (i >= N) return;
int x = 14 + 8 * i;
int y = h - 9;
tft.fillRect(x, 105, 5, 53, 0);
long z = cnt[i];
do {
tft.setCursor(x, y);
tft.print(z % 10);
z = z / 10;
y = y - 8;
}
while (z > 0);
}
Use a short wire from A0 to any other Ax to control the speed of the simulation.
Normally, in Galton boards the balls that have fallen through form columns to show the distribution. By printing only the numbers you get kind of a logarithmic behaviour which enables you to perform the experiment for longer hours. To read the results in each compartement, read the figures from top to bottom. The middle one in the picture shown above is 4180. If running without delays and 50 per cent probability, after 85 seconds you will have seen 4096 balls fallen through Galton's board; the figures should be very similar to the Binomial Coefficients for (a+b)^12:
After some more time, results could show like this:
You can compare the results you found with the theory by using an Excel spreadsheet:
The Excel formula entered in C2 is using "=BINOM.DIST(A2,12,0.5,FALSE)*SUM" and is to be copied until C14.
Software UpdatesIn order to ease the maintenance of the program parts of the main program were moved to separate functions. Speed change can be performed at any time. Selection of different probabilities was enabled. When you change the probability, all accumulated data will be reset.
For selection of speed and probability, you will need two jumper cables. At the moment, only five fixed values are supported. In case you want to have probabilities below one per cent, some redesign has to be done.
Also, a help screen was added, in this case, showing a QR code that leads to this Hackster web site by pressing the reset key during presentation of that hint. As the reset key was chosen to do this there was no need to add any hardware to the existing project.
If you want you can decrease the number of rows; increasing hardly will work using this kind of TFT display. You also might want to unbalance single nails giving them a probability other than the other nails. And also you might set a maximum number of balls to a certain value.
In case you decide to make this project a permanent one to use in education it is recommended to bypass the boot loader by uploading the sketch using a second Arduino as ISP. This will eliminate the short delay on power-up. Instructions how to do this can be found easily on the web.
Latest version 5s includes full instructions on the TFT display.
Distribution onlyIf you do not want to observe the board with the nails but only are interested in the results go for this sketch. As soon as the maximum reaches the top of the display, the complete graph is getting rescaled and redrawn.
#include <TFT.h>
#define cs 10
#define dc 9
#define rst 8
TFT tft = TFT(cs, dc, rst);
word G = 0x03E0;
word W = 0xFFFF;
word Y = 0x03FF;
const int N = 128;
int cnt[N];
long total = 0;
int scale = 1;
int w, h, h2, m;
void setup() {
Serial.begin(115200);
Serial.println(__FILE__);
tft.begin();
tft.setRotation(0);
w = tft.width();
h = tft.height();
h2 = h - 1;
m = w / 2;
frame();
for (int x = 0; x <= m; x++) cnt[x] = 0;
}
void loop() {
total++;
int x = m;
for (int y = 0; y < m; y++)
if (random(2)) x--; else x++;
int i = x / 2;
cnt[i]++;
int z = cnt[i] / scale;
if (z < h2) tft.drawPixel(x, h2 - z, Y);
else {
scale = scale * 2;
frame();
for (i = 0; i <= m; i++) {
int y = cnt[i] / scale;
tft.drawFastVLine(2 * i, h2 - y, y, Y);
Serial.println(cnt[i]);
}
}
}
void frame() {
tft.background(0);
tft.drawRect(0, 0, w, h, W);
tft.setTextColor(G);
tft.setCursor(2, 2);
tft.print("Galton scale = ");
tft.print(scale);
}
See the results on this screenshot:
The data are also sent to the Serial monitor.
Comments
Please log in or sign up to comment.