NoNoWood

by lotteHelmer in Circuits > Arduino

142 Views, 0 Favorites, 0 Comments

NoNoWood

20230512_113844.jpg
arduinoo.png

a wooden interactive picross puzzle board, made for a school assignment.

Supplies

Supplies for the Arduino


  • Arduino Mega
  • USB B to USB A Cable
  • A laptop or computer that can run unity, and has an open USB A slot
  • Copper tape width, anywhere between 2.5 cm and 5 cm. And for the length 3 or more meter
  • 100 * 25 cm Male to Male jumper cables. I recommend getting 100 or more male to male, as you'll be using more than 50, and some are bound to break.
  • A breadboard
  • Electrical wire, I used 1.5mm by 50 meters
  • Perf board for PCB



Supplies for soldering


  • Solder Station
  • Iron stand
  • Solder tin
  • Solder Sponge
  • wire strippers


Supplies for the casing

Disclaimer : I used what was mainly scrap wood but you will need


  • 2* Wooden plate 30 cm by 30 cm by 0,5 cm
  • 33 * Wooden block 5 cm by 5 cm by 2.5 cm
  • Wood glue, or a hot glue gun

Wooden sticks 5 mm by 5 mm by:

  • 30 cm (4x)
  • 28 cm (8x)
  • 5 cm (20x)


Optional is 2x 100M yarn for a 5mm hook to crochet around the project, I used 2 different colours. A 5mm crochet hook and a pair of scissors.


Software


  • Unity
  • Arduino IDE

The Concept

For this project we were given an assignment to make something using an Arduino.


I thought it would be fun to make something that's rather nostalgic for me. So, I wanted to make a picross like puzzle as I used to always make those in analog booklets with my mom when I was a kid. And considering I went on a trip down memory lane I decided to make this with a wooden board, like the wooden toys I used to have, that you could connect with unity. Giving you a possibility to make levels in unity and play them out with a wooden set.

The reason I chose unity was because this is a game engine that is most familiar to me, and an engine with many tutorials online.

and thus my main concept became a wooden interactive picross puzzle board.

The Wooden Board

wood1.jpg
wood2.jpg
board.jpg

For the casing make sure to gather all the correct sized wood pieces


  • 1* Wooden plate 30 cm by 30 cm by 0,5 cm
  • 33 * Wooden block 5 cm by 5 cm by 2.5 cm
  • Wood glue, or a hot glue gun

Wooden sticks 5 mm by 5 mm by:

  • 30 cm (4x)
  • 28 cm (8x)
  • 5 cm (20x)



First you'll want to drill holes into the wooden plate as to where the cables will go to the top of the board.

Horizontally, start with 3,5 from the edge and then every 6cm

Vertically, 2cm from the edge, then 4, then 2 again until you reach the end.


After this you simply assemble the board and sticks with glue.

The longest 2 sticks are for the left and right edge of the top part of the plate and the bottom

2 of the 28cm sticks are for the other 2 edges on the bottom.

the other 6 will be used on the top, 2 for the outer edges that are left and the other 4 every 6 centimeters from the top/bottom edge.

the small sticks are for between the spaces created behind the 28 centimeter sticks, every 6 centimeters from the left/right to create a grid pattern.

This creates a board with blocks that you can already use to play the puzzle, however we want to make this partially digital.

Adding Cables

20230424_120847.jpg
rn_image_picker_lib_temp_d6cb8b8a-92d8-48b9-b461-dd8b692de04b.jpg
soldertop.jpg

My sizing for the 1.5mm wiring was rather chaotic, so I recommend cutting the wire 4cm long for 50 times, and stripping both the ends so the cable is a bit more exposed, we will later need this during the soldering. I glued all these cables on the bottom of the board, and made sure that the cable and the top of the board were on the same level.


After the glue has dried well, add 2 blocks per corner, parallel to the board to heighten the board. One vertically and one on the bottom horizontally for a stable base. This way the cables have the space they need and we can start soldering.


For the top of the board we want to make sure that the copper is heated and then place a droplet of tin on top, make sure this droplet is bigger than the hole so that is will be stuck on top and cover enough area for the block to touch once we add the copper tape. Solder all 50 wires on top.

Making the Blocks.

blockk.jpg
image.png

I used copper tape that wasn't made for electrical prototypes but was marketed as a snail repellent tape. The entire bottom was covered with glue and didn't conduct electricity so after testing my first overlapping pattern it didn't conduct. so I decided to have a wide strip of tape on the bottom. and after testing this with 2 jumper cables in my Arduino it worked and showed me a difference in current after connecting and disconnecting.


