Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Slugworth
Feb 18, 2001

If two grown men can't make a pervert happy for a few minutes in order to watch a film about zombies, then maybe we should all just move to Iran!
I want you to succeed, but because it would be funny, I also secretly hope you can't move the icon from that spot on the screen.

Adbot
ADBOT LOVES YOU

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


I've been thinking about your soft power switch A LOT, and I think using the buttons arduino to control it is a simpler path than trying to get the raspi to do it. The two controllers are already talking to each other, so signalling intent shouldn't be too difficult. Since almost all of the soft-power-on stuff can be in the setup() routine and the power-off can be in the raspi with hard clamping help from the arduino, that can also help narrow down where problems are happening and give a little bit of redundancy.

Also, great work on the overlay! Why is the emulator on layer 10,000? That's silly.

Cory Parsnipson
Nov 15, 2015

Slugworth posted:

I want you to succeed, but because it would be funny, I also secretly hope you can't move the icon from that spot on the screen.

Oh no, my peepee is much too big for that :smugdog:


https://i.imgur.com/vuLm4WG.mp4

Pngview Documentation posted:

Utility to display a PNG image on the Raspberry Pi screen using the Dispmanx windowing system. Press Esc key to exit. Use 'w', 's', 'a' and 'd' keys to move the image on screen. Use '+' and '-' keys to change the number of pixels the image moves (default is 1).


EXPERIENCE TRANQUILITY

babyeatingpsychopath posted:

I've been thinking about your soft power switch A LOT, and I think using the buttons arduino to control it is a simpler path than trying to get the raspi to do it. The two controllers are already talking to each other, so signalling intent shouldn't be too difficult. Since almost all of the soft-power-on stuff can be in the setup() routine and the power-off can be in the raspi with hard clamping help from the arduino, that can also help narrow down where problems are happening and give a little bit of redundancy.

Up until recently for some reason I thought if I added more button control to the Arduino, then it'd have unintended consequences like letting the user configure them as gamepad buttons (i.e. you could map the volume +/- or power buttons to jump or shoot, etc), but then after I read this I realized that it wouldn't happen unless I specifically added them to the HID report. I think you're on to something though. The Arduino should be the microcontroller I need to do power-on hysteresis, except that it would mean I'd have to change the Vout wiring on the power switch and then maybe add another transistor controlled by the Arduino leading to the RPi. The power-off would work as is I guess. After the overlay is mostly done I'm going to go back to the power switch wiring and put it back in it's original place and then mount everything on a 3D printed bracket. That'll be a good time to see if I can change anything there and hope that it's not too hard for me to do...

babyeatingpsychopath posted:

Also, great work on the overlay! Why is the emulator on layer 10,000? That's silly.

I think they wanted plenty of room to draw on layers behind and in front of the emulation station canvas and chose 10,000 arbitrarily. A more logical solution would have been 32767 :spergin:

Cory Parsnipson fucked around with this message at 23:06 on Sep 23, 2021

Cory Parsnipson
Nov 15, 2015
Jak Sie Masz



Hello, it is with great excite I would like to present to you, a glorious update for make benefit of video game console.

I've been writing this python script that uses many pngview calls to draw images to the screen. It is also capable of calling the bq27441 bash script using subprocess calls to get the remaining battery life. Here I took an intermediate form of the script and wrote a short loop that decrements the displayed number, wrapping around and switching between charging and discharging states just so I could see what everything looked like.


https://i.imgur.com/yzvktPr.mp4

Pretty cool! However, the flickering when the image changes was kind of annoying so next I tried to get rid of it.


https://i.imgur.com/6Hnko9f.mp4

Hehe. Heck yeah. :cool: To do this properly involves replacing pngview with a custom program that supports animation. pngview unfortunately wasn't written with animation or regular screen refreshes in mind. But if you look at the guy's source code, he does have another section where he animates stuff by doing a different series of function calls to the DispmanX API. Writing a custom pngview-type program to copy that is too much effort at this stage in the game so I did a quick hack instead.

My script and the GBZ overlay code work by calling pngview whenever a new sprite needs to be drawn to the screen. Each call spawns a new instance of the program, but there is no way to update the picture without spawning a new process. Instead, a new pngview process is created with the new image and then the old process, which was saved in memory, is killed. This causes a flicker because there's no overlap here. I found that if I put in a really small delay between creating the new process and destroying the old one, I can make it so that the flicker is hard to see.

code:
    pngview_call = [val for pair in zip(["-" + str(k) for k in kwargs.keys()], [None if not str(v) else str(v) for v in kwargs.values()]) for val in pair]
    pngview_call.insert(0, PNGVIEW_PATH)
    pngview_call.append(pngfile)

    pngview_call = filter((None).__ne__, pngview_call)

    pid = subprocess.Popen(pngview_call)
    time.sleep(0.025) # this is a hack to prevent flickering
    if draw_id in PNGVIEW_PROCESSES:
        PNGVIEW_PROCESSES[draw_id].kill()
    PNGVIEW_PROCESSES[draw_id] = pid

    return pid

kekekekekekeke

25 milliseconds works. Who knew?

Looks great, but I still wanted to add a dark background over the HUD in case the background was light colored.


Oooooohhhoooo~ looks even better!!


Hey! Everybody! This man added a NOTCH! Lets GET HIIIIIIIM


https://i.imgur.com/Iugisf3.mp4

Here's an action shot. I'm not sure how I feel that the HUD isn't lined up to the edge of the emulator screen for the non-widescreen programs. I haven't found a way to adjust the width of the HUD to match, but it looks to be quite difficult.

When I was trying to record this video, I ran into an issue where the analog sticks were haywire again. I figured out that I can get them back by wiggling the USB cord around, so that's another thing to toss on the pile of controller fixes. Not sure what's going on but the connector has a metal case, so maybe I should wrap it in electrical tape. *sigh*

TODO

So the display isn't quite done yet. I have the fuel gauge readings working, I just need to feed them into the display code so that the number on the screen is actually what the battery status is.

Other features to do before I move on include:

* Momentary power button press to toggle HUD visibility. Obviously you're gonna want to hide the battery display at some point.
* Show momentary popup notification when battery reaches low levels.
* Call sudo shutdown -h now when the battery falls below critical levels. Critical level TBD. Let's hope it's not something ridiculous like 30%...

Nice to have (but possibly difficult to implement) features:

* Brightness adjustment (I need to figure out how to intercept controller input when the menu is up to accomplish this...)
* Screenshot function?

I found this program called raspi2png also written by AndrewFromMelbourne that records a screenshot when you call it. I can probably write a script to hook it up to a button combo or an option from the menu underneath the brightness adjustment.

code:
wget "https://github.com/AndrewFromMelbourne/raspi2png/raw/master/raspi2png"
chmod 755 raspi2png
sudo mv raspi2png /usr/local/bin

raspi2png -c 9 -p snapshot.png

Cory Parsnipson
Nov 15, 2015
GPIO interrupt handling

Current code here. I got the battery level interrupt coded, it was one line:

code:
def handle_battery_charge_state_change(channel):
    """ Update the status overlay with new battery life percentage
        information.
    """
    draw_hud(battery=get_state_of_charge(), is_charging=(not is_discharging()))
All in a day's work, I say. :smug:

