ATTAG – fighting with a diva called S3 Mini

Since the beginning of ATTAG (OSDYLS) I switched the MCU multiple times, from D1 Mini to S2 Mini because I needed more GPIOs and now to S3 Mini. So I collected some experience with these little time eaters.

Let me say one thing at this point, the S3 Mini is a diva. Not sure if it is matter of revision number or of the core cpu or because it is relatively new. However, be prepared for some dramatic behaviour during the programming of it. It loves to block flashing from time to time or ends in boot loops if your code isn’t closely to what it likes. Don’t worry until now I was able to recover any of these, so it isn’t too easy to brick one to death.

  • First of all, make sure the IDE got CDC on boot “enabled” otherwise you won’t see any serial print outputs.
  • If it got stuck in a boot loop you need to reset it with the buttons, sometimes multiple times and/or remove/replug the usb cable. If it still doesn’t like to be flashed go to your console and manually execute the esptool command copied from the IDE output.
  • If it still refuses flashing add –no-stub to the parameters, like this: C:\esptool_py\4.5.1/esptool.exe –no-stub –chip esp32s3 –port COM6 –baud 115200 –before default_reset –after hard_reset write_flash -z –flash_mode dio –flash_freq 80m –flash_size 4MB 0x0 […]

So why the S3 at all if it is so complicated?

Because the D1 and S2 are single core computers, the S3 got two cores and that means one core can be reserved for “listening” to incoming signals. That way the detection of a hit is never interrupted by whatever else happens on the blaster.

So the “eyes” of the blaster will run in the main loop() of the code which is set to core 1 by default, all the trigger/display/ammo/audio will be put on core 0, if everything goes well.

Libs that work with interrupts tend to don’t work well with the IRremote library, such as the WLED control. I need to do some tests to figure that out, however the feedback on the WLED usually just happens when IR detection is not required. Such as hit feedback AFTER hit detection.

Another thing that I stumbled across is the fact that IRremote only allows ONE receiving pin, this makes it more difficult to add multiple hitpoints. There is an old fork of the lib with multiple inputs, I have to check if it works.

So that is the stuff I am currently working on, the Wifi LR / UDP thing is still unresolved, waiting for the guys @espressif to work on it.


A tiny project in between.

I was looking for a way to measure the amps that will hit the sending IR LED of the ATTAG project so I quickly built a small ammeter (amperemeter) with a recording to micro SD feature.

If you choose to build your own you need these parts:

  • 1x D1 mini (any ESP or arduino should do)
  • 1x 0,91 OLED IĀ²C display
  • 1x INA219 IĀ²C module
  • 1x SPI micro SD card module
  • 1x some regular holeboard 70x50mm
  • 1x micro button
AMMETER Ampere Meter

AMMETER Ampere Meter
Ammeter Ampere Meter
AMMETER Fritzing
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Adafruit_INA219.h>
#include <Fonts/FreeMono9pt7b.h>
#include <SPI.h>
#include <SD.h>
#define RECBUTTON 0

File myFile;
unsigned long timestamp;
int currentState;
int rec = 0;

Adafruit_INA219 ina219;

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET     -1