for this step you will have to grab 25 blocks and add a strip of copper tape in the middle, make sure it goes from one side of the bottom of a block to the other side (5 cm long).

Adding the Wires in the Arduino

20230511_130707.jpg
20230508_175244.jpg
image.png

For the analog pins this is rather simple, you will need to make sure that you have one side of each grid on the top connected to the ground, and the other connected to the pin. You can follow the image for visualized instruction. do this for 15 of the analog pins available in the Arduino mega.


Sadly the Arduino Mega doesn't contain 25 analog pins so the remaining ten will have to be connected via a pull up resistor. This is something that didn't come to mind when I first started to use all the pins, and I did the same for the digital pins as I did for the analog. However if a digital pin isn't connected with a circuit it will give you a random variable.


Lucky for us, the Arduino comes with a built in pull-up resistor that we can use. Simply follow the Tinkercad image for all of the 25 pins. I myself used 15 analog pins and 10 digital pins. (The pushbuttons here are to symbolize our 'block sensor'.)


To connect the jumper cables and the electrical wires, simply cut and then strip the jumper cable, and then solder them together. See if you can give it a small tug to check if it is sturdy, however if you are confident in your soldering you can skip this.

I also glued my Arduino to the bottom of the board with the USB port just over the border.

Programming (Arduino IDE)

The code that I sent to my Arduino


void setup()
{
  //sets serial port for communication
  Serial.begin(9600);
  //This makes sure that we use the internal PULLUP resistors.
  pinMode(44,INPUT_PULLUP);
  pinMode(22,INPUT_PULLUP);
  pinMode(24,INPUT_PULLUP);
  pinMode(43,INPUT_PULLUP);
  pinMode(52,INPUT_PULLUP);
  pinMode(45,INPUT_PULLUP);
  pinMode(47,INPUT_PULLUP);
  pinMode(49,INPUT_PULLUP);
  pinMode(51,INPUT_PULLUP);
  pinMode(53,INPUT_PULLUP);
}

void loop()
{
 //reading the pins
  int value1 = analogRead(A0); //A5
  int value2 = analogRead(A1); //B5
  int value3 = analogRead(A2); //C5
  int value4 = analogRead(A3); //D5
  int value5 = analogRead(A4); //E5
  int value6 = analogRead(A6); //B4
  int value7 = analogRead(A7); //D4
  int value8 = analogRead(A8); //B1
  int value9 = analogRead(A9); //A3
  int value10 = analogRead(A10); //E4
  int value11 = analogRead(A11); //D2
  int value12 = analogRead(A12); //C3
  int value13 = analogRead(A13); //E2
  int value14 = analogRead(A14); //C4
  int value15 = analogRead(A15); //C2

  int value16 = digitalRead(44); //E1
  int value17 = digitalRead(22); //A4
  int value18 = digitalRead(24); //A2
  int value19 = digitalRead(43); //A1
  int value20 = digitalRead(52); //E3
  int value21 = digitalRead(45); //D3
  int value22 = digitalRead(47); //C1
  int value23 = digitalRead(49); //B2
  int value24 = digitalRead(51); //B3
  int value25 = digitalRead(53); //D1
//This will affect the way it will be imported to unity and how it is printed within arduino IDE Make sure to put them in order of location so that it'll be easier in unity
  String seperatorinside = ":";
  String seperatorOutside = ",\n";

  String everything = "A1" + seperatorinside + value19 + seperatorOutside +
                      "A2" + seperatorinside + value18 + seperatorOutside +
                      "A3" + seperatorinside + value9 + seperatorOutside +
                      "A4" + seperatorinside + value17 + seperatorOutside +
                      "A5" + seperatorinside + value1 + seperatorOutside +
                      "B1" + seperatorinside + value8 + seperatorOutside +
                      "B2" + seperatorinside + value23 + seperatorOutside +
                      "B3" + seperatorinside + value24 + seperatorOutside +
                      "B4" + seperatorinside + value6 + seperatorOutside +
                      "B5" + seperatorinside + value2 + seperatorOutside +
                      "C1" + seperatorinside + value22 + seperatorOutside +
                      "C2" + seperatorinside + value15 + seperatorOutside +
                      "C3" + seperatorinside + value12 + seperatorOutside +
                      "C4" + seperatorinside + value14 + seperatorOutside +
                      "C5" + seperatorinside + value3 + seperatorOutside +
                      "D1" + seperatorinside + value25 + seperatorOutside +
                      "D2" + seperatorinside + value11 + seperatorOutside +
                      "D3" + seperatorinside + value21 + seperatorOutside +
                      "D4" + seperatorinside + value7 + seperatorOutside +
                      "D5" + seperatorinside + value4 + seperatorOutside +
                      "E1" + seperatorinside + value16 + seperatorOutside +
                      "E2" + seperatorinside + value13 + seperatorOutside +
                      "E3" + seperatorinside + value20 + seperatorOutside +
                      "E4" + seperatorinside + value10 + seperatorOutside +
                      "E5" + seperatorinside + value5;
  //The actual printing of the values
  Serial.println(everything);
}