And then coded up the power button interrupt handling code. This was slightly more complicated because I had to debounce it in software and also wanted to distinguish between short and long presses. Ignore that I wrote "debounce 100ms" but clearly have it waiting for 75ms. :haibrow: I have it so that a short press is 0.5 seconds or shorter and a long press is anything longer than that (but not 6.6 seconds long because that'll shut off the system). I accomplish this by reading the power switch GPIO pin level and using that to determine if we've pressed or released the button. If we've pressed it, then record the current time and go back to sleep. If we've released it, we need to get the current time and figure out the elapsed time between now and when the button was last pressed.

code:
def handle_power_button_press(channel):
    time.sleep(0.075) # debounce 100ms

    if GPIO.input(CONFIG["BATTERY_POWER_PIN"]):
        # input is high, button was released
        release_time = datetime.datetime.now()
        if release_time - __LAST_POWER_BUTTON_PRESSED_TIME__ < datetime.timedelta(0, 0, 0, 500):
            # short press has happened
            if CONFIG["POWER_SWITCH_BEHAVIOR"] == "FLASH" or CONFIG["POWER_SWITCH_BEHAVIOR"] == "FLASH_INITIAL_ON":
                flash_behavior()
            else:
                toggle_behavior()
        else:
            # long press has happened
            pass
    else:
        # input was low, button was pressed
        __LAST_POWER_BUTTON_PRESSED_TIME__ = datetime.datetime.now()
And then when a short press is detected, I have it choose either "flash" or "toggle" behavior based on the current config. And those I will explain next...

Adding new Usage Modes

I got into a programming kick again and refactored the local variables of the status_overlay script into a giant dictionary called "CONFIG". Also I added the ability to read and write this dictionary to a file in JSON format, so you can edit the variables manually. This was all in preparation for adding a couple usage modes that I think would be useful:

code:
# INITIAL_ON -> toggle mode, start with hud visible
# INITIAL_OFF -> toggle mode, start with hud hidden
# SAVED -> toggle mode, start with state read from config file
# FLASH (show hud on button press for a short time then hide)
# FLASH_INITIAL_ON -> Flash mode with hud shown for 3 seconds on start
CONFIG["POWER_SWITCH_BEHAVIOR"] = "SAVED"
So there's two modes, TOGGLE, and FLASH. Toggle is as you expect, when you momentarily press the power button, it will toggle the visibility of the hud. This is what I mentioned before. Should be nice to use. Within TOGGLE mode, there is "INITIAL_ON" and "INITIAL_OFF" to set whether or not you want the hud to be visible/hidden when the script starts up. "SAVED" is another mode that remembers the visibility and then loads it from the config file, which is why I did that stuff above. The intention of this mode is that the state will be remembered between reboots. I'm probably going to be using this for the time being.

https://i.imgur.com/6OvrgON.mp4
Toggling visibility. Woooo

The FLASH mode will, when the power button is momentarily pressed, leave the hud on the screen for 3 seconds and then disappear by itself. I thought this might be something popular too. There is also a "FLASH_INITIAL_ON" which is just flash mode but on start the hud is visible for 3 seconds and then disappears. And then it acts identical to FLASH.

https://i.imgur.com/a9SAFSD.mp4

Creating a systemd service for automatically running the script on boot

There's a bunch of informative guides that tell you how to add a program as a linux service that can start up automatically on boot. I followed those instructions and also made a Makefile for easy installation/removal.

code:
[Unit]
Description=Status Overlay (Battery level, etc) for RPi Device
After=multi-user.target

[Service]
Type=simple
User=pi
ExecStart=/usr/bin/python3 /usr/bin/status_overlay/status_overlay.py
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target
Some things to note is that this script should be run by the "pi" user to avoid having root run it and that to get STDOUT and STDERR output to show up in the logs, I needed the PYTHONUNBUFFERED line. There was a lot of debugging here related to making all the previously relative filepaths in the script into absolute paths.

code:
install:
	sudo mkdir -p /usr/bin/status_overlay
	sudo cp status_overlay.py /usr/bin/status_overlay/status_overlay.py
	sudo cp -r images /usr/bin/status_overlay
	sudo cp -rL lib /usr/bin/status_overlay
	sudo cp status_overlay.service /lib/systemd/system/status_overlay.service
	sudo systemctl daemon-reload
	sudo systemctl enable status_overlay.service
	sudo systemctl start status_overlay.service

clean: stop disable
	sudo rm -rf /usr/bin/status_overlay
	sudo rm /lib/systemd/system/status_overlay.service

.PHONY: install disable
Use it like this:

code:
sudo make install
And then later, when something fucks up:

code:
sudo make clean
I needed to do this like 50 times during dev, so this Makefile is my new best friend. With that the script automatically starts on boot. There's like a 10 second delay after emulation station starts up before the status overlay starts, but that's okay for now.

Almost done...

I've been having a lot of fun programming and not having to worry about voltages or whether or not stuff stop/starts working if I wiggle some wires around. I think being able to switch between different topics frequently is very refreshing. I just need to code in two more things--a warning popup on low battery and then another popup on critical followed by shutdown--then I can go back and dismantle the power supply circuitry and work on the final assembly of it.

Cory Parsnipson fucked around with this message at 23:52 on Sep 25, 2021

Cory Parsnipson
Nov 15, 2015
Low battery warning and critical battery shutdown

One last update before I tear down the power supply and go back to banging my head against electronics. I made some pictures to serve as notifications for low battery and critical levels of battery. I put the low battery level at 10% battery for now and critical battery is at 5%.


https://i.imgur.com/Ur60Fsq.mp4
Courtesy warning. (Temporarily using 98% to test out the code)

Aside from the extra calls to display the new images, most of the code changes were in the battery charge state interrupt handler. (It's no longer one line long. Sad!)

code:
def handle_battery_charge_state_change(channel):
    """ Update the status overlay with new battery life percentage
        information.
    """
    global __PREVIOUS_STATE_OF_CHARGE__

    charge = get_state_of_charge()
    draw_hud(battery=charge, is_charging=(not is_discharging()))

    if charge <= CONFIG["LOW_BATTERY_THRESHOLD"] and __PREVIOUS_STATE_OF_CHARGE__ > CONFIG["LOW_BATTERY_THRESHOLD"]:
        draw_notification("low_battery_warning.png", "low_battery", CONFIG["LOW_BATTERY_NOTIFICATION_DURATION"])

    if charge <= CONFIG["CRITICAL_BATTERY_THRESHOLD"] and __PREVIOUS_STATE_OF_CHARGE__ > CONFIG["CRITICAL_BATTERY_THRESHOLD"]:
        __SHUTDOWN_LOCK__.release()

    __PREVIOUS_STATE_OF_CHARGE__ = charge
As you can see, there's two statements that check for low notification and critical notification required. The critical battery notification is more complicated than the low battery warning because not only are we putting up a notification box, but I want the device to wait 5 seconds and then shutdown no matter what's going on.


https://i.imgur.com/k8RatUQ.mp4
The device shuts down after 5 seconds in the middle of whatever you were doing.

Shutdown is achieved by using the `sudo shutdown -h now` bash command in a subprocess.

code:
def shutdown():
    """ Shut the device down.
    """
    draw_notification("critical_battery_mock.png", "crit_battery", CONFIG["CRITICAL_BATTERY_NOTIFICATION_DURATION"])
    on_exit(0, 0, False)
    print("Initiating shutdown in 5 seconds...")
    time.sleep(5)
    subprocess.run("sudo shutdown -h now", shell=True)
Synchronization required...

GUH. I took out the infinite loop in the main thread and replaced it with a signalling lock. The main thread does everything and then at the very end gets blocked waiting on the Shutdown Lock. Then in the charge interrupt, I release the lock and exit to signal the main thread to actually do the shutdown. This was because I couldn't run the exit routine in the interrupt thread because it mucks with the POSIX signals some and Python doesn't like that. I didn't want to separate the `on_exit` function so I just made the interrupt thread signal the main thread to do the cleanup.

code:
import threading
# ...
__SHUTDOWN_LOCK__ = threading.Lock()
# ...

def handle_battery_charge_state_change(channel):
    """ Update the status overlay with new battery life percentage
        information.
    """
    # ...
    if charge <= CONFIG["CRITICAL_BATTERY_THRESHOLD"] and __PREVIOUS_STATE_OF_CHARGE__ > CONFIG["CRITICAL_BATTERY_THRESHOLD"]:
        __SHUTDOWN_LOCK__.release()

if __name__ == '__main__':
    # ...
    # acquire this twice because we want the Lock to start out blocking this thread
    __SHUTDOWN_LOCK__.acquire()
    __SHUTDOWN_LOCK__.acquire()
    shutdown()

Cory Parsnipson fucked around with this message at 06:24 on Sep 27, 2021

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

I've been thinking about your soft power switch A LOT, and I think using the buttons arduino to control it is a simpler path than trying to get the raspi to do it. The two controllers are already talking to each other, so signalling intent shouldn't be too difficult. Since almost all of the soft-power-on stuff can be in the setup() routine and the power-off can be in the raspi with hard clamping help from the arduino, that can also help narrow down where problems are happening and give a little bit of redundancy.

This is what I've come up with, not sure if it matches what you were thinking:



So this differs from the current method in that now the power switch signals go into the Arduino instead of the RPi and the power is also routed into the Arduino via the RAW pin. There is also an NMOS transistor in front of the RPi VCC controlled by an Arduino GPIO.

On Power On -> When the button is pressed momentarily, it should turn on the Arduino and then in the firmware, I set the GPIO of the Sense/Ctrl to INPUT and wait maybe 500ms before checking to see if the power button is still pressed. If it isn't, I change the Sense/Ctrl GPIO to OUTPUT and drive it to ground with the Arduino. If it is pressed, I turn on the transistor going into VCC of the RPi with another GPIO (and this remains high until power off).

During Normal Operation -> When the power button is pressed during normal operation, the Arduino watches the sense/ctrl pin and then somehow sends a message to the RPi which has to route that to status_overlay.py.

On Shutdown -> When it's time to shutdown, the RPi sends a message to the Arduino to do a shutdown and then does `sudo shutdown -h now`. No gpio-poweroff overlay needed and GPIO6 and GPIO16 are not used or connected to anything.

Hmm, I suppose this will work. Feels kind of bad throwing all the gpio-poweroff stuff away though... And I need to figure out what protocol to pass messages between the Arduino and the RPi over USB, but this might be "cleaner" if I can get it all to work. :thunk:

babyeatingpsychopath, do you have anything to elaborate on this?

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


Cory Parsnipson posted:

GPIO6 and GPIO16 are not used or connected to anything.

Hmm, I suppose this will work. Feels kind of bad throwing all the gpio-poweroff stuff away though... And I need to figure out what protocol to pass messages between the Arduino and the RPi over USB, but this might be "cleaner" if I can get it all to work. :thunk:

For absolute simplicity, GPIO?? to the arduino for the power-off command and only ever pass USB one direction. Bidirectional USB can be irritating. Unless you're already sending stuff bidirectional, in which case n/m. I seem to remember you had 3 or 4 "spare" GPIOs available.

Alternatively, have GPIO?? tied to the NMOS GPIO and, after the arduino powers the NMOS on, sometime later it just makes that an input. That way, when the pi pulls the NMOS low or de-asserts it, the arduino gets that signal by default. Seems a little bit more fail-safe as long as you trust the power protection and pullups/pulldowns (if enabled, probably not necessary).

I'm not sure if you can use GPIO6 or if you have to use 16, honestly. The GPIO-overlay stuff is a bit esoteric.

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

For absolute simplicity, GPIO?? to the arduino for the power-off command and only ever pass USB one direction. Bidirectional USB can be irritating. Unless you're already sending stuff bidirectional, in which case n/m. I seem to remember you had 3 or 4 "spare" GPIOs available.

Alternatively, have GPIO?? tied to the NMOS GPIO and, after the arduino powers the NMOS on, sometime later it just makes that an input. That way, when the pi pulls the NMOS low or de-asserts it, the arduino gets that signal by default. Seems a little bit more fail-safe as long as you trust the power protection and pullups/pulldowns (if enabled, probably not necessary).

I'm not sure if you can use GPIO6 or if you have to use 16, honestly. The GPIO-overlay stuff is a bit esoteric.

I see. Not doing "slow-on" makes the wiring much simpler. I hook up GPIO6 from the RPI to the Arduino and then sense/ctrl from the power switch to the Arduino. The rest of the communication would occur through the USB ports. Doing slow power on would mean I need to wire up RAW and GND of the Arduino and then wire up a MOSFET, hook GPIO6 to the gate and then probably a voltage level shifter because I'd be hooking up an Arduino GPIO and an RPi GPIO together. I don't think I want to mess with the MOSFET right now. I'm too exhausted to do that without a PCB...

I was looking at RPi and Arduino serial communication over USB and it looks pretty doable. Here's a nice tutorial. I can replace the polling loop in the tutorial with a blocking wait command in a secondary thread too. A nice bonus is that bi-directional communication isn't that bad either. Though I wouldn't need to do that if GPIO6 is going into the Arduino.

Getting to the Arduino to modify the wiring is kind of a liability at this point. So I'm still undecided...

EDIT:



Took another look at the Arduino layer and all the extra GPIOs are covered up with wires except GPIO5 and GPIO6. Unfortunately, the SPX-17870 example code says any GPIO is fine EXCEPT 0, 5, and 15. Bummer. What I think I'll end up doing is hooking RPi GPIO6 to Arduino GPIO6 and the sense/ctrl of the power switch (which is, now I realize, what babyeatingpsychopath was saying all along). It should be good if I'm careful to write LOW to the Arduino before changing it to an output.

Cory Parsnipson fucked around with this message at 02:25 on Sep 30, 2021

Cory Parsnipson
Nov 15, 2015
Possibly some disappointing news on the Power Switch connection front

Ok, so I took some time to think about it and I was going through the steps and I am really reluctant to open up the frame back down to the controller level to solder the two wires I need to the protoboard. I'm scared that I'm going to sever some of the delicate controller wires and I'm kind of hoping to just not touch them ever and fix it in the second version instead... It appears that I've built myself into a corner. Sorry :(

I think it will be easier to just make a weird Y cable splice for now and stick with the current working method. As a consolation, I can go into the "Mk II" with this knowledge from the start and design with this in mind. In the later stages of the project, I'm estimating that reducing the number of GPIO connections to the RPi will be much, much more valuable than it is now. Also, I found an article featured by Hackaday about a project that is disturbingly similar to this one and the guy in this one started with an Arduino to handle exterior button and joystick inputs as a USB HID device and in this current version moved to an ESP32 for that purpose instead. I don't really know what decisions made him switch, but it could be due to reliability or slightly more power/capabilities of the ESP32. I could be likely that I'll eventually end up doing the same thing, but the key takeaway here is that giving more responsibility to the microcontroller acting as some sort of "front-side bus"/"host controller" type thingy is a good thing.

I locked my brain in an empty room for a week and this came out


There's random holes everywhere on it. What is this, a loving car????

The second version of the backplate looks like this. Recall that the old version looks like this:



It really ballooned in size because I decided to add bracing to the sides underneath the dpad and button pads. This was originally going to be part of the back of the enclosure, but finding an unbroken straight line from the back of the case to the parts that it needs to brace is barely possible. In this way, the design ends up being separated into horizontal layers. Now if only I thought of this before and was able to clean up the wires...

Making new frame parts is particularly hellish, simply because I'm making everything up as I go along and with each new part come a bunch of extra positioning constraints. The alignment of the bracing columns was pretty daunting, but having a full assembly of all the previous pieces made it much easier to do the trial and error without having to print anything. There's so many wires, screw holes, etc, to work around. This'll definitely be something to avoid the next time around.


Here's the front of the assembly. Looks pretty cool, actually. :thunk:

As for the actual component mounting, I sat and stared at this thing for a couple days, and eventually settled on a layout like this:



Probably looks obvious now, but man these three tiny PCBs feel like they were specifically designed with I/O placed in such a way to prevent fitting them together compactly.



This is them drawn on the back of the second layer frame piece.


Seven hours of printing later...

Charger stand-offs and power switch holder



The second layer frame piece needs some extra pieces to mount everything. The Sparkfun charger can get up to ~58C when charging and supplying power so I wanted to keep that off of the frame itself and far away from the USB hub. I also need the gap underneath to route two wires to the speakers.

I'm pretty proud of the power switch holder. It makes me feel like I'm getting better at CAD. It's a pretty sturdy design that is quite low profile and, aside from the circular hole, prints pretty easy. This holds a tactile "OMRON" switch and n3DS XL power button. This will be wired into the latching soft power switch and mounted on the edge of the frame so it'll be flush with the enclosure.





I took some risks with the design of these parts. The standoffs have 4 long-ish bridges to keep the contact to the Charger at a minimum. The bridging didn't work out super well, though it was without supports. Another thing to mention is that the vertical hole for the power button has a flat top because my Prusa seems to have a problem with this type of overhang. I think I want to do some calibration and try and fix these problems soon. The printer also seems to be developing a partial clog or something cause I'm seeing some areas of underextrusion for no apparent reason. Perhaps now is a good time to spend some time on printer maintenance...

Well I'll be



Holy shiiiit pisss!! The piece fits perfectly! Assemblies are my new best friend.

cakesmith handyman
Jul 22, 2007

Pip-Pip old chap! Last one in is a rotten egg what what.

That is an incredible assembly of pieces, really impressive to see the design iterating.

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


Cory Parsnipson posted:

Holy shiiiit pisss!! The piece fits perfectly! Assemblies are my new best friend.

WOOHOO! Great job! The iterations on this have been fascinating to watch. You're an inspiration.

Cory Parsnipson
Nov 15, 2015
Thanks guys. I hope I can get to the point where people can try printing these out themselves. Not these, though, they're way too overcomplicated.

Cory Parsnipson
Nov 15, 2015
Wiring up the Power Switch

I soldered wires to the power switch and I used a flux pen to get the leads nice and wet. It makes a huge difference in ease of soldering and I was able to get two nice big globs on there.


These connections are stronk. They're not going anywhere.





Oooooh lookin gooooood

The Last Piece

I was going to start putting everything on the second layer when I realized I forgot to make one last piece of the frame. The RPi mounting bracket. This needs to go on before the second layer is screwed on to the frame because the screws go in from underneath. So naturally, I quickly got to work and ended up playing video games for two days. And then I designed the mounting bracket.



The bridged section here seemed to work out a little better than before (because I cleaned the printer). This was also printed with no supports and there was only a slight droop. I cleaned some of the gunk off the underside of my steel sheet. I think this was causing the print surface to be unlevel and since it's not metal, the printer doesn't know to compensate for it. That would explain the z-level issues and seemingly random elephant's foot I've been seeing. Everything started working good as new again. No more random underextrusion, melted artifacts, and slightly improved bridging. Whew.



There, that's all the frame pieces done--



Ah poo poo. It's too short. Those two big caps are in precisely the wrong spot. I could bend the legs of the mounting bracket around them but it's not worth the effort. Gonna make the entire device 2.5mm thicker instead. :rip:

Second Layer Fastened

Ok so some modifications and about an hour and a half of printing later, I got an RPi mounting bracket that's 2.5mm taller and everything fits now. Link to the chassis v2 parts for the curious: https://github.com/CoryParsnipson/rpi-proto-1/tree/6359b8e61d1ac39969db7ae18f3ea0343bc6d752/models/chassis-v2



Here's the whole setup from the bottom. I've connected all the speaker and stereo decoder wires to the audio amplifier protoboard.



Here it is from the top.



And here is a side view. The second layer basically doubles the thickness of the device. And the third (I consider the RPi holder to be the third layer) is probably going to add another inch or so on top of that... This is because of the pin header on the RPi and the plastic dupont connector housing wires attached to them. So yeah it's going to be pretty thick. Currently looks to be coming in at about the size of a brick. One that is slightly thicker than usual.

The Final Stretch

It's time to add on all the power supply components and wire them together and then turn it on and cross my fingers and see what happens.

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


Cory Parsnipson posted:

It's time to add on all the power supply components and wire them together and then turn it on and cross my fingers and see what happens.

Bummer about the bracket being too short. Thankfully you're not getting these milled from billet aluminum and they take two weeks to show up.

Good luck with the power-on and don't let the smoke out!

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Bummer about the bracket being too short. Thankfully you're not getting these milled from billet aluminum and they take two weeks to show up.

Good luck with the power-on and don't let the smoke out!

It wasn't too big a deal with 3d printing. I had the modifications in place before the nozzle finished warming up and then had a new bracket printed in the time it takes to go for a run and eat dinner. God I love this thing.

Power Supply Installation (Part 1)



I put in some squares of electrical tape on top of the charger mount where it touches the charger. I don't know if this will actually help or is even necessary. When the battery runs down, I need to remember to use the device while it's charging and then check to see if anything melted.

Today was busy. So much crimping... and then cutting and bending wires... and more crimping... I started with making a new USB power cable:


Soldered and then smothered in super glue for superior hold



The new one next to the old one. The new one needs to be much longer and also lower profile to fit into the case dimensions. Since I moved the power switch back to being between the RPi and the charger, I need to put a 2-pos JST-PH connector on it too. Also I've mounted the battery. There's a hole in the middle of the case underneath the battery that I've used a single 2.5M screw to secure to the second tier holder. I've screwed it in somewhat tight, but it still rotates a little if I touch it. That's ok. It just needs to be secure enough not to rattle when I shake it.



Here's the cable fitted to the RPi and routed under the charger mount into the power switch.



I made two more cables. One going from the power switch to the 5V regulator (green PCB), and then another one coming out of the regulator. It's currently stuck dangling in the air because it is going to go into the charger output. The Big rear end (TM) cap is stuck on the Vin of the 5V regulator and I've bent it over the regulator for space reasons. The ports of the regulator are jammed up right next to the charger mount so there's not much space there and it's really hard to mess with things. Not too ideal, but this is just life when you're working with off-the-shelf components.



All three power supply boards are mounted now and the 5V wires now run from the charger to the RPi.

Cory Parsnipson
Nov 15, 2015
Power Supply Installation (Part 2)

Almost there. The thick power delivery wires are done and now I need to hook up all the data signals and stuff to the RPi.



I've crimped five more wires using dupont connectors for all the charger signals. I accidentally made a really pretty cable. I used a 5 pos dupont connector for the charger side that splits off into individual wires for the RPi side. It's also conveniently Voltron colored, so that's cool. To refresh, the charger signals contain a ground (black) and 5V reference (red), then there's SDA (yellow) and SCL (blue) which are the two signals for the I2C fuel gauge interface, and lastly there's the GPOUT signal (green) for the state of charge interrupt signal.

There's just one more component to finish hooking up and that's the soft latching power switch. This has 4 signals to do and now the time has come for me to finally suck it up and make that weird cable I talked about.

Making that Weird Y shaped cable



So the two signals from the power button holder go into the leftmost GND and BTN signals.


This thing.

Then there's the other GND and the sense/ctrl pin that I got stuck on for a few weeks. This pin needs to go to GPIO6 and GPIO16 on the RPi, and we leave the FAST OFF signal unconnected.



Ok so I got these parts lying around. How are we gonna make a single wire go into two dupont connectors... :abrathink: This is one of those times that I go in without a solid plan and it ends up working out pretty alright. Feels good man.



I took an exacto knife and stripped the wire somewhere in the middle by carefully cutting around it and pulling the right side out like a long sock. Then I recut the extra plastic and stripped the right side after that. Next I put a metal dupont crimp onto the right side of the blue wire and prepared the brown wire by cutting it to size, stripping it, and crimping the left side.



After that, get in touch with your inner sewing freak and twirl the resistor lead around the exposed middle of the blue wire. I used the flux pen from earlier to get the coil wet for a nice big solder blob to go on it. Also recall that I'm using a resistor between them to protect against the unlikely event that I set both GPIO6 and GPIO16 to output and drive them to different values.



Twirl the other lead of the resistor around the end of the brown wire, which was much more difficult. And then solder both junctions.



Cut the leads to length and wrap with small pieces of electrical tape.

Assembly Complete!



Woo hoo! I had feelings sitting there realizing that I don't have to make any more new parts for this device anymore. My desk is so clean now.

Cory Parsnipson
Nov 15, 2015






I send my friend a picture of it facing the screen and he thought it was like half an inch thick. Haha LOL nope, this thing is fat. SOMEDAY

BIG REVEAL

Ta daaaaaa

https://i.imgur.com/c7AWAaU.mp4


https://i.imgur.com/4cyUldU.mp4


Again apologies for the crappy camera work. I did not realize how hard it was to film one handed... Also this system is really not able to be operated with a single hand. That's something we might be able to fix later though. :thunk:

So close, yet so far

I have some bad news. The analog sticks don't work and the left dpad is also still busted. You might be able to tell in the video where I briefly press it and kirby doesn't move to the left. I'm surprised at how important going left is in so many video games even in ones where the objective is to go to the right...

I know I just put everything together, but now I'm gonna have to strip everything down to the Arduino layer and try and figure out what the problem is.

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


That's great, man. Great video! I thought you were taking it outside to put next to a literal brick for scale.

Is it possible to get code into the arduino from its current assembly state and have it push ultra-verbose messages about what signals it's getting so you don't have to vivisect it and get in with the logic probe?

Cory Parsnipson
Nov 15, 2015
Oh drat I should have gotten a brick. It's like 150% thicker than one though so it would be an unfavorable comparison haha.

I can use jstest /dev/input/js0 to see the button readings. What I see is the analog sticks tend to be unresponsive and at -32765 and the left button isn't getting anything.

Also on another note I set up arduino-cli so I can program it in situ and its pretty cool.

I think I have to take it apart. :( Even the multimeter shows all the wires are connected so I don't really know what's going on. It feels like something related to the socket maybe because the signal comes and goes depending on how I wiggle the USB cable or flex the protoboard.

Cory Parsnipson
Nov 15, 2015
I realized that I don't have to disconnect every single thing when I take it apart. I just need to disconnect the DSI cable, USB hub cable, and audio amplifier signals and then I can slide the second and third layers off of the first.


This kills the crab.

Lot of weirdness going on but I noticed that if I slam the Arduino down all the way into the socket, the analog sticks stop responding. They come back if I pull it slightly out of the socket. Later I found that if I flex the protoboard everything is on in one direction, the signals come back, and if I flex in the opposite direction, the signals go away. I originally thought the problem was with the USB cable, but now it looks like it might be the socket.

I pulled out the controller jellyfish and just did some random reflows using my soldering iron including the two wires that the analog signals go on. There wasn't any real reason for it, I was just doing in case it would help with keeping a stable connection when the board flexes. Weirdly enough, the analog sticks are back from just doing that! Very good. There's absolutely no noise detected from jstest and they reliably work across power cycles, some slight flexing, etc. I think I got very lucky here and put the stuff back into the holder and hope that nothing I do will flex the board very hard from now on.

Second tier holder fixes



So in the first version of the second tier holder, I put a little bump on the underside that I called a "cable press". This was from before this week when I dug more into the signal issues. Previously, I thought it was because of the USB cable tugging at the Arduino so I put in this cable press to keep the Arduino in the socket. Now that I know it isn't the case, I've taken it out of the model and did a bunch of small positioning fixes and stuff while I was at it. (It was inevitable because FreeCAD sucks and I basically had to rebuild half the model anyway)



The cable press is now a clearance notch.



And it turns out I have to remove everything anyway to move it to the new holder. I did all that this afternoon and it wasn't that bad, maybe a couple hours tops. I shouldn't be so afraid of taking things apart, it's not as bad as I thought it would be.

Mystery Bug



The analog sticks seem to be back in business, but the dpad is still broken. This completely eludes me. As far as I can tell, whether it works or not is random. I jiggled the wires, reflowed the solder joints, checked continuity, contemplated replacing the tactile switch.

The only consistent thing is that when I power cycle the device, the left dpad usually (>90%) doesn't work. And when that happens, if I put my finger across the switch, bridging both leads together, and then press the dpad a couple times, it starts working again! And it works pretty reliably until shutdown and it lays there dormant for a couple minutes and then doesn't work again when I turn it back on. What the gently caress is this

Maybe I should swap out the tactile switch, it could be defective? OR... it might be easier to just take a tiny capacitor and wire it across the button? But I don't wanna do that! It's WEIRD :saddowns:

Cory Parsnipson
Nov 15, 2015
I briefly broke the sound but I fixed it this morning... I take back what I said about taking stuff apart.



Yeah I should dig into the software some instead of going directly to the hardware. I don't want to replace the switch because once it gets "unstuck", it works perfectly, so I don't think that's it.

Arduino-cli setup for future reference

I set up the arduino-cli so I can change the sketch and program it from the RPi through an ssh session.

I installed the "32 bit arm" version of the linux binary from here into /usr/local/bin. And then install a whole bunch of other stuff by googling the error messages it spits out.

I can compile the sketch with:

code:
arduino-cli compile -b arduino:avr:leonardo controller.ino
and upload it to the Arduino with:

code:
arduino-cli upload -b arduino:avr:leonardo -p /dev/ttyACM0 controller.ino
And then replace the serial monitor with these commands:

code:
stty -F /dev/ttyACM0 raw 9600
cat /dev/ttyACM0
We got ourselves a Heisenbug, boys :clint:

babyeatingpsychopath posted:

Is it possible to get code into the arduino from its current assembly state and have it push ultra-verbose messages about what signals it's getting so you don't have to vivisect it and get in with the logic probe?

Last night I enabled the serial messages in the Arduino sketch and uploaded it. Then repeatedly booted up the device and then running jstest and pressing the left dpad button. Consistently, this doesn't do anything, while literally all the other buttons are fine.

When I use the command to view the serial messages and press the left dpad, I can see the press is detected. Then if I exit and rerun jstest, the dpad button miraculously works again. Vice versa, if I look at the serial monitor first, the switch works and then jstest looks fine too. Something fucky is happening and maybe it's a really esoteric software bug.

My feeling is that on boot, the two pins that scan the left dpad button get "stuck" and then running the serial monitor program or touching the switch somehow gets it "unstuck" and it works usually forever until I shut the device off. There's two variations on this. 1) Very, very rarely, the switch stops working after I unstick it. I can get it working again by running the serial monitor. 2) last night there were a couple times where NONE of the buttons would work on startup, but everything worked perfectly after I ran the serial monitor.

I don't understand, it's just two wires and a button that connects them when I press it. How hard can this be???



Slugworth do you see this poo poo?? Do you see this utter bullshit???

Cory Parsnipson fucked around with this message at 21:59 on Oct 14, 2021

Slugworth
Feb 18, 2001

If two grown men can't make a pervert happy for a few minutes in order to watch a film about zombies, then maybe we should all just move to Iran!

Cory Parsnipson
Nov 15, 2015
Yes exactly!! :negative:

I changed out the tactile switch and everything's the same. That wasn't it, but at least I know for sure now. Maybe it's some software bug. I wonder if I can capture the HID packets...

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


Cory Parsnipson posted:

Yes exactly!! :negative:

I changed out the tactile switch and everything's the same. That wasn't it, but at least I know for sure now. Maybe it's some software bug. I wonder if I can capture the HID packets...

Where's your code repository? I would like to take a look at it and tell you you misspelled "38400" or something :D

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Where's your code repository? I would like to take a look at it and tell you you misspelled "38400" or something :D

https://github.com/CoryParsnipson/rpi-proto-1/blob/main/code/controller/controller.ino That would be awesome if it was something like that.

babyeatingpsychopath
Oct 28, 2000
Forum Veteran



Everything here looks minimally acceptable. I'm never a fan of delay(), and think it causes problems. All of the heavy lifting is done somewhere else, though. I can't see what Gamepad() is doing (or even where it's defined).

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Everything here looks minimally acceptable. I'm never a fan of delay(), and think it causes problems.

Well, don't just leave it at that! :rolleyes: What's missing? What's wrong with delay() and what is the replacement?

babyeatingpsychopath posted:

All of the heavy lifting is done somewhere else, though. I can't see what Gamepad() is doing (or even where it's defined).

Gamepad() is part of the NicoHood HID project library. The gamepad interface lets you set the state of the buttons in the HID packet structure and then it handles writing out through the USB interface to the computer and getting it to recognize the device as an HID. (Cory Decides to Use an Arduino)

============================

Say My Name



I put everything back together, because I think if the left dpad button is going to get fixed, it probably won't require me to make any physical changes to it. So I'm going to let this percolate in the background and hope some bright idea will pop up at some point while I work on other stuff. In the meantime, the prototype will be a quirky little thing that has a wonky left dpad button...

After I spent most of the day yesterday trying to figure out what was wrong with that one button, I needed to take a break and unwind for a while. Nothing unusual, except this time was different. Instead of watching tv or going for a walk, I took the RPi, hit the sack, and ended up playing some games on it. Since the analog sticks are working now, I can get around the left dpad issues by mapping the left analog stick to be a second dpad. Looks like we've finally reached a point where things are getting interesting. :getin:

And that brings me to a little series of experiments that I've been wanting to do for a long time:



Metroid Zero Mission was super fun when it came out and is perfect for just some low stakes jumping and shooting. I love that it doesn't have a lengthy intro cutscene.

https://i.imgur.com/38vqfdg.mp4

This thing is an ergonomic nightmare... It doesn't have a case on it yet so it's hard to get an accurate gauge at this point, but I don't know if having one will help that much. The buttons and thumbsticks are way too low on the front face to be comfortable and I have to be really careful not to touch any of the wires or exposed circuitry on the back. Also interesting thing to note was that when I unplugged the usb cable one time, I let go and it bounced back to smack on the exposed RPi, somewhere over its onboard voltage regulator. The metal of the USB connector must have struck just perfectly to bridge two really important traces because it shut the device off. Chalk one up for reasons to have a case!

https://i.imgur.com/3KgBumf.mp4

As you can see, for the average case, the controls are responsive enough to make playing this game mostly enjoyable. I can't adequately describe how good the thumbstick feels as a dpad. This. is. awesome! It's good enough for me to wall jump consistently so...



Two things to note is that having the hardware debounce will help on the occasional time where I get a double button press (I haven't played enough to experience this yet, but I believe it is out there). Also the ABXY holder I printed is just sliiiiiightly too small so the silicon membrane is folded a little bit and that make the buttons sticky sometimes.

Lastly, the viewing angle on this screen is pretty bad. The colors look much better in person, but the videos are taken at an off angle for... ~reasons~. This thing is advertised as an IPS panel, but I think what is happening is that the capacitive touch plate is probably messing it up. (Yes there's touch capability here. I'll try it out sometime, but it's at the back of the list for now). This should be a secondary metric that I need to be careful about when selecting new LCD screens in the future. The small viewing angle is surprisingly annoying at times.

Ongoing collection of Quiescent Power Consumption Data

Remember when I said I was going to put the power switch between the 5V regulator and the RPi? This means that the battery is now always connected to the Sparkfun battery babysitter. I am now convinced this is the intended way to use it because I found that when the Sparkfun charger loses power, it will rewrite all its configuration registers with default values, despite the configuration memory being non-volatile memory. So every time I disconnect the battery and take everything apart, I need to rewrite the config with my 18650 parameters or else it will assume the battery capacity is 1340 mAh. On the flip side, this means that the battery will be constantly drained by the babysitter at the "quiescent power consumption" rate when the device is off. There's this annoying red LED that is always on when the battery is connected and both ICs inside the babysitter claim to consume power on the order of microAmps when the device is off.

To see if this is true, I am making a datasheet to keep track of battery percentage between when I turn the device off and turn it back on some time later (e.g. 12 hours later the next morning).

code:
Observed Percentage	Voltage		Time		Date		Fuel Gauge was Reset	Notes
96			4.126		10:06 PM	10/11/21	*	
88 (or 48???)		3.706/3.753	10:19 AM	10/12/21				Second reading was observed after some minutes. Not sure what happened, SOC interrupt might have come in and the script updated percentage with new info.
44			3.671		4:22 PM		10/12/21		
					
100			4.194		9:54 PM		10/14/21	*			This was originally showing 52%, then after some time, the display changed to 100% probably after SOC interrupt update.
98			3.839		11:14 PM	10/14/21				how did voltage drop so much
91			3.785		11:28 PM	10/14/21				Played Metroid Zero Mission for about 15 minutes
84			3.655		11:19 AM	10/15/21				This changed to 41% battery after a few minutes. Voltage was still the same level. Something weird going on with percentage calculation?
So far the data I've collected is really weird. The fuel gauge needs a couple full discharge cycles to increase accuracy so that might have something to do with it. I'm seeing that the voltage drops below 4.2V rapidly until it gets to 3.7V and then only loses fractions of a volt after that even 12 hours later. This looks to be as expected, but the percentage numbers are wack but maybe the fuel gauge will adjust accordingly after a few discharge cycles. Overall, I'm not see the babysitter to be as efficient as claimed. A micro Amp power consumption would be pretty much undetectable, but the always-on LED could be loving things up. I'm going to collect a bunch of data, then cut the LED and see what difference that makes.

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


I am exceptionally bad at github, but some friends helped me and I believe you may have something approximating a ham-fisted pull request.

The "turn serial port debugging on and it works" sounds very suspicious to me, so I modified your code with #defines to 100% strip the serial port stuff out if you're not using it.

If the d-pad doesn't ever work with the serial port 100% off, then MAYBE there's just something very strange going on in the guts of the USB subsystem on your arduino.

I don't know what pins (row/col) everything is mapped to. Only your .ino is hosted and it doesn't actually list the physical mapping. That specific button may be a weird edge case. When I was doing charlieplexing, there were I/Os that wouldn't go from output to hi-z as fast as others for whatever reason, so I had to have short delays doing row/column selects. It's possible that your Serial() calls are introducing this delay for you.

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

I am exceptionally bad at github, but some friends helped me and I believe you may have something approximating a ham-fisted pull request.

The "turn serial port debugging on and it works" sounds very suspicious to me, so I modified your code with #defines to 100% strip the serial port stuff out if you're not using it.

If the d-pad doesn't ever work with the serial port 100% off, then MAYBE there's just something very strange going on in the guts of the USB subsystem on your arduino.

I don't know what pins (row/col) everything is mapped to. Only your .ino is hosted and it doesn't actually list the physical mapping. That specific button may be a weird edge case. When I was doing charlieplexing, there were I/Os that wouldn't go from output to hi-z as fast as others for whatever reason, so I had to have short delays doing row/column selects. It's possible that your Serial() calls are introducing this delay for you.

Wowowow! I patched your PR, compiled it, and uploaded it and now it seems like it's working. I restarted it a couple times to try it out and consistently seems to be working now.

Oh yeah, I forgot to tell you what the pins going to the left dpad were. The left dpad button is button 7 (from 0) in the HID packet, which could be on a byte boundary. In the key matrix, the row pin 16 on the Arduino and column is pin 4 (so row is set to INPUT_PULLUP and goes high and col is set to OUTPUT and driven LOW).

Good catch on the serial port code. I should have put that behind a macro from the start. Thanks! I've merged the PR.

Cory Parsnipson fucked around with this message at 01:26 on Oct 17, 2021

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


Glad to hear it. I had the file open still and wanted to get some low-effort, low-risk practice with github, so I made another PR. Mostly just for fun, since the code works and all. If it's not broken, refactor until it is!

Cory Parsnipson
Nov 15, 2015
Wow, very gung ho about this... Ok, I took a look at the second PR and left some comments for requested changes and some clarification. You can make the changes and then update the PR or let me know if it's too much effort and I can try to fill them in myself.

Some main points:

* I think I have a general idea of what you're doing with the new delay code, but I'm confused by the details. Could you explain? Also the delayMicroseconds(REFRESH_INTERVAL) is still there and I'm not sure if that's a mistake or not.
* the new readAnalog function is way better, good job. I'd like to change the name to readAxis() now just as a descriptive thing. Also a suggestion for a slight refactor on the bottom of that function to just use two returns and shorten it by a lot.

As a rule of thumb, usually it's a good idea to keep PR's small and focused on a group of related changes. For example, one smaller PR for refactoring readAnalog, another small PR for adding delay loop changes, etc. Or (less preferably, imo) you can organize each of those things into different commits and them push them all together in one PR. For later though, this one's fine.

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


Cory Parsnipson posted:

Wow, very gung ho about this... Ok, I took a look at the second PR and left some comments for requested changes and some clarification. You can make the changes and then update the PR or let me know if it's too much effort and I can try to fill them in myself.

Some main points:

* I think I have a general idea of what you're doing with the new delay code, but I'm confused by the details. Could you explain? Also the delayMicroseconds(REFRESH_INTERVAL) is still there and I'm not sure if that's a mistake or not.
* the new readAnalog function is way better, good job. I'd like to change the name to readAxis() now just as a descriptive thing. Also a suggestion for a slight refactor on the bottom of that function to just use two returns and shorten it by a lot.

As a rule of thumb, usually it's a good idea to keep PR's small and focused on a group of related changes. For example, one smaller PR for refactoring readAnalog, another small PR for adding delay loop changes, etc. Or (less preferably, imo) you can organize each of those things into different commits and them push them all together in one PR. For later though, this one's fine.

Sure. I explained my method and thinking in the arduino thread, but I'll record it here, too.
First of all, I'm not actually compiling any of this code, so I don't know if it even works or where I've made typos. I just did one big rush through everything with broad strokes.

My Arduino timing-based sketches almost always have a loop that looks like this:
code:
	loop() {
	now=whatTimeIsIt(); // be that millis() or micros()
	if (now < time_to_do_a_thing) { 
		time_to_do_a_thing = now + how_long_until_do_a_thing_again;
		do_a_thing(); }
	if (now < time_to_do_another_thing_maybe_with_different_periodicity) {
		time_to_do_another_thing = now+its_periodicity;
		do_another_thing(); }
	do_this_stuff_every_loop();
	}
there won't be any massive delay() in there. Maybe a delay(1..5) to get something fiddly to settle down, but largely, loop() is free-running at maximum speed and the processor just idle-spins at max speed updating now as fast as possible until it's time to do something again. For low-power mode, i set low-power at the end of the loop and let whatever mechanism i have to wake me from low power do its thing when it's time, and then just run through loop() again.

And yeah, this is a fairly massive and wide-reaching PR; I wouldn't do this for an actual collab. I just did the couple of tweaks in the first PR, then wanted to see how this whole PR stuff works. Thanks for your (unwitting) help, and I hope my suggestions are somewhat useful!

babyeatingpsychopath fucked around with this message at 02:27 on Oct 17, 2021

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Sure. I explained my method and thinking in the arduino thread--



Interesting... I have it bookmarked but now I'm curious to read through it.

babyeatingpsychopath posted:

there won't be any massive delay() in there. Maybe a delay(1..5) to get something fiddly to settle down, but largely, loop() is free-running at maximum speed and the processor just idle-spins at max speed updating now as fast as possible until it's time to do something again. For low-power mode, i set low-power at the end of the loop and let whatever mechanism i have to wake me from low power do its thing when it's time, and then just run through loop() again.

Is idle-spinning at maximum speed going to have any negative implications on battery life or lifespan? The application here has limited battery life and is running a single task that checks for events that are ~O(100ms) apart. I hope to keep the loop iterating kind of slowly and as far apart as maybe 50ms. I'm still not sure what's so bad about using delay().

In any case, I see that delay() doesn't save any power and what I thought delay() did was what is called "sleep". I was looking at Arduino's sleep function (which I thought was delay) and it looks like you can sleep and wake up really fast. Probably gonna add that to end of these changes.

babyeatingpsychopath posted:

And yeah, this is a fairly massive and wide-reaching PR; I wouldn't do this for an actual collab. I just did the couple of tweaks in the first PR, then wanted to see how this whole PR stuff works. Thanks for your (unwitting) help, and I hope my suggestions are somewhat useful!

Seems like an actual collab to me. Someday this maybe even a real open source project. :downs: Thanks for the changes, I think overall the program is better now. It's not everyday you get to use the collab features on github.

babyeatingpsychopath
Oct 28, 2000
Forum Veteran


As I understand it, Arduinos consume the same amount of power with loop() {} as they do with loop() { delay(1000); }. No problem. With the pro micro, you have to be careful which sleep state you go into so that you don't turn off the USB subsystem, and how long you try to sleep so that USB doesn't have its functionality crap out.

That said, I think it's important to figure out if the microcontroller is a big power drain on your system. The Internet is saying full-load-max-clock current draw of 50mA, which can be cut to 35mA just by prying off the power LED. It's possible that all those lights hanging off all the various boards are drawing more current than your microcontroller.

Cory Parsnipson
Nov 15, 2015
Spoopy programmer creepy pasta

It was a sunny and brisk Autumn morning on a lazy Sunday. I finally put together some programming changes and was ready to upload to my Arduino. I merged the second PR and fixed some compilation errors. And then when I uploaded the new code to the Arduino, something really spooky happened...

The left dpad button stopped working.


gently caress you, bug

I could feel a rising panic in my stomach as the more frantically I pressed, nothing happened. I started mashing furiously and yet still nothing was happening. Confused as hell, I went back to the console and checked out the previous image of just after the first PR and compiled that and reuploaded it.

I power-cycled the device in sweaty anticipation, but to my surprise... when I turned it on again, the left dpad still wouldn't respond...! Oooooooh spooopy~

I had to touch my finger to the switch again before it would work, but when I did that, both the first PR and second PR work again. Relieved, I decided to take a quick nap and that's when I woke up from my nightmare! My phone was ringing on the table next to me and when I picked it up, a gravelly old lady voice said I'm movin' with your auntie and uncle in Bel Air asked me "who was phone???"

============================

I had to touch the switch with my finger to get it working again, but after that everything seems to be working consistently across both commits. The device was kind of sitting there in the off state for about 24 hours, so this kind of had the feeling of "warming" it up or getting the rust off or something. Very spooky cause I don't know what is happening in there, but the current code does feel like it operates correctly under more circumstances. Maybe this incident was just a fluke?

At the least, I think we're getting close to cracking this case.

EDIT:

Whelp, this isn't a fluke. I turn it on again today after being "cold" for almost 24 hours and the left dpad was dead again. Touching it didn't turn it on this time.

Cory Parsnipson fucked around with this message at 22:09 on Oct 18, 2021

Cory Parsnipson
Nov 15, 2015
Put some clothes on, ya perv!



I'm gonna let the whole left dpad thing work itself out in the background. Maybe something will come up later that'll get me closer to figuring out the root cause. In the mean time, I gotta hurry up and make an enclosure for this thing to get the drat thing done.

Wait a minute

I was making coffee this morning and I had an idea.


This thing is 0.908 pounds!!

This is a heckin' big chonker. And this isn't even with the case on it, which may push it to a full pound. I thought the switch felt heavier, but it turns out that it's lighter! Still heavy, but lighter.


Daaaaaaaaaaayummmm

It's at a svelte 0.884 pounds.

Test plates

The front and back halves of the enclosure will be the largest 3d prints I've made to date. To save on time and filament, I'm going to be making "test plates" of portions of the controller to get the fit right and maybe try out different approaches.





Here's the facade of the left controller that will be covering the select button, the thumbstick, and dpad. Still a lot to do. I need to extend the sides that go over the screen and to the left edge and then make a lip on the back. I know that printing a fillet on the face down side is a no-go, but I want to try it just to see how bad it looks.

Cory Parsnipson
Nov 15, 2015
Enclosure design continues


Circa 2021. An actual honest to god photo of me working on this project



This is beginning to look like something interesting. It was a bit difficult to get the frame fastening screw holes aligned correctly, but the assembly file really helped with that.





Can't wait to do this IRL.


If only the entire device was this thin



And here's the almost complete left controller test plate. It's really starting to look like something! I'm getting a little nostalgia just looking at it. I'm pushing some boundaries with this design here. The panel line around the screen, "SELECT" text, and speaker holes are all going to be facing downwards, meaning the backs will be bridged over. They are being squished together too so there are areas with dangerously thin perimeters. Not that squishing everything together was intentional, it's just the amount of clearance I gave myself while making the inner frame. When I get to the next iteration, I should be able to give myself extra leeway in key areas (e.g. the top of the screen) since I won't be just making everything up as I go.



For instance, this screen panel means the first two layers of this print will have the middle portion of the screen separated. And then they connect via three layers of bridging, ending in the final thing which will be ~0.25mm thick at some points. I think this should be sturdy enough to work, judging from previous designs of the shoulder buttons. But this test plate is exactly to answer questions like these.



The back of the speaker holes has an interesting bridge too. The bridged area of the circle perimeters is so short that I think this should be fine. Very curious to know what it'll look like printed out.



I want the select button text to be in a small font, but this is pretty hard to print. A lot of these depend on immaculate first layer adjustments and adhesion and I've got all that pretty much dialed in, so I'm confident it'll work. (In fact, I'm 20% through the print now and everything stuck almost perfectly). However, later this may be a bigger concern, if I want this to be open source. It would be nice to figure out ways to avoid doing difficult things like this so other people can print these things out without too much trouble, while avoiding compromising on the aesthetics of the design.

Test Plate: Left Controller Cover

I'm printing two versions side by side on the same bed:


Chamfered


Filleted

Initially I preferred the fillet look, which was kind of disappointing because that doesn't print well on faces that are touching the bed. But dang, that chamfer, actually looks pretty snazzy. What I think brought it over the top was instead of using a 45 degree one, I made it 30 degrees (down from the vertical) and that let me make the chamfer really big, which I think looks real nice 'n all. As a bonus, its even easier to print than a 45 degree one.

I'll post back here when they're printed out and fitted. Fingers crossed.

Cory Parsnipson
Nov 15, 2015


Aw sheeit. These pieces don't live up to the hype. The "SELECT" button text is probably the best I could do with a 0.4mm nozzle and doesn't really look that great. The bridging over the speaker holes looks like crap too (although the circle bridge came out perfectly). I think any bridge lower than 1mm is too low for proper cooling to happen. The panel line is 0.3mm deep, the speaker holes are 0.5mm deep, and the SELECT inset portions are 1mm deep. The bridged portions of the SELECT text look like they came out much, much better.

Text on the top surface usually turns out much better, though printing in that orientation would mean I'd need to fill the entire inside with support material and even then the inside finish wouldn't be flat. I could try printing the case in multiple pieces and gluing them together, but the whole point of printing the case in 1 big piece was to avoid ugly seams and creases in the middle of large facades.



The fillet is possible, but leaves much to be desired. The curve sucks and is basically a chamfer anyway. The chamfer piece has an odd bulge where the chamfer meets the vertical wall, which could indicate slight over-extrusion issues. Overall, the chamfer looks better and is probably what I'll go with for 3d printed cases.



The test plate is meant to slide onto the inner frame shoulder buttons first. Luckily the screw holes and all clearance cutouts are right on the money and it fits into place. The only problem is that there is some resistance getting it flush, so I think I need an extra cutout somewhere, but it's hard to see where. Probably right on the top edge of the vertical wall of the shoulder buttons somewhere.





It looks okay I guess. I think I've been staring at this for too long, cause I feel like it's more underwhelming than it should be.



Bonus shot from the back with all the guts exposed.



Here is where the frame fastening screw holes are to keep the front plate in place. It requires poking deep down through the second tier holder and weaving between wires. It's a challenge to get the screw in there, but there's a hole with a countersunk edge at the bottom to guide the screw, so I can just drop it in there with tweezers and then find it with the screwdriver after.



Here's a close-up of the screen panel-lining. The top dimension literally has a section with 1 nozzle width on it. Gotta pull back the size of the chamfer a little. I think the test plate actually accentuates the problem because the actual case would extend all the way across the LCD screen. However, this does look like a difficult area to print.

TODO

I forgot to give reasonable tolerances to most of the holes actually, so almost everything is too small. I should:

* Increase size of thumbstick hole slightly (~1mm). Change chamfer from 45 degrees to something like 55-60 degrees. The edge of the thumbstick scrapes against the chamfer when used.
* Increase size of select button hole and also increase chamfer angle. The button is too short so it's a little unsatisfying to press this.
* I can probably shave off 0.25mm from the front face thickness. This will help with the previous bullet point. I need to print a swatch with 0.25, 0.5, and 0.75mm thick sections and compare how sturdy they are side-by-side.
* It's currently unplayable right now because the shoulder button holes have no tolerances on them. The case is forcing them to be pressed all the time. I need to widen the holes.
* Maybe try inverting the SELECT button text so the word itself is an extrusion and the negative space around the word is a 1mm cutout. That might be better.
* Increase speaker hole inset to 1mm. Possibly consider doing this to the screen panel line too.
* Cutout a small section near the top underneath the shoulder button holes for fitting the enclosure on the inner frame more easily.

Adbot
ADBOT LOVES YOU

Cory Parsnipson
Nov 15, 2015
Trying to 3D print text



I made some smaller test swatches for testing how thin I can make the screen overhang. Using a different font, I added 1.5mm text and you can guess exactly how well that came out.



So, I used GNU Free Sans in the "SELECT" button of the previous test plate and that was set to 1.5mm in FreeCAD on Linux, but somehow that meant the text was about 3.5mm tall. I made this other test plate without thinking using FreeCAD in Windows and obviously this is way too small for the printer. Welcome to Whose Line is it Anyway where everything's made up and the sizes don't matter.



I made a second swatch with various different fonts, this time with bigger sizes. I was using the slicer output to filter out bad ideas to save some time.



Even at 3.9mm, Arial's T doesn't make the cut in the slicer settings. Looks like doing a cutout of the negative space is actually worse than cutting out the text. I've read somewhere that each stroke needs to be at least about 0.7mm wide for it to show up (I have detect thin walls checked too).

I did some searching for good fonts for 3d printing small text and came across someone else's research, but the smallest you can go is like 5.7mm. I downloaded the font anyway and tried it at 3mm ish but I got worse results than Tahoma and Arial.



Another attempt where I tried Verdana and then underneath used the best letters of Tahoma and the best letters of Arial together, which looks pretty good, but is still bigger than the 3.5mm SELECT on the original test plate.

tl;dr

This doesn't really seem like something I should be using the 3D printer to do. I'm gonna try shrinking the latest "SELECT" with Tahoma and Arial to 3.5mm and see what happens. If not, I might just use "SE" or "SEL" instead of the whole word.

For a better solution, I think I'd go with paint or water apply decals (like on those fancy gundam models) for the button labels. It feels like at this point I would need to use plastic injection molding to get satisfactory results. I might experiment with that next time around.

PS

OH and I think I'm coming around to the fillet edge cover... The visual looks kind of bad, but it actually feels rounded and figuring that out made me like it a lot. :sigh: decisions, decisions...

Cory Parsnipson fucked around with this message at 22:37 on Oct 25, 2021

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply