What's the "right way" to do software flips?

143 views
Skip to first unread message

kaydeeH

unread,
Nov 4, 2025, 4:19:48 PM11/4/25
to MPF Users
Hi all,

I have a flipper that I want to do a 2s auto pulse when a certain event is received. Here's a sterilized version of what I currently have, then I'll talk about what's happening in the game with this setup.

flippers:
    flipper_a:
        main_coil: c_flipper_a
        hold_coil: c_flipper_a_hold
        activation_switch: s_flipper_a_button
        enable_events: e_active_event, e_special_condition_enable
        disable_events: e_inactive_event, e_special_condition_disable
        sw_flip_events: e_special_condition_flip
        sw_release_events: e_special_condition_deflip

When the mode starts, e_active_event happens, flipper enables, works normally.
Then at a certain point, the e_inactive_event occurs and the flipper disables, is disabled normally.
A moment later, I want to pulse the flipper for 2s (to release any trapped ball under the flipper, don't ask, it would take too long to explain and it's not really relevant).
So to pulse the flipper, I send the e_special_condition_enable event to enable it, this works normally.
Then 1s later, I send the e_special_condition_flip event. The logs show it enabling the main and hold driver for the coil. But it doesn't flip.
Then 2s later, I send the e_special_condition_deflip event. The logs show it disabling the drivers. But since it didn't flip, nothing happens.
Then 1s later, I send the e_special_condition_disable event to return the flipper to its normal disabled state.

So it's like it should be working, but nothing happens. But here's where it gets interesting. If I manually flip the flipper with the button during the 2s window that the flipper should be flipping on its own, it flips AND HOLDS for the rest of the 2s window until the e_special_condition_deflip occurs and releases it.

I'm at a bit of a loss. It's like it wants to work, but... doesn't... unless I "help" it a little with the flipper button. Is it that I'm not pulsing it long enough doing it this way (it's default is 21ms, which maybe isn't long enough to pulse it to where the hold coil can grab and hold it, though that works fine for an actual flip)? I don't see a way to change the pulse times.

Which leads me to the real question: Is this the way I should be trying to do this? I see that I could use a "pulse_event" directly on the coil, but I believe that will also follow the short default pulse time for the coil and won't let me "hold" it for 2s. Should I set up a second clone flipper, like in the "weak flipper" example? But if so, I still don't see a way to override the default pulse time of the coil.

Update: So I discovered the main_coil_overwrite: option for flippers, and I tried making a clone flipper like in the "weak flippers" example as follows:

flippers:
    flipper_a:
        #Removed all special condition handling
        main_coil: c_flipper_a
        hold_coil: c_flipper_a_hold
        activation_switch: s_flipper_a_button
        enable_events: e_active_event
        disable_events: e_inactive_event
    flipper_a_auto:
        #New special flipper for handing the special condition for auto flipping
        #Activation switch removed so you can't manually flip even when enabled
        main_coil: c_flipper_a
        hold_coil: c_flipper_a_hold
        enable_events: e_special_condition_enable
        disable_events: e_special_condition_disable
        sw_flip_events: e_special_condition_flip
        sw_release_events: e_special_condition_deflip
        main_coil_overwrite:
            pulse_ms: 1000

I thought for sure this was going to do it, but in the log (when running virtual on my PC), it shows it's still pulsing it for only the usual default 21ms. I also tried it using the hold_coil_overwrite set, but same thing, log shows normal pulse time for that coil.

I'll try pushing this to the physical game anyways to see what happens, but my expectations are low based on what I'm seeing on my local logs. But I suspect I'm still either missing something or misusing the coil_overwrite somehow. Any advice would be much appreciated!

Thanks,
Kaydee


kaydeeH

unread,
Nov 4, 2025, 5:22:15 PM11/4/25
to MPF Users
Can confirm that it's doing the same thing in the physical game. It's like the coil_overwrite isn't doing anything and the log just shows the normal pulse time when the e_special_condition_flip event is received.

kaydeeH

unread,
Nov 4, 2025, 5:41:19 PM11/4/25
to MPF Users
Ugh, it's sooo close to working. No change since the last time, but I tried putting my fingers on the flippers and I can feel them buzzing when the auto flip happens. If I manually hold them up during the buzzing, they hold up, just like with the button assisted flip, then drop when they should. So I'm just not getting a strong enough main pulse to make them flip, but the override config doesn't seem to work, so this is where I'm stuck. The events are fine and the auto flipper is responding to the 2s hold, but the main pulse is too weak...

Thanks in advance for any help!

kaydeeH