Setting Up in Unity

1.png
2.png
3.png
4.png
5.png
6.png
7.png
8.png
9.png
10.png
11.png
12.png
13.png
14.png

Create a Unity 2D project


The first image displays a list of all gameobjects that I've used.


1 - you will want to place your main camera on X 344 Y 193.6 and Z-10

2 - Create a background, for this you will want to create a square and scale it up (See image for location and scale)

3 - I made an empty game object called grid, within this I made square game objects on a higher sorting level I named grid, and placed all the square game objects to form the grid

4 - Add the numbers, I did this using TextMeshPro game objects font size 36, make sure to have the sorting layer for these above the background

5 - Create a game object for each individual block within the grid using squares, I made a dark red square for the incorrect spots and bright red for the correct spots as I wanted to make a heart puzzle, add these to an even higher sorting level to ensure they get shown on top.

6 - Enter all these Buttons in an empty game object that I called 'buttons' and add the code that is in the following step. Now manually add the buttons into the inputs when you scroll down this code in the unity inspector when the buttons game object is selected.

7 - for the 'win screen' I made a TextMeshPro object and also a square one that I put below for a background. Make sure that the text is on the highest sorting layer and the background for this one layer below so that this will overlap.

Programming (Unity)

The code I used in the unity project.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class SetActive : MonoBehaviour
{
  //public GameObject[] activationObjects;
  //communicating with arduino
  public string portName = "COM7";
  public int baudRate = 9600;

  private SerialPort stream;
  public string[] values;
  public int value;
  //creating a string for every block
  public string[] A1;
  public string[] A2;
  public string[] A3;
  public string[] A4;
  public string[] A5;
  public string[] B1;
  public string[] B2;
  public string[] B3;
  public string[] B4;
  public string[] B5;
  public string[] C1;
  public string[] C2;
  public string[] C3;
  public string[] C4;
  public string[] C5;
  public string[] D1;
  public string[] D2;
  public string[] D3;
  public string[] D4;
  public string[] D5;
  public string[] E1;
  public string[] E2;
  public string[] E3;
  public string[] E4;
  public string[] E5;

  //creating a public gameobject for every block
  public GameObject A1a;
  public GameObject A2a;
  public GameObject A3a;
  public GameObject A4a;
  public GameObject A5a;
  public GameObject B1a;
  public GameObject B2a;
  public GameObject B3a;
  public GameObject B4a;
  public GameObject B5a;
  public GameObject C1a;
  public GameObject C2a;
  public GameObject C3a;
  public GameObject C4a;
  public GameObject C5a;
  public GameObject D1a;
  public GameObject D2a;
  public GameObject D3a;
  public GameObject D4a;
  public GameObject D5a;
  public GameObject E1a;
  public GameObject E2a;
  public GameObject E3a;
  public GameObject E4a;
  public GameObject E5a;
  public GameObject Win;

  void Start()
  {
    //input for arduino data
    stream = new SerialPort(portName, baudRate);
    stream.ReadTimeout = 50;
    stream.Open();
  }

  void Update()
  {
    {
      //checking arduino data
      string arduinoData = stream.ReadLine();
      //making a seperate string for all of the inputs, to be able to check them seperately

      values = arduinoData.Split(',');
      A1 = new string[values.Length];
      A1 = values[0].Split(':');
      A2 = new string[values.Length];
      A2 = values[1].Split(':');
      A3 = new string[values.Length];
      A3 = values[2].Split(':');
      A4 = new string[values.Length];
      A4 = values[3].Split(':');
      A5 = new string[values.Length];
      A5 = values[4].Split(':');
      B1 = new string[values.Length];
      B1 = values[5].Split(':');
      B2 = new string[values.Length];
      B2 = values[6].Split(':');
      B3 = new string[values.Length];
      B3 = values[7].Split(':');
      B4 = new string[values.Length];
      B4 = values[8].Split(':');
      B5 = new string[values.Length];
      B5 = values[9].Split(':');
      C1 = new string[values.Length];
      C1 = values[10].Split(':');
      C2 = new string[values.Length];
      C2 = values[11].Split(':');
      C3 = new string[values.Length];
      C3 = values[12].Split(':');
      C4 = new string[values.Length];
      C4 = values[13].Split(':');
      C5 = new string[values.Length];
      C5 = values[14].Split(':');
      D1 = new string[values.Length];
      D1 = values[15].Split(':');
      D2 = new string[values.Length];
      D2 = values[16].Split(':');
      D3 = new string[values.Length];
      D3 = values[17].Split(':');
      D4 = new string[values.Length];
      D4 = values[18].Split(':');
      D5 = new string[values.Length];
      D5 = values[19].Split(':');
      E1 = new string[values.Length];
      E1 = values[20].Split(':');
      E2 = new string[values.Length];
      E2 = values[21].Split(':');
      E3 = new string[values.Length];
      E3 = values[22].Split(':');
      E4 = new string[values.Length];
      E4 = values[23].Split(':');
      E5 = new string[values.Length];
      E5 = values[24].Split(':');
      //to set the gameobjects active when the circuit is finished
      if (A1[1] != "0")
      {
        A1a.gameObject.SetActive(false);

      }
      else
      {
        A1a.gameObject.SetActive(true);
      }
      if (A2[1] != "0")
      {
        A2a.gameObject.SetActive(false);

      }
      else
      {
        A2a.gameObject.SetActive(true);
      }
      if (A3[1] != "0")
      {
        A3a.gameObject.SetActive(false);

      }
      else
      {
        A3a.gameObject.SetActive(true);
      }
      if (A4[1] != "0")
      {
        A4a.gameObject.SetActive(false);

      }
      else
      {
        A4a.gameObject.SetActive(true);
      }
      if (A5[1] != "0")
      {
        A5a.gameObject.SetActive(false);

      }
      else
      {
        A5a.gameObject.SetActive(true);
      }
      if (B1[1] != "0")
      {
        B1a.gameObject.SetActive(true);

      }
      else
      {
        B1a.gameObject.SetActive(true);
      }
      if (B2[1] != "0")
      {
        B2a.gameObject.SetActive(false);

      }
      else
      {
        B2a.gameObject.SetActive(true);
      }
      if (B3[1] != "0")
      {
        B3a.gameObject.SetActive(true);

      }
      else
      {
        B4a.gameObject.SetActive(true);
      }
      if (B4[1] != "0")
      {
        B4a.gameObject.SetActive(false);

      }
      else
      {
        B4a.gameObject.SetActive(true);
      }
      if (B5[1] != "0")
      {
        B5a.gameObject.SetActive(false);

      }
      else
      {
        B5a.gameObject.SetActive(true);
      }
      if (C1[1] != "0")
      {
        C1a.gameObject.SetActive(false);

      }
      else
      {
        C1a.gameObject.SetActive(true);
      }
      if (C2[1] != "0")
      {
        C2a.gameObject.SetActive(false);

      }
      else
      {
        C2a.gameObject.SetActive(true);
      }
      if (C3[1] != "0")
      {
        C3a.gameObject.SetActive(false);

      }
      else
      {
        C3a.gameObject.SetActive(true);
      }
      if (C4[1] != "0")
      {
        C4a.gameObject.SetActive(false);

      }
      else
      {
        C4a.gameObject.SetActive(true);
      }
      if (C5[1] != "0")
      {
        C5a.gameObject.SetActive(false);

      }
      else
      {
        C5a.gameObject.SetActive(true);
      }
      if (D1[1] != "0")
      {
        D1a.gameObject.SetActive(false);

      }
      else
      {
        D1a.gameObject.SetActive(true);
      }
      if (D2[1] != "0")
      {
        D2a.gameObject.SetActive(false);

      }
      else
      {
        D2a.gameObject.SetActive(true);
      }
      if (D3[1] != "0")
      {
        D3a.gameObject.SetActive(false);

      }
      else
      {
        D3a.gameObject.SetActive(true);
      }
      if (D3[1] != "0")
      {
        D3a.gameObject.SetActive(false);

      }
      else
      {
        D3a.gameObject.SetActive(true);
      }
      if (D4[1] != "0")
      {
        D4a.gameObject.SetActive(false);

      }
      else
      {
        D4a.gameObject.SetActive(true);
      }
      if (D5[1] != "0")
      {
        D5a.gameObject.SetActive(false);

      }
      else
      {
        D5a.gameObject.SetActive(true);
      }
      if (E1[1] != "0")
      {
        E1a.gameObject.SetActive(false);

      }
      else
      {
        E1a.gameObject.SetActive(true);
      }
      if (E2[1] != "0")
      {
        E2a.gameObject.SetActive(false);

      }
      else
      {
        E2a.gameObject.SetActive(true);
      }
      if (E3[1] != "0")
      {
        E3a.gameObject.SetActive(false);

      }
      else
      {
        E3a.gameObject.SetActive(true);
      }
      if (E4[1] != "0")
      {
        E4a.gameObject.SetActive(false);

      }
      else
      {
        E4a.gameObject.SetActive(true);
      }
      if (E5[1] != "0")
      {
        E5a.gameObject.SetActive(false);

      }
      else
      {
        E5a.gameObject.SetActive(true);
      }
      //WinScreen conditions
      if (A2a.activeInHierarchy & A4a.activeInHierarchy & B1a.activeInHierarchy & B2a.activeInHierarchy & B3a.activeInHierarchy & B4a.activeInHierarchy & B5a.activeInHierarchy & C1a.activeInHierarchy & C2a.activeInHierarchy & C3a.activeInHierarchy & C4a.activeInHierarchy & C5a.activeInHierarchy & D2a.activeInHierarchy & D3a.activeInHierarchy & D4a.activeInHierarchy & E3a.activeInHierarchy)
      {
        if (!A1a.activeInHierarchy & !A3a.activeInHierarchy & !A5a.activeInHierarchy & !D1a.activeInHierarchy & !D5a.activeInHierarchy & !E1a.activeInHierarchy & !E2a.activeInHierarchy & !E4a.activeInHierarchy & !E5a.activeInHierarchy)
        {
          Win.gameObject.SetActive(true);
        }
      }
    }
  }

  void OnApplicationQuit()
  {
    //stop reading when unity playMode isn't active
    if (stream != null && stream.IsOpen)
    {
      stream.Close();
    }
  }
}