void setup() {
  delay(500); // calm down pause
  while (!Serial) {
  if (!SD.begin(15)) {
    Serial.println("initialization failed!");
  Serial.println("initialization done.");
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  if (! ina219.begin()) {
    Serial.println("INA219 failed");
    while (1) {

void loop() {
  currentState = digitalRead(RECBUTTON);

  if (currentState == LOW && rec == 1) {
    rec = 0;
    Serial.println("recording off");
  } else if (currentState == LOW && rec == 0) {
    rec = 1;
    Serial.println("recording on");
    myFile ="ammeter.txt", FILE_WRITE);

  float shuntvoltage = 0;
  float busvoltage = 0;
  float current_mA = 0;
  float loadvoltage = 0;
  float power_mW = 0;

  shuntvoltage = ina219.getShuntVoltage_mV();
  busvoltage = ina219.getBusVoltage_V();
  current_mA = ina219.getCurrent_mA();
  power_mW = ina219.getPower_mW();
  loadvoltage = busvoltage + (shuntvoltage / 1000);

  delay(200);  // decrease if you want to increase number of recordings per second but display may flicker

  display.setCursor(0, 10);
  display.print("mA:"); display.print(current_mA);
  display.setCursor(0, 23);
  display.print("mW:"); display.print(power_mW);
  display.setCursor(0, 25);

  if (busvoltage < 0) busvoltage = 0;
  if (shuntvoltage < 0) shuntvoltage = 0;
  if (loadvoltage < 0) loadvoltage = 0;

  display.print("VB:"); display.print(busvoltage);
  display.print(" S:"); display.print(shuntvoltage);
  display.print(" L:"); display.print(loadvoltage);

  display.setCursor(100, 0);
  if (rec == 1) {

  if (rec == 1) {
    myFile.print(current_mA * -1);

The code is based on some examples from the adafruit INA219 lib. I just added the display output and the recording feature.

In order to get these 3D printable files working you need some of the 2,54mm 8×1 pin header sockets. Whatever they are called:

3D printable files:

AMMETER printable files

ATTAG – changing the address of an OLED display

In the requirements I mentioned a 128×32 pixel OLED in the optional stuff, if you are planning to use more than one display per blaster you will have to change the address of the 128×64 pixel OLED unless you get a 128×32 pixel OLED with changeable addresses.

This needs a bit more advanced soldering skills with SMD, which I never had to use before. However I succeeded with my first approach even though it looks pretty ugly. šŸ˜‰

Remember this absolutely is NOT required for the functionality of the blasters, it is just a neat addon. But if you want to have it you should get a hot air soldering station, to remove the SMD resistor from its current place.

The resistor is a 4.7K, just in case you kill it during the process. You need to remove it from position R11 (address 0x3C) and solder it to position R12 (address 0x3D).

ATTAG – IR laser measurings

As I wrote in a former post, I would test the laser power of the small IR laser. I got myself a tiny HWLPM-Mini 10W. It isn’t very accurate and usually measures up to 7% higher than the real power. The smallest step is 1mW and pointing the IR laser at it, powered with 3.3V coming from a D1Mini, it leaves the display of the laser-meter at 0.000W.

While the max voltage of the laser is 3.5V , the specs look pretty realistic with 0.6-0.9mW. So at 3.3V it probably will be around 0.7-0.8mW.

You may say the laser-meter is broken, no it actually isn’t. I tested two laser pointers at it and was a bit shocked, the blue one ends up at 28mW after 20 seconds, the red one at 6mW, so they are both far over the 1mW rate they are sold at and the blue is even far above the 5mW labeled sticker on it. So watch your eyes when using these.

Conclusion: The IR laser might actually be an option.

ATTAG – Required components

This post will be updated from time to time, the components might change, so it is up to you if you want to experiment on your own while in the “pre-release” state or wait for a release state. All items get a color status:

yellow = component might change blue = component is final choice, only chance of change is if insurmountable obstacles appear

The prices are those I payed for them and of course depend on the source where you get them. I am not related to any of these shops and I don’t get any bonus or affiliate payments, they are just a suggestion.

NOTE: Not in the list are basic items you will need for sure such as wires, solder, some glue and filament for the printed parts. For the JST connectors I don’t provide a link since there are offers with collections that make more sense including or not including tools etc.

Minimum requirements for ONE blaster, minimum means no audio or visual feedback and no blaster ID, which makes all of this pretty useless but you can fire at a target and the target gives feedback. Actually you just need the IR sender and receiver, one resistor plus the LOLIN S3. But hey, that won’t be fun at all.

qtycomponentdate of change/addpriceurl to shop
1LOLIN S3 mini or clone2024-03-075,47 EURlink
1LD 274-3 IR LED2024-02-030,99 EURlink
11000 uF capacitor2024-02-030,95 EURlink
1TIP 120 transistor2024-02-030,45 EURlink
21N4148 diode2024-02-030,06 EURlink
13,3KOhm resistor2024-02-030,05 EURlink
10,5Ohm resistor2024-02-030,23 EURlink
1TSOP 31238 IR receiver2024-02-030,85 EURlink
15V power bank2024-02-03
1micro switch2024-02-030,17 EURlink

Suggested additional parts for ONE blaster. This is the stuff YOU WANT to get in addition to the minimum requirements.

qtycomponentdate of change/addpriceurl to shop
1128×64 I2C OLED2024-02-031,57 EURlink
14Ohm 3W speaker2024-02-030,82 EURlink
2socket for the S3 mini2024-02-030,16 EURlink
1trimmer 100Ohm2024-02-030,30 EURlink
1PAM 8302A amp2024-03-011,60 EURlink
24 pin JST XH 2,54mm socket2024-02-03
24 pin JST XH 2,54mm
82 pin JST XH 2,54mm
82 pin JST XH 2,54mm
43 pin JST XH 2,54mm
43 pin JST XH 2,54mm

1mainboard PCB2024-02-03
1achromat lens2024-02-03

Additional blaster components for maximum fun šŸ˜‰

qtycomponentdate of change/addpriceurl to shop
3470 Ohm resistor2024-02-030,81 EURlink
14 pin magnetic
2024-02-032,02 EURlink
1MB85RC256V FRAM2024-02-032,48 EURlink
25mm LED red2024-02-03
1WS2812B 5V
LED strip
1128×32 OLED display2024-02-031,20 EURlink

Components for the server

qtycomponentdate of change/addpriceurl to shop
sunton display
WITH touch
2024-02-0310,80 EURlink
14Ohm 3W speaker2024-02-030,82 EURlink
1rechargable battery2024-02-034,71EURlink

Update 2024-03-07:

Since the S3 Mini causes massive trouble with many libs I probably have to replace it again by something else, I ordered some ESP32 WROOM dual core boards to check them out and to compare their behaviour to the bitching of the S3 Mini.

I hope the S3 is still an option in the future (damn, I got ten of them šŸ˜‰ ) but at the moment it suffers from incompatibility because the development of many important libs is still not aware of it or just doesn’t want to be aware of it.

ATTAG – don’t waste the light?

While I was watching the IR LED with some old dashcam I noticed that still a lot of the light, which is not in the main cone of light, is unused plus the lens is 31mm instead of the ideal 47,7mm. So the best choice would be a lens about 50mm with the focal length of ~135mm. However this would make a big gun barrel and usually those bigger lenses have a longer focal length so it won’t match the LED again with its 20Ā° angle. Also the spot diameter would be bigger though with less incrementation at distance.

So instead I’ll try to get more light from the LED and push it into a smaller angle with these reflectors:

However they don’t have a 5mm bore so the LED needs to be fixed behind it. Don’t know if there will be any advantage at all but I’ll try. Using two LEDs instead of one is still an idea but in first tests this turned into a display of two spots.

Update: Test with and without reflector, with and without achromat. It looks like the reflector is of no real use. However, these tests are made without the peak amperage of 1A which finally will be used for some microseconds per shot. So the LED emission from the LED still might be different then.

And this is what happens when using two diodes while hoping that the intensity can be doubled. It is not working with lens usage, it probably would requires some diffusor or whatever, I don’t know. I am open for ideas šŸ˜‰