Author Topic: Readable Matrix for Battleship Game  (Read 831 times)

0 Members and 1 Guest are viewing this topic.

Offline TonkoTopic starter

  • Newbie
  • Posts: 2
  • Country: au
Readable Matrix for Battleship Game
« on: March 13, 2025, 11:47:43 am »
Hello smart people. I am stuck I need help.

I am creating a "Battleship" Game that uses custom Pegs that light up to show hits, and the ships themselves have built in LEDs to show hits as well.

It will be running on an Arduino Mega.

When I first came up with the project, after lots of thinking, I landed on using Mono Headphone Jacks with LEDs soldered between sleeve and tip for the Pegs (I also have a prototype that uses DC power jacks in the same way - both work the same way, I might use one for the ships and one for the hit/miss pegs).

Anyway, for the game boards themselves, my original plan was to use a matrix of resistors at each node (soldered across female audio jack or DC jack). The player would plug in the jack, and effectively short the resistor, pulling it low, thus allowing me to "scan" the matrix and know where the peg and/or ships are.

I started with TinkerCad and got a working 3x3 version that did everything I needed it to (place a peg, press 'fire' and if the array of pre-determined ship positions shows that coordinate was occupied, it registers a hit and lights the LED inside the peg).

Check the code below, but put simply, cathode columns set to input_pullup then set each row one at a time to high and do a digitalRead on the columns one at a time, and if it has pulled low (or high depending on the setup) then there is a peg at that intersection)

After the online prototype worked, I moved to hardware and built the same 3x3 prototype. This also worked and gave me the confidence to move forward with the full sized 10x10 grid.

And this is where things fall down.