Finalizing Casing

All should work properly now, and you can finalize the casing after checking if all the blocks work and cables are soldered properly. You can replace the breadboard with the perf board and close up the bottom using the second wooden plate. I decided to crochet around my project instead of make a wooden casing on the sides for a softer look.


First crochet a chain that is as tall as the board once you've reached that, Chain one flip and Single Crochet until the end, Chain one flip and redo this for as long as you want to, you can switch colours in between for a blocky texture.


To crochet in the part where the USB port comes out, simply Single Crochet the row until the 3 last stitches, chain and turn, single crochet until the end, chain and turn, single crochet until the end, chain and turn, and single crochet until the end, chain 4 and turn and repeat the process that you were doing beforehand. This will create a little gap at the top for the cable to come through.

once it is long enough you can crochet one end to the beginning creating a big loop. I simply covered the project's sides with this big loop and glued the top and bottom to the wooden plates.


Here is a tutorial I found for those new to crochet:

(11) How to Crochet for Absolute Beginners: Part 1 - YouTube

Reflection

During this project I came across a ton of trial and error, mainly with the soldering which I did thrice to make sure it is all connected properly and with the coding within unity. The attached txt file shows an earlier code used which was more optimized but didn't work to the surprise of multiple people. Also the copper tape, and digital pins weren't on my side exactly.


These errors were to my believe the biggest learning points in this project. I've learned a ton about how the Arduino works, and with this a bit about how the hardware I use every single day works. I've also learned how to solder, and measure out and make a wooden casing. but more importantly I've learnt that even if everything seems to be going wrong, it can still work with some creative solutions. and that even though for a first project with an Arduino this was stupidly ambitious, with a ton of willpower and help from others you can still make it work one way or another. or at least most of the time.


I will however next project for sure have more testing moments in-between and start with something smaller, I enjoy the end of this project a lot but the sleepless nights and stress might've been a bit higher than necessary.


However this project inspired me to work more with hardware, as I am really happy with the Game feel and enjoyed making the casing a ton.


For my next project I would like to also work on my documentation, as a lot of my choices are coming from improvisation, or quick iterations when encountering mistakes, I would like to more clearly see where and when I went wrong and how I fixed that for my next project.


I learnt a lot from this, and I think that if you enjoy puzzle games, and wooden toys, this might be worth a try. Especially i f you can avoid the mistakes that I've made.

Downloads

Enjoy!

20230512_113844.jpg
F9RP6YFLHS1M7HF.png

(2) arduino :) - YouTube


Here is a clip of the project in action!