unread,
Nov 4, 2025, 7:51:10 PM11/4/25
to MPF Users
If it helps, here's the matching coil config:

    c_flipper_a_hold :
        number: 1616_2-11
        default_pulse_ms: 40
        default_hold_power: 0.7
        tags: coils
     c_flipper_a :
        number: 1616_2-12
        default_pulse_ms: 21
        tags: coils

I'm starting to wonder if the coil_player is the answer to my quandry... I'll play with that too. I also noticed I don't have allow_enable set for the main coil, but again, the flipper works under normal conditions without it, so not sure if that's got anything to do with it.

kaydeeH

unread,
Nov 4, 2025, 9:37:18 PM11/4/25
to MPF Users
Well, I thought I had something with coil_player. I got it to work on the virtualized platform and the logs indicated it was honoring my desired pulse times, so I thought I had finally cracked it. But when I went to put it on the physical hardware, it compiled and the game started, but the moment the event fired, it crashed with the following error:

  File "/home/game_dir/MyGame/venv/lib/python3.11/site-packages/mpf/core/events.py", line 755, in _run_handlers
    result = handler.callback(**merged_kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/game_dir/MyGame/venv/lib/python3.11/site-packages/mpf/core/config_player.py", line 348, in config_play_callback
    return self.play(settings=settings, context=context, calling_context=calling_context, priority=priority,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/game_dir/MyGame/venv/lib/python3.11/site-packages/mpf/config_players/coil_player.py", line 44, in play
    coil.pulse(pulse_ms=s['pulse_ms'], pulse_power=s['pulse_power'], max_wait_ms=s['max_wait_ms'])
  File "/home/game_dir/MyGame/venv/lib/python3.11/site-packages/mpf/devices/driver.py", line 351, in pulse
    self._pulse_now(pulse_ms, pulse_power)
  File "/home/game_dir/MyGame/venv/lib/python3.11/site-packages/mpf/devices/driver.py", line 314, in _pulse_now
    self.hw_driver.pulse(PulseSettings(power=pulse_power, duration=pulse_ms))
  File "/home/game_dir/MyGame/venv/lib/python3.11/site-packages/mpf/platforms/fast/fast_driver.py", line 474, in pulse
    self._pulse(pulse_settings)
  File "/home/game_dir/MyGame/venv/lib/python3.11/site-packages/mpf/platforms/fast/fast_driver.py", line 494, in _pulse
    pwm1_ms = Util.int_to_hex_string(pulse_settings.duration)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/game_dir/MyGame/venv/lib/python3.11/site-packages/mpf/core/utility_functions.py", line 352, in int_to_hex_string
    raise ValueError("invalid source int: %s" % source_int)
ValueError: invalid source int: 2000

So it looks like there's some sort of MPF error parsing the pulse time. So I'm back to zero unless someone can clue me in to what I'm doing wrong here.

Here's how I set up the coil_player, FYI:

coil_player:
  e_special_condition_flip:
     c_flipper_a:
       action: pulse
       pulse_ms: 250
       pulse_power: .7
     c_flipper_a_hold:
       action: pulse
       pulse_ms: 2000
       pulse_power: .7

kaydeeH

unread,
Nov 4, 2025, 10:00:49 PM11/4/25
to MPF Users
Le sigh... looks like that utility function caps out the input at 255, arbitrarily limiting the max pulse time to 255s when called by the Fast driver. That won't do, and I can't imagine a core utility function is something I want to start monkeying with. :-( Confounded at every turn!

So back to my original question I guess... how to can do auto flippy thing? :-P

kaydeeH

unread,
Nov 4, 2025, 10:26:00 PM11/4/25
to MPF Users
I should mention this game was originally coded on MPF 0.57.3.dev2 and that's what it's currently running. So if someone can confirm this fast driver issue was fixed on a different version, I suppose that's one approach to get the coil_player to work unless there's an overall better way to be doing this.

Jérôme V

unread,
Nov 5, 2025, 4:42:49 AM11/5/25
to MPF Users
I don't know how to do that but what about the Dual Coil Diverter in the MPF doc ?

Philip Dixon

unread,
Nov 5, 2025, 8:29:19 AM11/5/25
to MPF Users
c_flipper_a_hold :
        number: 1616_2-11
        default_pulse_ms: 40
        default_hold_power: 0.7
        allow_enable: true
        enable_events: auto_flip_event
        disable_events: some_other_event

        tags: coils

This is how I do it.

kaydeeH

unread,
Nov 6, 2025, 9:53:22 PM11/6/25
to MPF Users
Thank you Philip... I hadn't even looked at that because usually "enable/disable" functions refer to whether or not it will listen to events in MPF, so I hadn't considered that it meant "fire the coil" in this case, but... IT WORKED! Out of I believe three completely different strategies, this works where none of the other approaches worked. So thank you for pointing me to this. I'm going to write up a bug for the coil_player with Fast using that utility function that arbitrarily limits you to 250ms, but the other approach... maybe I'll see about writing up a bug for the sw_flip/release_events as well, because that should've worked too (unless anyone can explain why they shouldn't have).

Anyways, thank you, thank you for the pointer! We're back in business!! :)

Alex L

unread,
Nov 7, 2025, 2:22:12 AM11/7/25
to MPF Users
I've been following this and put some thoughts down on the MPF repo issues, but neither felt like the right place to ask for these followup details:

Did Jerorc's suggestion of using a dual-wound coil definition and/or a diverter definition per MPF docs lead to any partial successes or were they complete failures? https://missionpinball.org/latest/mechs/diverters/dual_coil_diverter/

I played around with a dual_wound_coil + diverter definition a while back on Trogdor for a diverter mech (that is actually just a standard flipper with a custom bat) and I believe I had it working well enough to solve your core issue ("a flipper that I want to do a 2s auto pulse when a certain event is received"). I haven't used that configuration in a while, but you shouldn't need a coil_player hook at all, preferring just to send one of the diverter's `activate_events` (which then holds it for `activate_time`).

Actually looking in trogdor code right now, I've even just got the main coil wired and defined, and dont even use the hold coil, and it holds open for 8s no problem - https://github.com/bosh/trogdor-pinball/blob/ced5443103709f4388e83c667e2ff14b66cdbcf4/config/coils.yaml#L126 (running FAST Neuron latest firmware + MPF 0.80.0.dev11). Note I even have a second config on the same coil for a 15s held-open variant

Anthony van Winkle

unread,
Nov 7, 2025, 1:32:06 PM11/7/25
to MPF Users
I believe the 255ms limit on FAST is because the command accepts a two-character hex value, which runs from 00 to FF and has a maximum value of 255. Anything longer than that is not a "pulse" but a "hold", so you'll want to use an enable command rather than a pulse command.

kaydeeH

unread,
Nov 7, 2025, 2:35:09 PM11/7/25
to MPF Users
@Anthony, it's possible that a 255ms initial pulse may have been enough to get the flipper to actuate enough for the hold coil to grab it, but by the time I had discovered the nature of the limit I had already moved on. Either way, even if this is an intended and reasonable limit, the error that 2000 is an invalid int value is misleading at best and should probably still be caught and wrapped with a better error. But the fact that this limit exists when you can readily bypass it with other approaches creates inconsistency that leads to confusion and should probably still be addressed somehow, but that's just my opinion.

@Alex, the diverter option was going to be my next attempt if Phillip's suggestion hadn't worked, but since his suggestion worked, I haven't tried it at this time. Also, this is an actual flipper, not a diverter (I do get that they're mechanically virtually identical), so I don't want to make the game code more confusing by having config in the game for both a flipper and a diverter for the same device just to work around the other limitations I ran into... not if I can avoid it anyways, which I was able to do with Philip's approach.

kaydeeH

unread,
Jan 2, 2026, 8:52:51 PM (8 days ago) Jan 2
to MPF Users
Philip, while your way works, it only works when I do the same thing for the hold and main (power) coil (the hold coil alone isn't enough to get it to flip). That said, it immediately leads to the coil overheating during normal gameplay when you hold the flippers (I suspect allow_enable: true is causing the main coil to pulse at 100% duty the whole time you hold the flipper). Do you have a more complete example how you did it, involving both coils, or was the hold coil enough to trigger a flip for you? I've tried adding default_pulse_power and max_pulse_power to 0.0 in the main coil config, but that didn't seem to stop the problem. The other flippers without allow_enable: true are not overheating when you hold them.

On Wednesday, November 5, 2025 at 6:29:19 AM UTC-7 Philip Dixon wrote:

kaydeeH

unread,
Jan 2, 2026, 8:56:34 PM (8 days ago) Jan 2
to MPF Users
That was a typo... I set default_hold_power and max_hold_power to 0.0.

kaydeeH

unread,
Jan 2, 2026, 9:02:30 PM (8 days ago) Jan 2
to MPF Users
While I wait to hear back, I'm probably going to try that dual wound diverter config and see if I can get it to play nice with everything. Something eventually has to work...

kaydeeH

unread,
Jan 2, 2026, 9:56:34 PM (8 days ago) Jan 2
to MPF Users
Well I thought I had it with the dual wound coil diverter. Worked perfect in software mode as watched from the MPF Monitor. Failed to do anything in the game. Here's my full (relevant) config, and I'm not sanitizing it this time cuz I'm too frustrated to go through it, so this is the exact literal config. To better set the context, the game is essentially a constant two ball multiball that ends the turn after one ball drains but waits for the second to land in the trough as well (first ball to drain disables the flippers, which can potentially leave the second ball trapped between this flipper and other hardware with no way for the player to release it), and the goal here is just to have the software flip this flipper for 1 or 2s after a ball drain to allow a potentially trapped ball go free so it too can drain. This approach may seem like overkill, and I can probably code around it another way, but I'm going to need to figure out how to get software flips to work at some point for another problem I need to tackle down the line, so I may as well get it working here. Anywho, here's my attempt with the dual wound diverters. Am I doing something wrong?

flippers:
    purple_flipper_middle:
        main_coil: c_purple_flipper_middle_main
        hold_coil: c_purple_flipper_middle_hold
        activation_switch: s_purple_right_flipper_button
        enable_events: e_goals_active, e_fight_bell_complete
        disable_events: e_goal_scored, e_period_ended, e_monster_meter_fight_begin

coils:
    c_purple_flipper_middle_hold:
        number: 1616_2-11
        default_pulse_ms: 25
        default_hold_power: 0.7
        tags: coils
        allow_enable: true
    c_purple_flipper_middle_main:
        number: 1616_2-12
        default_pulse_ms: settings.purple_middle_flipper_pulse_time (<-- set to 21 in the settings)
        tags: coils

dual_wound_coils:
  purple_flipper_middle_dualcoil:
    main_coil: c_purple_flipper_middle_main
    hold_coil: c_purple_flipper_middle_hold

diverters:
  purple_flipper_middle_diverter:
    activation_coil: purple_flipper_middle_dualcoil
    type: hold
    activate_events: e_after_goal_common_events
    activation_time: 1s
    enable_events: mode_game_started
    disable_events: mode_game_stopped

When "e_after_goal_common_events" fires, MPF Monitor shows the diverter is enabled and active and, after 1s, it goes inactive - exactly what I want. But in the game with physical hardware, nothing happens, the flipper is motionless. This flipper works just fine when activated by the physical flipper button, and it worked using Philip's approach (or my interpretation of it anyways), except for rapidly overheating when flipping and holding normally. This is making me crazy... any help very much appreciated.

Philip Dixon

unread,
Jan 3, 2026, 11:02:25 AM (7 days ago) Jan 3
to MPF Users
I don't use the hold coil even though I am running Williams Red coils.

This is my def for the coil:

c_upperrightflippermain:          # Pulse Coil
        number: A0-B0-4             # PD0-J7-Pin 6
        default_pulse_ms: 10
        default_hold_power: 0.1
        enable_events: diverter_shooter_lane_activating
        disable_events: diverter_shooter_lane_deactivating
        label: Bank A (J5 70v) Address 0 PD0-J7-Pin 6 - Pulse Coil (24v)- Right Upper Flipper

I was using PWM but I think that got discontinued. I am using the flipper to guide the ball 

You have to appreciate that any coil held on will heat. Maybe enable both coils and then disable the pulse coil after 10ms?
To do that enable both with the same event and then set a timer that starts with the event and posts a secondary event on completion to disable the pulse coil
Finally a disable event as before to disable the hold coil.
Just a thought.

kaydeeH

unread,
Jan 3, 2026, 1:04:11 PM (7 days ago) Jan 3
to MPF Users
When I used your approach (albeit with both a power and hold coil configured) that's exactly what I did. One event fired both coils, a second event disabled the power coil after 20ms, and a third event disabled the hold coil after 2s. It worked great for the software controlled flips, and they didn't overheat from that. But something about having that allow_enable=true seemed to cause the power coil to go 100% with human-button-based flips/holds - even through the hold phase - and THAT is what was causing the overheating. That's the frustrating bit (aside from none of the "normal" approaches working), I had this working for the software side, but it seemed to break the human side by causing overheats.

At this point, I'm happy to try ignoring the hold coil and just PWM'ing the main for holds just like you did, if it still supports that. Otherwise, I think I'm just going to add an EOS switch and do it the old fashioned way, which should solve all my problems.

kaydeeH

unread,
Jan 3, 2026, 1:05:21 PM (7 days ago) Jan 3
to MPF Users
And when I say overheating, I don't mean "it's warmer", I mean it's scalding hot to the touch and causing the coil plastic to melt after just a half hour of gameplay.

Philip Dixon

unread,
Jan 4, 2026, 8:59:45 AM (6 days ago) Jan 4
to MPF Users
yeh, the EOS switch would solve a lot rather than the fliptronic route. Sometimes take the easy win!
Reply all
Reply to author
Forward
0 new messages