My oringal matrix used 1k resistors that, at 10x10, all of the extra paths, there it so much leackage, that it only shows very low resistance across each intersection node (about 190ohm, where as my 3x3 matrix of 1K's showed about 555ohm) - This affected the ability to detect pegs. As in, the same pegs did not register at all.

I tried using external pulldowns, pullups and reversing the logic (peg pulls high instead of low). I managed to get a version with a modified Peg with a 68ohm resistor in parallel with the LED to work, but only 1 or 2 pegs would detect. More than than that and it would begin interfere with other pegs and they would not register.

I also tried using the 3rd pin on a TRS audio jack. So when the peg is inserted it physically disconnects the resistor and only flows through peg. But I think this meant I had floating pins and caused inconsistent readings and I could not even get a small scale 3x3 board to work for that method. Even with stronger external pulldown, I was getting some strange results. So I gave that up.

I have also tried putting different combinations of Diodes and resistors inside the peg, in both Parallel and in series - and in combination with external pullups/pulldowns on the matrix, but alas, to no avail. I even managed to create a weird scenario where I was reversing the current at one point- dont ask, I dont know how I did that....

Finally, it hit me! A traditional matrix of LEDs works without these issues, and LEDs are just diodes! So instead of resistors at the intersections, I tried diodes, in series with a resistor - The empty nodes read, High, then when Peg is plugged in (with a smaller resistor with the LED)  it would pull it LOW and I could detect it!

But this is where I have hit yet another wall - I only had enough Schottky Diodes to do a small 2x2 matrix for a test. And at first it seemed to work flawlessly... until I realised it was showing the peg one row 'offset' from its actual position (if the peg was on row 0, it would show row 1, if it was in row 1 it would show row 0) - And even 2 pegs at once in the same column would only show one row no matter what! (I did register 2 pegs at once, as long as they were on different columns, but would still show as offset to the wrong row)

I checked everything to troubleshoot!!! - Solder connections, shorts, diode the right way around, my code, the Array was correct, I had the pins in the right order. Also tried plugging pegs in each point and just individually setting their anode/cathodes to high/low to light them up one by one. It all worked fine! But no matter what, my 'scanning' code says the peg is plugged in on the wrong row! - as if somehow its "passing" the short along to the next row!

Anyway, I am at my wits end - I was sure the Matrix of Diodes would be the answer, but this new quirk is kicking me in the guts.

Things I still want to try:
  • I am going to try scaling up the 10x10 resistor matrix to 4.7k on each node- My calculations (Ok, ChatGPT's calculations) show me that it will be about 900ish ohms once all wired up. And Since my 3x3 with 1k's worked so well, I am hoping the same method with bigger resistors is the answer - its just risky since its takes me SO long to solder 100 DC jacks or Audio jacks into a matrix, and there is no guarantee it will even work
  • The other thing is, I have this odd feeling that the 2x2 diode matrix is just doing something quirky, and that I should at least give it the full 3x3 test to make sure. I just need to buy some more diodes.



I am going to attach pictures and some of my test code for those that are interested.

I know schematics would be helpful, but I dont have them. I can say though that is literally just like a standard LED matrix. All Anodes are rows and all cathodes are columns. The Diode version has a 1k resistor in series so that it goes
Code: [Select]
Anode -> 1k -> diode -> cathode.  But the resistor version is literally just
Code: [Select]
Anode -> 1K -> CathodeAs for the pins, I have tried many versions, but the one I am using the most is an LED and resistor in parallel (I found a combination that can pull the node low and still light the LED) - I have also tried in series, but cant go too high since I need it to be less than the board's resistance.

Oh and if you are wondering, I am handling all these pins with Shift registers for the Anodes (just need high and low) but to be able to read the Cathode columns, they are all going directly to their own Pin on the Arduino - Hence the Mega - ( I need 40 cathode pins - 10 for player 1's target board, 10 for their fleet board, and the same again for player 2)

Specific Questions:
  • If anyone has any thoughts on a different method on how I can not just light up a 10x10 matrix but actually "read" when something changes at a node, then Im open to suggestions...
  • What is up with my 2x2 diode matrix detecting the wrong row?
  • Would just simply going bigger 4.7k resistors work? the 3x3 works so well! Or am I just wasting my time?

Here is a Tinker cad setup of my diode dilemma: https://www.tinkercad.com/things/9lRQKs6wZvs-battleship-rnd

This is a simplified version of some code, I'm not turning on the LEDs here, because I can get that working, its just the scanning that is killing me:
Code: [Select]
// Pin Definitions
const int cathodePins[] = {6,7};  // Columns
const int anodePins[] = {8,9};    // Rows
const int numRows = 2;
const int numCols = 2;

// Stores detected pegs
bool detectedState[numRows][numCols] = {{false}};

void setup() {
  Serial.begin(9600);

  // Initialize all anode pins as OUTPUT and set LOW
  for (int i = 0; i < numRows; i++) {
    pinMode(anodePins[i], OUTPUT);
    digitalWrite(anodePins[i], LOW);
  }

  // Initialize all cathode pins as INPUT_PULLUP
  for (int i = 0; i < numCols; i++) {
    pinMode(cathodePins[i], INPUT_PULLUP);
  }

  Serial.println("Matrix Peg Detection Ready...");
   scanMatrix();
 
}

void loop() {
}

void scanMatrix() {
  Serial.println("Scanning Matrix...");

  for (int row = 0; row < numRows; row++) {
   
    digitalWrite(anodePins[row], HIGH); // Activate the current row for scanning
    delayMicroseconds(200); // Stabilization delay

    Serial.print("Row ");
    Serial.print(row);
    Serial.print(": ");

    // Scan current row
    for (int col = 0; col < numCols; col++) {
      pinMode(cathodePins[col], INPUT_PULLUP); // Ensure it's in pull-up mode
      int pegState = digitalRead(cathodePins[col]);
      detectedState[row][col] = (pegState == HIGH); // Peg detected if HIGH

      // Print the raw read value
      Serial.print(pegState ? "1 " : "0 ");
    }

    Serial.println(); // New line for each row

    // Reset row after scanning
    digitalWrite(anodePins[row], LOW);
  }

  Serial.println("Scan Complete!\n");
}




« Last Edit: March 13, 2025, 12:13:40 pm by Tonko »
 

Offline TonkoTopic starter

  • Newbie
  • Posts: 2
  • Country: au
Re: Readable Matrix for Battleship Game
« Reply #1 on: March 13, 2025, 01:25:12 pm »
Oh. My. God.

Why Am I connecting them at all???????

In a button matrix.... the nodes are just not connected till you press a button.... this "shorts" the intersection and you can read the signal.... Am I crazy??? Or could it be this simple??? No resistors, no diodes... just empty space till the plug is inserted???

I need to go to bed. Will test tomorrow!
 

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 6111
  • Country: nl
Re: Readable Matrix for Battleship Game
« Reply #2 on: March 13, 2025, 01:37:31 pm »
I did not read your post in full, but I have an idea on how you might get it working.

First of all, most scan matrices work with diodes in series with the keys to avoid cross talk. In your case maybe the LED can be the diode. By keeping the current low it won't noticeably light up but might still be seen by the input as a high versus a low.

Like shown in the attached picture. The cross point in the scan matrix are the connections to your sockets, and the LED is attached to the mating connector. Multiple inserted LED's can be scanned this way. I just picked some resistor values and did not test to see if it will actually work. It is just an idea. It depends on the supply voltage and the LED forward voltage if the high will actually be a high.

To make the LED's light up the scanning has to stop and additional connections need to be used to up the current through the LED. A second matrix with a high side drive and a low side sink can be used for this. In the high side drive incorporate the resistor to limit the LED current. See the second picture. Depending on the MCU or IO extenders used, the LED sink lines and scan_in lines could be combined. During scanning set them up as inputs, and when needed switch them to outputs that are set low.

Since it is a game and not a keyboard the inserting and removing of the peg's or boats won't be that fast, so the matrix scanning can be slow.

Offline PCB.Wiz

  • Super Contributor
  • ***
  • Posts: 3370
  • Country: au
Re: Readable Matrix for Battleship Game
« Reply #3 on: March 13, 2025, 07:07:35 pm »
Quote
Specific Questions:
* If anyone has any thoughts on a different method on how I can not just light up a 10x10 matrix but actually "read" when something changes at a node, then Im open to suggestions...
* Would just simply going bigger 4.7k resistors work? the 3x3 works so well! Or am I just wasting my time?

You are wasting your time with simple resistors, and shorts.

I think the best approach is to use LED inserts everywhere, and scan them with variable current Linear LED drivers.
You use very low current on the read-only nodes, to just dimly light the LED, and that can verify to the user they have electrical contact.
For hits, you allocate a higher current setting, and the LED is very bright.

In hardware you need 10x Current settable LED drivers, and 10x ADCs to read their current, and 10x MUX switches.

In overall design, it may be simpler to make 4 identical 10x10 boards, with a MCU on each, and have a master/slave switch and link, them serially.
Much easier to repair and wire.

Addit: You can get smarter LED drivers with analog current setting and LED fault readback, but they come in QFN type packages, and have complex register setups.

For simpler design, you may be able to avoid the ADC this way:

Use a cheap, generic LED 16ch Linear sink driver with a common RSET (all LEDs are the same) and a two stage scan
1) Set to a low drive current, and drive all LEDs on
2) use 2 x 74HCT165/ HCT597 (etc) Parallel in shift registers to read-back the LED driver, after few us settling time. Typically 1.2-1.4 Vth
3) HI is LED present, LOW is no LED/Peg
4) Set Driver to HIGH current, and set scoring LEDs to ON, this is normal display MUX eg 1ms ON per column scan.
 

High side drivers for the other axis are less common, but you can use another low cost sink driver and PNP's/Resistors as simple current mirrors.
« Last Edit: March 14, 2025, 04:49:13 am by PCB.Wiz »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

-->