https://pinballmakers.com/wiki/api.php?action=feedcontributions&user=Jab&feedformat=atomPinball Makers - User contributions [en]2024-03-29T14:01:39ZUser contributionsMediaWiki 1.27.1https://pinballmakers.com/wiki/index.php?title=Programming&diff=52434Programming2019-03-17T18:12:28Z<p>Jab: /* Game Modes */</p>
<hr />
<div>After the initial [[Construction#Whitewood|whitewood]] has been built, it is time to bring it to life by programming the control system and adding game rules.<br />
<br />
== Languages ==<br />
<br />
The programming language being used is going to be dictated primarily by the hardware control system chosen. Off the shelf systems such as '''[[Construction#Off-the-Shelf_Boards|P-ROC]]''' have a close relationship to '''[http://github.com/preble/pyprocgame PyProcGame]''', which is dedicated exclusively to the P-ROC, or the '''[https://missionpinball.com/framework/ Mission Pinball Framework]''' which supports P-ROC, FAST, OPP and LISY-1 and is a higher level programming framework.<br />
<br />
For more lower-level control, there is the [http://github.com/preble/libpinproc libpinproc] library for P-ROC boards, which allow binding into other languages and building of custom frameworks using things like [http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer SDL] or [http://www.sfml-dev.org/ SFML] which provides access to ''OpenGL'' and other graphics APIs.<br />
<br />
If using custom hardware, it is up to the designer to decide on how to interface with the controller.<br />
<br />
=== Pinball Frameworks ===<br />
<br />
To make programming pinball machines easier, a number of frameworks are available to use that provide a baseline of functionality.<br />
<br />
* [https://missionpinball.org/ Mission Pinball]: Currently supports P-ROC, FAST and [[OPP|Open Pinball Project]] controllers, written in Python. Uses YAML config files to define functions. [http://docs.missionpinball.org/ Mission Pinball Documentation]<br />
* [http://pyprocgame.pindev.org/ PyProcGame]: Developed specifically for the P-ROC controllers, written in Python<br />
* [http://skeletongame.com/ SkeletonGame]: Based on PyProcGame<br />
* [https://github.com/preble/libpinproc libPinPROC]: Lower level C library for P-ROC<br />
* [http://mypinballs.co.uk/electronics/store.jsp myPinballs]: Framework written in C for developing custom games in conjunction with the myPinballs Custom Controller Board Set for early 80s Bally/Stern games. <br />
<br />
<br />
The following is a breakdown of the hardware and functionality support for the top three frameworks.<br />
<br />
{| class="wikitable" style="text-align: center;"<br />
!<br />
! Mission Pinball Framework<br />
! PyProcGame<br />
! SkeletonGame<br />
|-<br />
!Hardware<br />
| <br />
|<br />
|<br />
|-<br />
| P-ROC<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| FAST <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| OPP <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Stern SPIKE <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Gottlieb System1/80<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Displays<br />
|<br />
|<br />
|<br />
|-<br />
| LCD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| DMD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Alphanumeric<br />
| style="color: white; background-color: green;"| ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Lighting<br />
|<br />
|<br />
|<br />
|-<br />
| Incandescent<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Serial LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
! Devices<br />
|<br />
|<br />
|<br />
|-<br />
| Coils<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Motors / Servos<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
! Standard Functions<br />
|<br />
|<br />
|<br />
|-<br />
| Config File Setup<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Custom Code<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Service Menu<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
|}<br />
<br />
== Rules ==<br />
<br />
As pinball hardware advanced in complexity from simple relays to transistors, so did game rules. ''Electromechanical'' (EM) pinball machines often struggled to register multiple switch hits at the same time, while early ''Solid State'' (SS) games allowed fast response times and multiple concurrent switch hits to be registered. Faster CPUs with more memory allow for the deeper rule sets of modern pinball.<br />
<br />
Rules can be as simple as ''Complete the rollovers for bonus multiplier'' to stacking several mode-scoring multiballs together.<br />
<br />
=== Maintaining State ===<br />
<br />
Deeper rule tracking requires maintaining '''State''', which is a map (in memory) of the current switch conditions, such as:<br />
<br />
* What was the state of all the switches N seconds ago? <br />
* Has anything changed in N seconds?<br />
* How many times has a switch been hit total?<br />
<br />
<br />
These are all ''States'' and the control program keeping track of these allows for modes and other advanced rules.<br />
<br />
Think of an orbit shot: two switches, one of the left side orbit entry, one of the right side orbit entry. An orbit is complete if both switches are hit in order. It takes time for the ball to travel from one side to the other - there may be 5 seconds or more if the ball is slow, struggles to get to the apex, or dribbles down the other side. A failed orbit may count two hits to only one of the switches. It may count only one hit if the ball just makes it and rolls back down. The orbit shot is a good example of needing to know the previous switch state, the question then becomes, how many previous states to track? <br />
<br />
''Example'': If an orbit is a multiball jackpot shot, how to handle when a second ball enters the left orbit before the first ball has triggered the right orbit switch? This means an orbit that can be fed from either direction is probably not a good way to score a jackpot. This is why a ramp shot is very easy to track a jackpot on - ramps have an apex and once your past the apex, any exit switch hit from the ramp is easily countable. <br />
<br />
Another example of an advanced rule would be tracking the order of something - having five drop targets that give an extra bonus if hit in order of one to five, or five to one. This is a variable outside of standard switch state and it has to be managed outside of just target hits, as well as be reset on a ball drain, reset if a mode changes, or reset if the drop targets are reset.<br />
<br />
Code complexity is increased by remembering the state of that variable and which targets have been hit or not between changing players.<br />
<br />
The deeper rules become, the more variables, flags and timers that are needed to be tracked and managed, and the more difficult the code becomes to debug and maintain.<br />
<br />
Some other examples of maintaining state:<br />
<br />
* If a target enables a kickback, will extra kick backs be added if it is already lit?<br />
* Knowing how many balls are in the ball trough before lighting the add-a-ball insert.<br />
<br />
=== Game Logic Flow ===<br />
<br />
For an example of a typical layout of general game rules and how the logic should flow, see the [[Rule Flow]] subpage.<br />
<br />
=== Priority ===<br />
<br />
Modes, display events and sounds all need to be '''prioritized''' relative to each other - for example, background displays or sounds are a lower priority than a switch hit or score display. <br />
<br />
For example, if a high priority sound is playing, and the ball hits a switch that triggers a low priority sound effect, the control program can skip playing the lower priority sound, or play it at a lower volume. Or, if there is a display event for a pop bumper hit, it will be higher priority than the score display.<br />
<br />
== Light Shows ==<br />
<br />
With modern CPU-controlled lamps, it is possible to use general illumination, flashers and playfield insert lamps to produce '''Light Shows''' during Attract mode to bring attention to the game from a passer-by, or while the game is active to convey information to the player.<br />
<br />
For example, lighting lamps from the bottom of the playfield up to the top, then turn them off from the bottom up would be a distinct lamp show used during Attract mode. Below shows part of the attract mode for ''High Speed'' which uses multiple techniques.<br />
<br />
[[Image:high-speed-attract-mode.gif]]<br />
<br />
''Mission Pinball Framework'' supports the concept of [http://docs.missionpinball.org/en/dev/shows/index.html Light shows], which allow a maker to script what lamps are lit, for how long, and at a specific brightness to produce various effects.<br />
<br />
=== Light Groups ===<br />
<br />
Lights can be put into ''groups'' of similar lamps that allow for specific light effects. For example ''High Speed'' has the circular rev lamps, which lend themselves to a circular lamp effect, or the lamps in a row above them are well suited to a side-to-side effect.<br />
<br />
=== Backbox ===<br />
<br />
Most modern games have abandoned controlled lamps in the backbox to save on costs, but a garage maker has no such restrictions on creativity and can add various light effects to the backglass. Separating sections off to light separately is a common technique.<br />
<br />
[[Image:backbox-light-show.gif]]<br />
<br />
== Settings / Preferences ==<br />
<br />
=== Audits ===<br />
<br />
Auditing for a pinball machine involves keeping a tally of various activities, such as:<br />
<br />
* Total plays<br />
* Total balls played<br />
* Coins dropped<br />
* Replays awarded<br />
<br />
<br />
Creating audit tracking is easy, programming-wise. When a game is over, you would simply increment the "total games played" variable up by one. <br />
<br />
=== Settings ===<br />
<br />
These are values that modify the game rules. Most modern games have dozens of settings that dramatically alter game play. Some examples include:<br />
<br />
* Free Play<br />
* Balls Per Game<br />
* Replay enabled<br />
* Replay score percentage<br />
* Extra balls enabled<br />
* Ball Save enabled<br />
<br />
<br />
=== Diagnostics ===<br />
<br />
Another benefit of the switch from EM to Solid State electronics was the ability to include '''Diagnostics''' as a standard part of new games. The operator can run quick diagnostics on a machine without having to lift the playfield. Some example include:<br />
<br />
* '''Switch Test''': With the playfield glass removed, switches can be individually tested, with the number being shown on numerical scoring games, or the matrix coordinates being shown on DMD pins.<br />
* '''Sound Test''': With modern computer-based pinball machines, this test might be obsolete.<br />
* '''Coil Test''': Coils can be individually fired for checking faults, or all coils fired in order to test all coils.<br />
* '''Light Test''': Insert lights can be checked for burned out bulbs by flashing them individually.<br />
* '''Unique Mechanism Test''': This would apply to parts unique to the machine. An example would be the rotating box on ''Bally Theatre of Magic''.<br />
<br />
== Scoring ==<br />
<br />
For scoring, a separate scoring subroutine should be used and called as needed. This routine can do checks for earning game-wide rewards (points, replay) each time a player's score is incremented. Having it separate also allows for incorporating a ''double score'' mode for adding twice the amount of points without having to incorporate the mode check in each target hit routine.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
def add_score(points):<br />
game.curplayer.score = game.curplayer.score + points<br />
if curplayer.score => game.settings.replayscore:<br />
award_replay()<br />
</pre><br />
<br />
Scoring in MPF work using a variable_player: [http://docs.missionpinball.org/en/latest/game_logic/scoring/index.html]<br />
<br />
=== Bonus Lanes ===<br />
<br />
Bonus lanes are typically located at the top of the playfield, consisting of three or more lanes a ball can fall through at random. A ball falling through one of the lanes will light the lane. A bonus will be awarded, typically with a bonus multiplier (but can vary) if all the lanes are lit. <br />
<br />
Beginning with ''Williams Firepower'', hitting the flipper buttons would cycle the lit lanes left or right, allowing the player to move the unlit lane under the falling ball, achieving the bonus. Bonus lanes are frequently incorporated into the skill shot.<br />
<br />
Layout:<br />
<br />
* One switch per lane. <br />
* Each lane will have one light associated with it. Some games have two lights per lane, creating two sets of bonus lanes (Example: ''Williams Barracora''').<br />
<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
cur_bonus = 1 <br />
lane1 = off <br />
lane2 = off<br />
lane3 = off<br />
tmplane = off<br />
<br />
def switch1_hit<br />
lane1 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane1 = on<br />
<br />
def switch2_hit<br />
lane2 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane2 = on<br />
<br />
def switch3_hit<br />
lane3 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane3 = on<br />
<br />
// and the code for cycling the bonus lanes, tied to flipper button<br />
<br />
// code for checking all bonus lanes<br />
def check_all_lanes()<br />
with curplayer<br />
if (lane1 = on) + (lane2 = on) + (lane3 = on)<br />
increase_bonus()<br />
play_sound(yay_bonus!)<br />
display_msg("BONUS INCREASED")<br />
// shut off states & reset!<br />
lights.lane1 = off<br />
lights.lane2 = off<br />
lights.lane3 = off<br />
<br />
// the code for increasing the bonus multiplier <br />
// bonus held not implemented<br />
<br />
def increase_bonus()<br />
curplayer.cur_bonus = curplayer.cur_bonus + 1<br />
// give any special award if it is at a high #<br />
</pre><br />
<br />
See [http://docs.missionpinball.org/en/latest/game_logic/bonus/index.html] for MPF bonus examples.<br />
<br />
== Game Modes ==<br />
<br />
These are modes that are specific to the game in question and relate to the theme or specific special devices included in the design. They can also fall outside regular gameplay - for example, ''Bally Safecracker'' has a special ''Assault the Vault'' mode triggered by using a unique token in the coin slot. Or ''Williams Black Knight'' and ''Time Fantasy'', which have a special post-game timed mode governed by time earned in regular gameplay, where you have unlimited balls to score extra points. <br />
<br />
If you are using MPF read the [http://docs.missionpinball.org/en/latest/game_design/index.html game design] section in the documentation.<br />
<br />
=== General Modes ===<br />
<br />
These are modes that are general to most games, rather than rules specific to the machine's theme.<br />
<br />
==== Game Start ====<br />
<br />
==== Game End ====<br />
<br />
After the game ends, cleanup of the playfield device and some variables internal to the software should be done. Examples in no particular order include:<br />
<br />
* Release any locked balls from kickers<br />
* Release any locked balls from vertical upkickers<br />
* Disable flippers<br />
* Return any mechanical devices to Game Start state<br />
* Check for any high scores achieved by any players and record initials<br />
* Run Replay Match<br />
* Set number of current players to zero<br />
* Null/delete any player objects<br />
* Delete the game session object<br />
* Audits - increase # of games played, etc.<br />
<br />
==== Replay Match ====<br />
<br />
==== Ball Seek ====<br />
<br />
In the event a ball gets stuck and the player is unable to play, many machines will go into a '''Ball Seek''' mode. All mechanisms that interact with the ball will individually fire after a specified "idle" delay in an attempt to free the stuck ball. The ''Ball Seek'' mode will often run continuously until the missing ball is found, or only repeat a few times at which point the ball is marked as ''lost'' and game play continues, with the software compensating for the missing ball as best as possible.<br />
<br />
A timer is updated to check for any '''idle time''' of the ball - any switch hits (indicating ball movement) resets this timer. If no switch activity occurs for a specified period of time (as set by an operator setting), the '''Ball Seek''' subroutine would be run.<br />
<br />
Put the timer reset calls through all the switch detection events (except for shooter lane, tilt plumb, buttons) as those switch hits indicate a healthy running ball session.<br />
<br />
A ball in the shooter lane should disable the timer, with it starting after confirming a ball has been launched and is in play. For convenience sake, invoke the ball seek timer after a player has passed or failed the skill shot. So, just after shutting down the skill shot (if implemented), start the ball save timer.<br />
<br />
Shut down the ball save timer once the ball session is over. <br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// invoke the ball seeker routine<br />
def bs_timer_start()<br />
// ball saver invoked<br />
bs_timer_countdown = 60<br />
<br />
// reset the timer<br />
def bs_timer_reset()<br />
bs_timer_countdown = 60<br />
<br />
// shut down the timer entirely<br />
def bs_timer_shutdown()<br />
bs_timer_countdown = -1<br />
<br />
// this runs when the timer has expired<br />
def ball_saver()<br />
if ( bs_timer_countdown = 0 ) <br />
// fire the coils<br />
coils.popbumper1.fire()<br />
// fire drop target reset<br />
coils.dtbank1.fire()<br />
// and so forth<br />
// reset timer and hopefully we won't have to run it again<br />
bs_timer_reset()<br />
<br />
// example of the 1 of many target hits<br />
// that show the timer reset routine<br />
def leaftarget1_hit()<br />
score.addpoints(50)<br />
sound.play("boop")<br />
bs_timer_reset()<br />
</pre><br />
<br />
==== Ball Save ====<br />
<br />
'''Ball save''' is when a ball in play is drained out shortly into the ball session. This routine can be triggered via the outlanes or center drain.<br />
<br />
Typically ''Ball Save'' is either time-based or score-based. The allowed time for ball save to be active can be set via '''Preferences'''.<br />
<br />
==== Extra Ball ====<br />
<br />
==== Skill Shot ====<br />
<br />
'''Skill Shots''' are available when the player first plunges the ball. Plunging the ball at the right strength, or at the right time, or hitting a specific switch, will earn the player a reward - generally a bonus multiplier or a large points bonus.<br />
<br />
Used in conjunction with a physical plunger (as opposed to an autoplunger), plunging the ball at just the right strength to hit a specific switch will award the ''Skill Shot'' value.<br />
<br />
Some shots are ''Strength-based'', where a group of targets or switches can be hit by the ball from the plunger, and the indicated target or switch, when hit, will award the value. Of these types, variations include the '''Side''' style where the ball is aimed at targets in a vertical alignment (as in ''Williams No Good Gofers''), or '''Over''' where the ball is plunged over the switches, as shown in this example from ''Williams Pinbot'':<br />
<br />
[[Image:pinbot-skill.jpg|400px]]<br />
<br />
For games with autoplungers, there are ''Time-based'' examples where the player must time the activation of the plunger to correspond with the ball hitting a lit target - ''Williams Terminator 2'' is an example of this type. Many autoplunger games use a randomly-chosen ''Bonus Lane'', where the skill shot is achieved if the ball goes through the indicated lane at the end of a plunge. <br />
<br />
When coding, the logic is:<br />
<br />
* Initialize the skill shot mode at the begin of a ball session<br />
* End the skill shot after the player has passed or failed<br />
<br />
==== Tilt ====<br />
<br />
Although not thought of as a ''mode'', it fits the same model - it is triggered from one or multiple switch events, in this case, the switch being the tilt bob. When the tilt is triggered enough times (and after warnings issued), the game will end the current ball. <br />
<br />
A ''Tilt'' should trigger the following:<br />
<br />
* Disable Flippers<br />
* Shut off GI and any insert lights<br />
* Shut off music<br />
* Disable pop bumpers<br />
* Disable slingshots<br />
* Do not award end-of-ball bonus points<br />
<br />
Once the ball is returned the trough, regular play resumes.<br />
<br />
An additonal mode is the '''Slam Tilt''', triggered by a switch on the coin door. The main difference is that the whole game for all players will be immediately ended, as to punish the player for being rough with the machine.<br />
<br />
==== Status Report ====<br />
<br />
Generally activated by holding down both flippers.<br />
<br />
[[Status Report]]<br />
<br />
=== Device Modes ===<br />
<br />
These are general modes that trigger specific mechanical devices.<br />
<br />
==== Kickback ====<br />
<br />
See the [[Kickback]] subpage for hardware details.<br />
<br />
For the kickback, some checks will need to be done to ensure that the ball is out of the outlane area. One solution is to leave it active for a specified period of time to give an additional kickback to ensure the ball is out.<br />
<br />
Other triggers may include:<br />
<br />
* A sound or call-out indicating to the player that kickback is enabled<br />
* A sound or call-out when kickback is invoked<br />
<br />
<br />
The action to activate the kickback is to pulse the solenoid. What is critical is getting the timing correct where it does not fire too soon, or too late, where the ball will be missed. Some timing adjustments will need to be done to find the sweet spot where it will handle the most amount of ball velocity variations.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
kickback_enabled = (on/off) <br />
<br />
// scope: ball session<br />
<br />
def enable_kickback()<br />
ballsess.kickback_enabled = on<br />
lights.kb = flashy<br />
play.sound("kickback is on!")<br />
<br />
// switch hit event for the left outlane<br />
// determines if you drain or kick<br />
<br />
def leftoutlane_sw()<br />
if ballsess.kickback_enabled = on<br />
( kickback_fire() )<br />
else<br />
score.addpoints(50)<br />
sound.play("aww shucks")<br />
<br />
// fire the kickback<br />
<br />
def fire_kickback()<br />
sound.play("misspiggy hiyah!")<br />
coils.kickback.pulse()<br />
<br />
// insert any additional "keep hot" code here<br />
// okay, shut off the kickback<br />
disable_kickback()<br />
<br />
// shut off kb<br />
// also shut this off if you tilt<br />
<br />
def disable_kickback()<br />
ballsess.kickback_enabled = off<br />
lights.kb = off<br />
</pre><br />
<br />
==== Ball Trough ====<br />
<br />
See the [[Ball Trough]] subpage for hardware details.<br />
<br />
Pseudocode example:<br />
<pre><br />
<br />
// callback function<br />
// returns true if the trough is full<br />
function is_trough_full()<br />
if (trsw1 = true) + (trsw2=true) + (trsw3=true)<br />
return true<br />
else<br />
return false<br />
</pre><br />
<br />
==== Drop Targets ====<br />
<br />
See the [[Drop Targets]] subpage for hardware details.<br />
<br />
For a drop target bank, a check is needed after every drop target hit. As an example of using ''state'' to manage the game, a player could be awarded points for hitting the drop targets in order (Example: ''Bally Centaur''), or award points for completing multiple sets of drop target banks. <br />
<br />
Pseudocode:<br />
<br />
<pre><br />
// variable scope(current ball session)<br />
dbank1 = off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
def dbank1_hit()<br />
score.addpoints(50)<br />
dbank1 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank2 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank3 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
// check to see if all the drop targets have been hit<br />
<br />
def check_dropbank1()<br />
if (dbank1= on) & (dbank2=on) & (dbank3=on)<br />
// reward for completing drop target bank<br />
play_sound(chaching)<br />
score.addpoints(200)<br />
<br />
// reset the variables<br />
dbank1= off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
// reset 'em<br />
coils.dbank1.pulse()<br />
<br />
// separate routine for resetting drop target bank ,<br />
// add this to the "ball begin" routine<br />
<br />
def reset_drop_bank()<br />
coils.dbank1.pulse()<br />
</pre><br />
<br />
==== Slingshots ====<br />
<br />
See the [[Slingshots]] subpage for hardware details.<br />
<br />
Most off-the-shelf controllers allow a user to create '''Triggers''', where if a specific switch is hit, it causes a specific coil to fire. For slingshots, this is all that is needed for them to operate as expected, plus recording any scoring involved.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Kicker Hole ====<br />
<br />
See the [[Kicker Hole]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Divertors ====<br />
<br />
See the [[Divertors]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Vertical Up-Kickers ====<br />
<br />
See the [[VUK]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
== Sound ==<br />
<br />
Sound is a critical component of any pinball machine. EM games used bells and chimes to inform the player while modern games use digitized voice callouts and stereo music.<br />
<br />
Some things to consider when deciding on how to incorporate sound in a game include:<br />
<br />
* Avoid playing sounds continuously over the top of one another. For example, having an explosion sound when a pop bumper is triggered - if the ball is getting a lot of pop bumper action and it triggers three pops in very fast succession, restarting the sound event on each trigger would sound like white noise. Thus, choose not to play the same sound effect unless N time has passed (say 3 seconds), or never play the same sound affect at the same time.<br />
* Too many sound effects playing over each over mutes the effect it should have on the player and can be confusing.<br />
* Timing of sound events should be kept short, as the longer the sound, the more likely it will overlap with another switch event trigger, leading to too many overlapping sound events or the white noise problem mentioned earlier.<br />
* Normalize the volume of all the sound effects to the same level to maintain a common volume level on the machine itself. <br />
<br />
[[sound assignments]]<br />
<br />
[[Music loops]]<br />
<br />
[[Basic sounds]]<br />
<br />
[[voice callouts]]</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Programming&diff=52433Programming2019-03-17T18:09:51Z<p>Jab: /* Scoring */</p>
<hr />
<div>After the initial [[Construction#Whitewood|whitewood]] has been built, it is time to bring it to life by programming the control system and adding game rules.<br />
<br />
== Languages ==<br />
<br />
The programming language being used is going to be dictated primarily by the hardware control system chosen. Off the shelf systems such as '''[[Construction#Off-the-Shelf_Boards|P-ROC]]''' have a close relationship to '''[http://github.com/preble/pyprocgame PyProcGame]''', which is dedicated exclusively to the P-ROC, or the '''[https://missionpinball.com/framework/ Mission Pinball Framework]''' which supports P-ROC, FAST, OPP and LISY-1 and is a higher level programming framework.<br />
<br />
For more lower-level control, there is the [http://github.com/preble/libpinproc libpinproc] library for P-ROC boards, which allow binding into other languages and building of custom frameworks using things like [http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer SDL] or [http://www.sfml-dev.org/ SFML] which provides access to ''OpenGL'' and other graphics APIs.<br />
<br />
If using custom hardware, it is up to the designer to decide on how to interface with the controller.<br />
<br />
=== Pinball Frameworks ===<br />
<br />
To make programming pinball machines easier, a number of frameworks are available to use that provide a baseline of functionality.<br />
<br />
* [https://missionpinball.org/ Mission Pinball]: Currently supports P-ROC, FAST and [[OPP|Open Pinball Project]] controllers, written in Python. Uses YAML config files to define functions. [http://docs.missionpinball.org/ Mission Pinball Documentation]<br />
* [http://pyprocgame.pindev.org/ PyProcGame]: Developed specifically for the P-ROC controllers, written in Python<br />
* [http://skeletongame.com/ SkeletonGame]: Based on PyProcGame<br />
* [https://github.com/preble/libpinproc libPinPROC]: Lower level C library for P-ROC<br />
* [http://mypinballs.co.uk/electronics/store.jsp myPinballs]: Framework written in C for developing custom games in conjunction with the myPinballs Custom Controller Board Set for early 80s Bally/Stern games. <br />
<br />
<br />
The following is a breakdown of the hardware and functionality support for the top three frameworks.<br />
<br />
{| class="wikitable" style="text-align: center;"<br />
!<br />
! Mission Pinball Framework<br />
! PyProcGame<br />
! SkeletonGame<br />
|-<br />
!Hardware<br />
| <br />
|<br />
|<br />
|-<br />
| P-ROC<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| FAST <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| OPP <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Stern SPIKE <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Gottlieb System1/80<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Displays<br />
|<br />
|<br />
|<br />
|-<br />
| LCD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| DMD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Alphanumeric<br />
| style="color: white; background-color: green;"| ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Lighting<br />
|<br />
|<br />
|<br />
|-<br />
| Incandescent<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Serial LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
! Devices<br />
|<br />
|<br />
|<br />
|-<br />
| Coils<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Motors / Servos<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
! Standard Functions<br />
|<br />
|<br />
|<br />
|-<br />
| Config File Setup<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Custom Code<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Service Menu<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
|}<br />
<br />
== Rules ==<br />
<br />
As pinball hardware advanced in complexity from simple relays to transistors, so did game rules. ''Electromechanical'' (EM) pinball machines often struggled to register multiple switch hits at the same time, while early ''Solid State'' (SS) games allowed fast response times and multiple concurrent switch hits to be registered. Faster CPUs with more memory allow for the deeper rule sets of modern pinball.<br />
<br />
Rules can be as simple as ''Complete the rollovers for bonus multiplier'' to stacking several mode-scoring multiballs together.<br />
<br />
=== Maintaining State ===<br />
<br />
Deeper rule tracking requires maintaining '''State''', which is a map (in memory) of the current switch conditions, such as:<br />
<br />
* What was the state of all the switches N seconds ago? <br />
* Has anything changed in N seconds?<br />
* How many times has a switch been hit total?<br />
<br />
<br />
These are all ''States'' and the control program keeping track of these allows for modes and other advanced rules.<br />
<br />
Think of an orbit shot: two switches, one of the left side orbit entry, one of the right side orbit entry. An orbit is complete if both switches are hit in order. It takes time for the ball to travel from one side to the other - there may be 5 seconds or more if the ball is slow, struggles to get to the apex, or dribbles down the other side. A failed orbit may count two hits to only one of the switches. It may count only one hit if the ball just makes it and rolls back down. The orbit shot is a good example of needing to know the previous switch state, the question then becomes, how many previous states to track? <br />
<br />
''Example'': If an orbit is a multiball jackpot shot, how to handle when a second ball enters the left orbit before the first ball has triggered the right orbit switch? This means an orbit that can be fed from either direction is probably not a good way to score a jackpot. This is why a ramp shot is very easy to track a jackpot on - ramps have an apex and once your past the apex, any exit switch hit from the ramp is easily countable. <br />
<br />
Another example of an advanced rule would be tracking the order of something - having five drop targets that give an extra bonus if hit in order of one to five, or five to one. This is a variable outside of standard switch state and it has to be managed outside of just target hits, as well as be reset on a ball drain, reset if a mode changes, or reset if the drop targets are reset.<br />
<br />
Code complexity is increased by remembering the state of that variable and which targets have been hit or not between changing players.<br />
<br />
The deeper rules become, the more variables, flags and timers that are needed to be tracked and managed, and the more difficult the code becomes to debug and maintain.<br />
<br />
Some other examples of maintaining state:<br />
<br />
* If a target enables a kickback, will extra kick backs be added if it is already lit?<br />
* Knowing how many balls are in the ball trough before lighting the add-a-ball insert.<br />
<br />
=== Game Logic Flow ===<br />
<br />
For an example of a typical layout of general game rules and how the logic should flow, see the [[Rule Flow]] subpage.<br />
<br />
=== Priority ===<br />
<br />
Modes, display events and sounds all need to be '''prioritized''' relative to each other - for example, background displays or sounds are a lower priority than a switch hit or score display. <br />
<br />
For example, if a high priority sound is playing, and the ball hits a switch that triggers a low priority sound effect, the control program can skip playing the lower priority sound, or play it at a lower volume. Or, if there is a display event for a pop bumper hit, it will be higher priority than the score display.<br />
<br />
== Light Shows ==<br />
<br />
With modern CPU-controlled lamps, it is possible to use general illumination, flashers and playfield insert lamps to produce '''Light Shows''' during Attract mode to bring attention to the game from a passer-by, or while the game is active to convey information to the player.<br />
<br />
For example, lighting lamps from the bottom of the playfield up to the top, then turn them off from the bottom up would be a distinct lamp show used during Attract mode. Below shows part of the attract mode for ''High Speed'' which uses multiple techniques.<br />
<br />
[[Image:high-speed-attract-mode.gif]]<br />
<br />
''Mission Pinball Framework'' supports the concept of [http://docs.missionpinball.org/en/dev/shows/index.html Light shows], which allow a maker to script what lamps are lit, for how long, and at a specific brightness to produce various effects.<br />
<br />
=== Light Groups ===<br />
<br />
Lights can be put into ''groups'' of similar lamps that allow for specific light effects. For example ''High Speed'' has the circular rev lamps, which lend themselves to a circular lamp effect, or the lamps in a row above them are well suited to a side-to-side effect.<br />
<br />
=== Backbox ===<br />
<br />
Most modern games have abandoned controlled lamps in the backbox to save on costs, but a garage maker has no such restrictions on creativity and can add various light effects to the backglass. Separating sections off to light separately is a common technique.<br />
<br />
[[Image:backbox-light-show.gif]]<br />
<br />
== Settings / Preferences ==<br />
<br />
=== Audits ===<br />
<br />
Auditing for a pinball machine involves keeping a tally of various activities, such as:<br />
<br />
* Total plays<br />
* Total balls played<br />
* Coins dropped<br />
* Replays awarded<br />
<br />
<br />
Creating audit tracking is easy, programming-wise. When a game is over, you would simply increment the "total games played" variable up by one. <br />
<br />
=== Settings ===<br />
<br />
These are values that modify the game rules. Most modern games have dozens of settings that dramatically alter game play. Some examples include:<br />
<br />
* Free Play<br />
* Balls Per Game<br />
* Replay enabled<br />
* Replay score percentage<br />
* Extra balls enabled<br />
* Ball Save enabled<br />
<br />
<br />
=== Diagnostics ===<br />
<br />
Another benefit of the switch from EM to Solid State electronics was the ability to include '''Diagnostics''' as a standard part of new games. The operator can run quick diagnostics on a machine without having to lift the playfield. Some example include:<br />
<br />
* '''Switch Test''': With the playfield glass removed, switches can be individually tested, with the number being shown on numerical scoring games, or the matrix coordinates being shown on DMD pins.<br />
* '''Sound Test''': With modern computer-based pinball machines, this test might be obsolete.<br />
* '''Coil Test''': Coils can be individually fired for checking faults, or all coils fired in order to test all coils.<br />
* '''Light Test''': Insert lights can be checked for burned out bulbs by flashing them individually.<br />
* '''Unique Mechanism Test''': This would apply to parts unique to the machine. An example would be the rotating box on ''Bally Theatre of Magic''.<br />
<br />
== Scoring ==<br />
<br />
For scoring, a separate scoring subroutine should be used and called as needed. This routine can do checks for earning game-wide rewards (points, replay) each time a player's score is incremented. Having it separate also allows for incorporating a ''double score'' mode for adding twice the amount of points without having to incorporate the mode check in each target hit routine.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
def add_score(points):<br />
game.curplayer.score = game.curplayer.score + points<br />
if curplayer.score => game.settings.replayscore:<br />
award_replay()<br />
</pre><br />
<br />
Scoring in MPF work using a variable_player: [http://docs.missionpinball.org/en/latest/game_logic/scoring/index.html]<br />
<br />
=== Bonus Lanes ===<br />
<br />
Bonus lanes are typically located at the top of the playfield, consisting of three or more lanes a ball can fall through at random. A ball falling through one of the lanes will light the lane. A bonus will be awarded, typically with a bonus multiplier (but can vary) if all the lanes are lit. <br />
<br />
Beginning with ''Williams Firepower'', hitting the flipper buttons would cycle the lit lanes left or right, allowing the player to move the unlit lane under the falling ball, achieving the bonus. Bonus lanes are frequently incorporated into the skill shot.<br />
<br />
Layout:<br />
<br />
* One switch per lane. <br />
* Each lane will have one light associated with it. Some games have two lights per lane, creating two sets of bonus lanes (Example: ''Williams Barracora''').<br />
<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
cur_bonus = 1 <br />
lane1 = off <br />
lane2 = off<br />
lane3 = off<br />
tmplane = off<br />
<br />
def switch1_hit<br />
lane1 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane1 = on<br />
<br />
def switch2_hit<br />
lane2 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane2 = on<br />
<br />
def switch3_hit<br />
lane3 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane3 = on<br />
<br />
// and the code for cycling the bonus lanes, tied to flipper button<br />
<br />
// code for checking all bonus lanes<br />
def check_all_lanes()<br />
with curplayer<br />
if (lane1 = on) + (lane2 = on) + (lane3 = on)<br />
increase_bonus()<br />
play_sound(yay_bonus!)<br />
display_msg("BONUS INCREASED")<br />
// shut off states & reset!<br />
lights.lane1 = off<br />
lights.lane2 = off<br />
lights.lane3 = off<br />
<br />
// the code for increasing the bonus multiplier <br />
// bonus held not implemented<br />
<br />
def increase_bonus()<br />
curplayer.cur_bonus = curplayer.cur_bonus + 1<br />
// give any special award if it is at a high #<br />
</pre><br />
<br />
See [http://docs.missionpinball.org/en/latest/game_logic/bonus/index.html] for MPF bonus examples.<br />
<br />
== Game Modes ==<br />
<br />
These are modes that are specific to the game in question and relate to the theme or specific special devices included in the design. They can also fall outside regular gameplay - for example, ''Bally Safecracker'' has a special ''Assault the Vault'' mode triggered by using a unique token in the coin slot. Or ''Williams Black Knight'' and ''Time Fantasy'', which have a special post-game timed mode governed by time earned in regular gameplay, where you have unlimited balls to score extra points. <br />
<br />
=== General Modes ===<br />
<br />
These are modes that are general to most games, rather than rules specific to the machine's theme.<br />
<br />
==== Game Start ====<br />
<br />
==== Game End ====<br />
<br />
After the game ends, cleanup of the playfield device and some variables internal to the software should be done. Examples in no particular order include:<br />
<br />
* Release any locked balls from kickers<br />
* Release any locked balls from vertical upkickers<br />
* Disable flippers<br />
* Return any mechanical devices to Game Start state<br />
* Check for any high scores achieved by any players and record initials<br />
* Run Replay Match<br />
* Set number of current players to zero<br />
* Null/delete any player objects<br />
* Delete the game session object<br />
* Audits - increase # of games played, etc.<br />
<br />
==== Replay Match ====<br />
<br />
==== Ball Seek ====<br />
<br />
In the event a ball gets stuck and the player is unable to play, many machines will go into a '''Ball Seek''' mode. All mechanisms that interact with the ball will individually fire after a specified "idle" delay in an attempt to free the stuck ball. The ''Ball Seek'' mode will often run continuously until the missing ball is found, or only repeat a few times at which point the ball is marked as ''lost'' and game play continues, with the software compensating for the missing ball as best as possible.<br />
<br />
A timer is updated to check for any '''idle time''' of the ball - any switch hits (indicating ball movement) resets this timer. If no switch activity occurs for a specified period of time (as set by an operator setting), the '''Ball Seek''' subroutine would be run.<br />
<br />
Put the timer reset calls through all the switch detection events (except for shooter lane, tilt plumb, buttons) as those switch hits indicate a healthy running ball session.<br />
<br />
A ball in the shooter lane should disable the timer, with it starting after confirming a ball has been launched and is in play. For convenience sake, invoke the ball seek timer after a player has passed or failed the skill shot. So, just after shutting down the skill shot (if implemented), start the ball save timer.<br />
<br />
Shut down the ball save timer once the ball session is over. <br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// invoke the ball seeker routine<br />
def bs_timer_start()<br />
// ball saver invoked<br />
bs_timer_countdown = 60<br />
<br />
// reset the timer<br />
def bs_timer_reset()<br />
bs_timer_countdown = 60<br />
<br />
// shut down the timer entirely<br />
def bs_timer_shutdown()<br />
bs_timer_countdown = -1<br />
<br />
// this runs when the timer has expired<br />
def ball_saver()<br />
if ( bs_timer_countdown = 0 ) <br />
// fire the coils<br />
coils.popbumper1.fire()<br />
// fire drop target reset<br />
coils.dtbank1.fire()<br />
// and so forth<br />
// reset timer and hopefully we won't have to run it again<br />
bs_timer_reset()<br />
<br />
// example of the 1 of many target hits<br />
// that show the timer reset routine<br />
def leaftarget1_hit()<br />
score.addpoints(50)<br />
sound.play("boop")<br />
bs_timer_reset()<br />
</pre><br />
<br />
==== Ball Save ====<br />
<br />
'''Ball save''' is when a ball in play is drained out shortly into the ball session. This routine can be triggered via the outlanes or center drain.<br />
<br />
Typically ''Ball Save'' is either time-based or score-based. The allowed time for ball save to be active can be set via '''Preferences'''.<br />
<br />
==== Extra Ball ====<br />
<br />
==== Skill Shot ====<br />
<br />
'''Skill Shots''' are available when the player first plunges the ball. Plunging the ball at the right strength, or at the right time, or hitting a specific switch, will earn the player a reward - generally a bonus multiplier or a large points bonus.<br />
<br />
Used in conjunction with a physical plunger (as opposed to an autoplunger), plunging the ball at just the right strength to hit a specific switch will award the ''Skill Shot'' value.<br />
<br />
Some shots are ''Strength-based'', where a group of targets or switches can be hit by the ball from the plunger, and the indicated target or switch, when hit, will award the value. Of these types, variations include the '''Side''' style where the ball is aimed at targets in a vertical alignment (as in ''Williams No Good Gofers''), or '''Over''' where the ball is plunged over the switches, as shown in this example from ''Williams Pinbot'':<br />
<br />
[[Image:pinbot-skill.jpg|400px]]<br />
<br />
For games with autoplungers, there are ''Time-based'' examples where the player must time the activation of the plunger to correspond with the ball hitting a lit target - ''Williams Terminator 2'' is an example of this type. Many autoplunger games use a randomly-chosen ''Bonus Lane'', where the skill shot is achieved if the ball goes through the indicated lane at the end of a plunge. <br />
<br />
When coding, the logic is:<br />
<br />
* Initialize the skill shot mode at the begin of a ball session<br />
* End the skill shot after the player has passed or failed<br />
<br />
==== Tilt ====<br />
<br />
Although not thought of as a ''mode'', it fits the same model - it is triggered from one or multiple switch events, in this case, the switch being the tilt bob. When the tilt is triggered enough times (and after warnings issued), the game will end the current ball. <br />
<br />
A ''Tilt'' should trigger the following:<br />
<br />
* Disable Flippers<br />
* Shut off GI and any insert lights<br />
* Shut off music<br />
* Disable pop bumpers<br />
* Disable slingshots<br />
* Do not award end-of-ball bonus points<br />
<br />
Once the ball is returned the trough, regular play resumes.<br />
<br />
An additonal mode is the '''Slam Tilt''', triggered by a switch on the coin door. The main difference is that the whole game for all players will be immediately ended, as to punish the player for being rough with the machine.<br />
<br />
==== Status Report ====<br />
<br />
Generally activated by holding down both flippers.<br />
<br />
[[Status Report]]<br />
<br />
=== Device Modes ===<br />
<br />
These are general modes that trigger specific mechanical devices.<br />
<br />
==== Kickback ====<br />
<br />
See the [[Kickback]] subpage for hardware details.<br />
<br />
For the kickback, some checks will need to be done to ensure that the ball is out of the outlane area. One solution is to leave it active for a specified period of time to give an additional kickback to ensure the ball is out.<br />
<br />
Other triggers may include:<br />
<br />
* A sound or call-out indicating to the player that kickback is enabled<br />
* A sound or call-out when kickback is invoked<br />
<br />
<br />
The action to activate the kickback is to pulse the solenoid. What is critical is getting the timing correct where it does not fire too soon, or too late, where the ball will be missed. Some timing adjustments will need to be done to find the sweet spot where it will handle the most amount of ball velocity variations.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
kickback_enabled = (on/off) <br />
<br />
// scope: ball session<br />
<br />
def enable_kickback()<br />
ballsess.kickback_enabled = on<br />
lights.kb = flashy<br />
play.sound("kickback is on!")<br />
<br />
// switch hit event for the left outlane<br />
// determines if you drain or kick<br />
<br />
def leftoutlane_sw()<br />
if ballsess.kickback_enabled = on<br />
( kickback_fire() )<br />
else<br />
score.addpoints(50)<br />
sound.play("aww shucks")<br />
<br />
// fire the kickback<br />
<br />
def fire_kickback()<br />
sound.play("misspiggy hiyah!")<br />
coils.kickback.pulse()<br />
<br />
// insert any additional "keep hot" code here<br />
// okay, shut off the kickback<br />
disable_kickback()<br />
<br />
// shut off kb<br />
// also shut this off if you tilt<br />
<br />
def disable_kickback()<br />
ballsess.kickback_enabled = off<br />
lights.kb = off<br />
</pre><br />
<br />
==== Ball Trough ====<br />
<br />
See the [[Ball Trough]] subpage for hardware details.<br />
<br />
Pseudocode example:<br />
<pre><br />
<br />
// callback function<br />
// returns true if the trough is full<br />
function is_trough_full()<br />
if (trsw1 = true) + (trsw2=true) + (trsw3=true)<br />
return true<br />
else<br />
return false<br />
</pre><br />
<br />
==== Drop Targets ====<br />
<br />
See the [[Drop Targets]] subpage for hardware details.<br />
<br />
For a drop target bank, a check is needed after every drop target hit. As an example of using ''state'' to manage the game, a player could be awarded points for hitting the drop targets in order (Example: ''Bally Centaur''), or award points for completing multiple sets of drop target banks. <br />
<br />
Pseudocode:<br />
<br />
<pre><br />
// variable scope(current ball session)<br />
dbank1 = off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
def dbank1_hit()<br />
score.addpoints(50)<br />
dbank1 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank2 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank3 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
// check to see if all the drop targets have been hit<br />
<br />
def check_dropbank1()<br />
if (dbank1= on) & (dbank2=on) & (dbank3=on)<br />
// reward for completing drop target bank<br />
play_sound(chaching)<br />
score.addpoints(200)<br />
<br />
// reset the variables<br />
dbank1= off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
// reset 'em<br />
coils.dbank1.pulse()<br />
<br />
// separate routine for resetting drop target bank ,<br />
// add this to the "ball begin" routine<br />
<br />
def reset_drop_bank()<br />
coils.dbank1.pulse()<br />
</pre><br />
<br />
==== Slingshots ====<br />
<br />
See the [[Slingshots]] subpage for hardware details.<br />
<br />
Most off-the-shelf controllers allow a user to create '''Triggers''', where if a specific switch is hit, it causes a specific coil to fire. For slingshots, this is all that is needed for them to operate as expected, plus recording any scoring involved.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Kicker Hole ====<br />
<br />
See the [[Kicker Hole]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Divertors ====<br />
<br />
See the [[Divertors]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Vertical Up-Kickers ====<br />
<br />
See the [[VUK]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
== Sound ==<br />
<br />
Sound is a critical component of any pinball machine. EM games used bells and chimes to inform the player while modern games use digitized voice callouts and stereo music.<br />
<br />
Some things to consider when deciding on how to incorporate sound in a game include:<br />
<br />
* Avoid playing sounds continuously over the top of one another. For example, having an explosion sound when a pop bumper is triggered - if the ball is getting a lot of pop bumper action and it triggers three pops in very fast succession, restarting the sound event on each trigger would sound like white noise. Thus, choose not to play the same sound effect unless N time has passed (say 3 seconds), or never play the same sound affect at the same time.<br />
* Too many sound effects playing over each over mutes the effect it should have on the player and can be confusing.<br />
* Timing of sound events should be kept short, as the longer the sound, the more likely it will overlap with another switch event trigger, leading to too many overlapping sound events or the white noise problem mentioned earlier.<br />
* Normalize the volume of all the sound effects to the same level to maintain a common volume level on the machine itself. <br />
<br />
[[sound assignments]]<br />
<br />
[[Music loops]]<br />
<br />
[[Basic sounds]]<br />
<br />
[[voice callouts]]</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Programming&diff=52432Programming2019-03-17T18:07:25Z<p>Jab: Fix link to MPF light shows</p>
<hr />
<div>After the initial [[Construction#Whitewood|whitewood]] has been built, it is time to bring it to life by programming the control system and adding game rules.<br />
<br />
== Languages ==<br />
<br />
The programming language being used is going to be dictated primarily by the hardware control system chosen. Off the shelf systems such as '''[[Construction#Off-the-Shelf_Boards|P-ROC]]''' have a close relationship to '''[http://github.com/preble/pyprocgame PyProcGame]''', which is dedicated exclusively to the P-ROC, or the '''[https://missionpinball.com/framework/ Mission Pinball Framework]''' which supports P-ROC, FAST, OPP and LISY-1 and is a higher level programming framework.<br />
<br />
For more lower-level control, there is the [http://github.com/preble/libpinproc libpinproc] library for P-ROC boards, which allow binding into other languages and building of custom frameworks using things like [http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer SDL] or [http://www.sfml-dev.org/ SFML] which provides access to ''OpenGL'' and other graphics APIs.<br />
<br />
If using custom hardware, it is up to the designer to decide on how to interface with the controller.<br />
<br />
=== Pinball Frameworks ===<br />
<br />
To make programming pinball machines easier, a number of frameworks are available to use that provide a baseline of functionality.<br />
<br />
* [https://missionpinball.org/ Mission Pinball]: Currently supports P-ROC, FAST and [[OPP|Open Pinball Project]] controllers, written in Python. Uses YAML config files to define functions. [http://docs.missionpinball.org/ Mission Pinball Documentation]<br />
* [http://pyprocgame.pindev.org/ PyProcGame]: Developed specifically for the P-ROC controllers, written in Python<br />
* [http://skeletongame.com/ SkeletonGame]: Based on PyProcGame<br />
* [https://github.com/preble/libpinproc libPinPROC]: Lower level C library for P-ROC<br />
* [http://mypinballs.co.uk/electronics/store.jsp myPinballs]: Framework written in C for developing custom games in conjunction with the myPinballs Custom Controller Board Set for early 80s Bally/Stern games. <br />
<br />
<br />
The following is a breakdown of the hardware and functionality support for the top three frameworks.<br />
<br />
{| class="wikitable" style="text-align: center;"<br />
!<br />
! Mission Pinball Framework<br />
! PyProcGame<br />
! SkeletonGame<br />
|-<br />
!Hardware<br />
| <br />
|<br />
|<br />
|-<br />
| P-ROC<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| FAST <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| OPP <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Stern SPIKE <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Gottlieb System1/80<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Displays<br />
|<br />
|<br />
|<br />
|-<br />
| LCD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| DMD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Alphanumeric<br />
| style="color: white; background-color: green;"| ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Lighting<br />
|<br />
|<br />
|<br />
|-<br />
| Incandescent<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Serial LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
! Devices<br />
|<br />
|<br />
|<br />
|-<br />
| Coils<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Motors / Servos<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
! Standard Functions<br />
|<br />
|<br />
|<br />
|-<br />
| Config File Setup<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Custom Code<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Service Menu<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
|}<br />
<br />
== Rules ==<br />
<br />
As pinball hardware advanced in complexity from simple relays to transistors, so did game rules. ''Electromechanical'' (EM) pinball machines often struggled to register multiple switch hits at the same time, while early ''Solid State'' (SS) games allowed fast response times and multiple concurrent switch hits to be registered. Faster CPUs with more memory allow for the deeper rule sets of modern pinball.<br />
<br />
Rules can be as simple as ''Complete the rollovers for bonus multiplier'' to stacking several mode-scoring multiballs together.<br />
<br />
=== Maintaining State ===<br />
<br />
Deeper rule tracking requires maintaining '''State''', which is a map (in memory) of the current switch conditions, such as:<br />
<br />
* What was the state of all the switches N seconds ago? <br />
* Has anything changed in N seconds?<br />
* How many times has a switch been hit total?<br />
<br />
<br />
These are all ''States'' and the control program keeping track of these allows for modes and other advanced rules.<br />
<br />
Think of an orbit shot: two switches, one of the left side orbit entry, one of the right side orbit entry. An orbit is complete if both switches are hit in order. It takes time for the ball to travel from one side to the other - there may be 5 seconds or more if the ball is slow, struggles to get to the apex, or dribbles down the other side. A failed orbit may count two hits to only one of the switches. It may count only one hit if the ball just makes it and rolls back down. The orbit shot is a good example of needing to know the previous switch state, the question then becomes, how many previous states to track? <br />
<br />
''Example'': If an orbit is a multiball jackpot shot, how to handle when a second ball enters the left orbit before the first ball has triggered the right orbit switch? This means an orbit that can be fed from either direction is probably not a good way to score a jackpot. This is why a ramp shot is very easy to track a jackpot on - ramps have an apex and once your past the apex, any exit switch hit from the ramp is easily countable. <br />
<br />
Another example of an advanced rule would be tracking the order of something - having five drop targets that give an extra bonus if hit in order of one to five, or five to one. This is a variable outside of standard switch state and it has to be managed outside of just target hits, as well as be reset on a ball drain, reset if a mode changes, or reset if the drop targets are reset.<br />
<br />
Code complexity is increased by remembering the state of that variable and which targets have been hit or not between changing players.<br />
<br />
The deeper rules become, the more variables, flags and timers that are needed to be tracked and managed, and the more difficult the code becomes to debug and maintain.<br />
<br />
Some other examples of maintaining state:<br />
<br />
* If a target enables a kickback, will extra kick backs be added if it is already lit?<br />
* Knowing how many balls are in the ball trough before lighting the add-a-ball insert.<br />
<br />
=== Game Logic Flow ===<br />
<br />
For an example of a typical layout of general game rules and how the logic should flow, see the [[Rule Flow]] subpage.<br />
<br />
=== Priority ===<br />
<br />
Modes, display events and sounds all need to be '''prioritized''' relative to each other - for example, background displays or sounds are a lower priority than a switch hit or score display. <br />
<br />
For example, if a high priority sound is playing, and the ball hits a switch that triggers a low priority sound effect, the control program can skip playing the lower priority sound, or play it at a lower volume. Or, if there is a display event for a pop bumper hit, it will be higher priority than the score display.<br />
<br />
== Light Shows ==<br />
<br />
With modern CPU-controlled lamps, it is possible to use general illumination, flashers and playfield insert lamps to produce '''Light Shows''' during Attract mode to bring attention to the game from a passer-by, or while the game is active to convey information to the player.<br />
<br />
For example, lighting lamps from the bottom of the playfield up to the top, then turn them off from the bottom up would be a distinct lamp show used during Attract mode. Below shows part of the attract mode for ''High Speed'' which uses multiple techniques.<br />
<br />
[[Image:high-speed-attract-mode.gif]]<br />
<br />
''Mission Pinball Framework'' supports the concept of [http://docs.missionpinball.org/en/dev/shows/index.html Light shows], which allow a maker to script what lamps are lit, for how long, and at a specific brightness to produce various effects.<br />
<br />
=== Light Groups ===<br />
<br />
Lights can be put into ''groups'' of similar lamps that allow for specific light effects. For example ''High Speed'' has the circular rev lamps, which lend themselves to a circular lamp effect, or the lamps in a row above them are well suited to a side-to-side effect.<br />
<br />
=== Backbox ===<br />
<br />
Most modern games have abandoned controlled lamps in the backbox to save on costs, but a garage maker has no such restrictions on creativity and can add various light effects to the backglass. Separating sections off to light separately is a common technique.<br />
<br />
[[Image:backbox-light-show.gif]]<br />
<br />
== Settings / Preferences ==<br />
<br />
=== Audits ===<br />
<br />
Auditing for a pinball machine involves keeping a tally of various activities, such as:<br />
<br />
* Total plays<br />
* Total balls played<br />
* Coins dropped<br />
* Replays awarded<br />
<br />
<br />
Creating audit tracking is easy, programming-wise. When a game is over, you would simply increment the "total games played" variable up by one. <br />
<br />
=== Settings ===<br />
<br />
These are values that modify the game rules. Most modern games have dozens of settings that dramatically alter game play. Some examples include:<br />
<br />
* Free Play<br />
* Balls Per Game<br />
* Replay enabled<br />
* Replay score percentage<br />
* Extra balls enabled<br />
* Ball Save enabled<br />
<br />
<br />
=== Diagnostics ===<br />
<br />
Another benefit of the switch from EM to Solid State electronics was the ability to include '''Diagnostics''' as a standard part of new games. The operator can run quick diagnostics on a machine without having to lift the playfield. Some example include:<br />
<br />
* '''Switch Test''': With the playfield glass removed, switches can be individually tested, with the number being shown on numerical scoring games, or the matrix coordinates being shown on DMD pins.<br />
* '''Sound Test''': With modern computer-based pinball machines, this test might be obsolete.<br />
* '''Coil Test''': Coils can be individually fired for checking faults, or all coils fired in order to test all coils.<br />
* '''Light Test''': Insert lights can be checked for burned out bulbs by flashing them individually.<br />
* '''Unique Mechanism Test''': This would apply to parts unique to the machine. An example would be the rotating box on ''Bally Theatre of Magic''.<br />
<br />
== Scoring ==<br />
<br />
For scoring, a separate scoring subroutine should be used and called as needed. This routine can do checks for earning game-wide rewards (points, replay) each time a player's score is incremented. Having it separate also allows for incorporating a ''double score'' mode for adding twice the amount of points without having to incorporate the mode check in each target hit routine.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
def add_score(points):<br />
game.curplayer.score = game.curplayer.score + points<br />
if curplayer.score => game.settings.replayscore:<br />
award_replay()<br />
</pre><br />
<br />
=== Bonus Lanes ===<br />
<br />
Bonus lanes are typically located at the top of the playfield, consisting of three or more lanes a ball can fall through at random. A ball falling through one of the lanes will light the lane. A bonus will be awarded, typically with a bonus multiplier (but can vary) if all the lanes are lit. <br />
<br />
Beginning with ''Williams Firepower'', hitting the flipper buttons would cycle the lit lanes left or right, allowing the player to move the unlit lane under the falling ball, achieving the bonus. Bonus lanes are frequently incorporated into the skill shot.<br />
<br />
Layout:<br />
<br />
* One switch per lane. <br />
* Each lane will have one light associated with it. Some games have two lights per lane, creating two sets of bonus lanes (Example: ''Williams Barracora''').<br />
<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
cur_bonus = 1 <br />
lane1 = off <br />
lane2 = off<br />
lane3 = off<br />
tmplane = off<br />
<br />
def switch1_hit<br />
lane1 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane1 = on<br />
<br />
def switch2_hit<br />
lane2 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane2 = on<br />
<br />
def switch3_hit<br />
lane3 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane3 = on<br />
<br />
// and the code for cycling the bonus lanes, tied to flipper button<br />
<br />
// code for checking all bonus lanes<br />
def check_all_lanes()<br />
with curplayer<br />
if (lane1 = on) + (lane2 = on) + (lane3 = on)<br />
increase_bonus()<br />
play_sound(yay_bonus!)<br />
display_msg("BONUS INCREASED")<br />
// shut off states & reset!<br />
lights.lane1 = off<br />
lights.lane2 = off<br />
lights.lane3 = off<br />
<br />
// the code for increasing the bonus multiplier <br />
// bonus held not implemented<br />
<br />
def increase_bonus()<br />
curplayer.cur_bonus = curplayer.cur_bonus + 1<br />
// give any special award if it is at a high #<br />
</pre><br />
<br />
== Game Modes ==<br />
<br />
These are modes that are specific to the game in question and relate to the theme or specific special devices included in the design. They can also fall outside regular gameplay - for example, ''Bally Safecracker'' has a special ''Assault the Vault'' mode triggered by using a unique token in the coin slot. Or ''Williams Black Knight'' and ''Time Fantasy'', which have a special post-game timed mode governed by time earned in regular gameplay, where you have unlimited balls to score extra points. <br />
<br />
=== General Modes ===<br />
<br />
These are modes that are general to most games, rather than rules specific to the machine's theme.<br />
<br />
==== Game Start ====<br />
<br />
==== Game End ====<br />
<br />
After the game ends, cleanup of the playfield device and some variables internal to the software should be done. Examples in no particular order include:<br />
<br />
* Release any locked balls from kickers<br />
* Release any locked balls from vertical upkickers<br />
* Disable flippers<br />
* Return any mechanical devices to Game Start state<br />
* Check for any high scores achieved by any players and record initials<br />
* Run Replay Match<br />
* Set number of current players to zero<br />
* Null/delete any player objects<br />
* Delete the game session object<br />
* Audits - increase # of games played, etc.<br />
<br />
==== Replay Match ====<br />
<br />
==== Ball Seek ====<br />
<br />
In the event a ball gets stuck and the player is unable to play, many machines will go into a '''Ball Seek''' mode. All mechanisms that interact with the ball will individually fire after a specified "idle" delay in an attempt to free the stuck ball. The ''Ball Seek'' mode will often run continuously until the missing ball is found, or only repeat a few times at which point the ball is marked as ''lost'' and game play continues, with the software compensating for the missing ball as best as possible.<br />
<br />
A timer is updated to check for any '''idle time''' of the ball - any switch hits (indicating ball movement) resets this timer. If no switch activity occurs for a specified period of time (as set by an operator setting), the '''Ball Seek''' subroutine would be run.<br />
<br />
Put the timer reset calls through all the switch detection events (except for shooter lane, tilt plumb, buttons) as those switch hits indicate a healthy running ball session.<br />
<br />
A ball in the shooter lane should disable the timer, with it starting after confirming a ball has been launched and is in play. For convenience sake, invoke the ball seek timer after a player has passed or failed the skill shot. So, just after shutting down the skill shot (if implemented), start the ball save timer.<br />
<br />
Shut down the ball save timer once the ball session is over. <br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// invoke the ball seeker routine<br />
def bs_timer_start()<br />
// ball saver invoked<br />
bs_timer_countdown = 60<br />
<br />
// reset the timer<br />
def bs_timer_reset()<br />
bs_timer_countdown = 60<br />
<br />
// shut down the timer entirely<br />
def bs_timer_shutdown()<br />
bs_timer_countdown = -1<br />
<br />
// this runs when the timer has expired<br />
def ball_saver()<br />
if ( bs_timer_countdown = 0 ) <br />
// fire the coils<br />
coils.popbumper1.fire()<br />
// fire drop target reset<br />
coils.dtbank1.fire()<br />
// and so forth<br />
// reset timer and hopefully we won't have to run it again<br />
bs_timer_reset()<br />
<br />
// example of the 1 of many target hits<br />
// that show the timer reset routine<br />
def leaftarget1_hit()<br />
score.addpoints(50)<br />
sound.play("boop")<br />
bs_timer_reset()<br />
</pre><br />
<br />
==== Ball Save ====<br />
<br />
'''Ball save''' is when a ball in play is drained out shortly into the ball session. This routine can be triggered via the outlanes or center drain.<br />
<br />
Typically ''Ball Save'' is either time-based or score-based. The allowed time for ball save to be active can be set via '''Preferences'''.<br />
<br />
==== Extra Ball ====<br />
<br />
==== Skill Shot ====<br />
<br />
'''Skill Shots''' are available when the player first plunges the ball. Plunging the ball at the right strength, or at the right time, or hitting a specific switch, will earn the player a reward - generally a bonus multiplier or a large points bonus.<br />
<br />
Used in conjunction with a physical plunger (as opposed to an autoplunger), plunging the ball at just the right strength to hit a specific switch will award the ''Skill Shot'' value.<br />
<br />
Some shots are ''Strength-based'', where a group of targets or switches can be hit by the ball from the plunger, and the indicated target or switch, when hit, will award the value. Of these types, variations include the '''Side''' style where the ball is aimed at targets in a vertical alignment (as in ''Williams No Good Gofers''), or '''Over''' where the ball is plunged over the switches, as shown in this example from ''Williams Pinbot'':<br />
<br />
[[Image:pinbot-skill.jpg|400px]]<br />
<br />
For games with autoplungers, there are ''Time-based'' examples where the player must time the activation of the plunger to correspond with the ball hitting a lit target - ''Williams Terminator 2'' is an example of this type. Many autoplunger games use a randomly-chosen ''Bonus Lane'', where the skill shot is achieved if the ball goes through the indicated lane at the end of a plunge. <br />
<br />
When coding, the logic is:<br />
<br />
* Initialize the skill shot mode at the begin of a ball session<br />
* End the skill shot after the player has passed or failed<br />
<br />
==== Tilt ====<br />
<br />
Although not thought of as a ''mode'', it fits the same model - it is triggered from one or multiple switch events, in this case, the switch being the tilt bob. When the tilt is triggered enough times (and after warnings issued), the game will end the current ball. <br />
<br />
A ''Tilt'' should trigger the following:<br />
<br />
* Disable Flippers<br />
* Shut off GI and any insert lights<br />
* Shut off music<br />
* Disable pop bumpers<br />
* Disable slingshots<br />
* Do not award end-of-ball bonus points<br />
<br />
Once the ball is returned the trough, regular play resumes.<br />
<br />
An additonal mode is the '''Slam Tilt''', triggered by a switch on the coin door. The main difference is that the whole game for all players will be immediately ended, as to punish the player for being rough with the machine.<br />
<br />
==== Status Report ====<br />
<br />
Generally activated by holding down both flippers.<br />
<br />
[[Status Report]]<br />
<br />
=== Device Modes ===<br />
<br />
These are general modes that trigger specific mechanical devices.<br />
<br />
==== Kickback ====<br />
<br />
See the [[Kickback]] subpage for hardware details.<br />
<br />
For the kickback, some checks will need to be done to ensure that the ball is out of the outlane area. One solution is to leave it active for a specified period of time to give an additional kickback to ensure the ball is out.<br />
<br />
Other triggers may include:<br />
<br />
* A sound or call-out indicating to the player that kickback is enabled<br />
* A sound or call-out when kickback is invoked<br />
<br />
<br />
The action to activate the kickback is to pulse the solenoid. What is critical is getting the timing correct where it does not fire too soon, or too late, where the ball will be missed. Some timing adjustments will need to be done to find the sweet spot where it will handle the most amount of ball velocity variations.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
kickback_enabled = (on/off) <br />
<br />
// scope: ball session<br />
<br />
def enable_kickback()<br />
ballsess.kickback_enabled = on<br />
lights.kb = flashy<br />
play.sound("kickback is on!")<br />
<br />
// switch hit event for the left outlane<br />
// determines if you drain or kick<br />
<br />
def leftoutlane_sw()<br />
if ballsess.kickback_enabled = on<br />
( kickback_fire() )<br />
else<br />
score.addpoints(50)<br />
sound.play("aww shucks")<br />
<br />
// fire the kickback<br />
<br />
def fire_kickback()<br />
sound.play("misspiggy hiyah!")<br />
coils.kickback.pulse()<br />
<br />
// insert any additional "keep hot" code here<br />
// okay, shut off the kickback<br />
disable_kickback()<br />
<br />
// shut off kb<br />
// also shut this off if you tilt<br />
<br />
def disable_kickback()<br />
ballsess.kickback_enabled = off<br />
lights.kb = off<br />
</pre><br />
<br />
==== Ball Trough ====<br />
<br />
See the [[Ball Trough]] subpage for hardware details.<br />
<br />
Pseudocode example:<br />
<pre><br />
<br />
// callback function<br />
// returns true if the trough is full<br />
function is_trough_full()<br />
if (trsw1 = true) + (trsw2=true) + (trsw3=true)<br />
return true<br />
else<br />
return false<br />
</pre><br />
<br />
==== Drop Targets ====<br />
<br />
See the [[Drop Targets]] subpage for hardware details.<br />
<br />
For a drop target bank, a check is needed after every drop target hit. As an example of using ''state'' to manage the game, a player could be awarded points for hitting the drop targets in order (Example: ''Bally Centaur''), or award points for completing multiple sets of drop target banks. <br />
<br />
Pseudocode:<br />
<br />
<pre><br />
// variable scope(current ball session)<br />
dbank1 = off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
def dbank1_hit()<br />
score.addpoints(50)<br />
dbank1 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank2 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank3 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
// check to see if all the drop targets have been hit<br />
<br />
def check_dropbank1()<br />
if (dbank1= on) & (dbank2=on) & (dbank3=on)<br />
// reward for completing drop target bank<br />
play_sound(chaching)<br />
score.addpoints(200)<br />
<br />
// reset the variables<br />
dbank1= off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
// reset 'em<br />
coils.dbank1.pulse()<br />
<br />
// separate routine for resetting drop target bank ,<br />
// add this to the "ball begin" routine<br />
<br />
def reset_drop_bank()<br />
coils.dbank1.pulse()<br />
</pre><br />
<br />
==== Slingshots ====<br />
<br />
See the [[Slingshots]] subpage for hardware details.<br />
<br />
Most off-the-shelf controllers allow a user to create '''Triggers''', where if a specific switch is hit, it causes a specific coil to fire. For slingshots, this is all that is needed for them to operate as expected, plus recording any scoring involved.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Kicker Hole ====<br />
<br />
See the [[Kicker Hole]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Divertors ====<br />
<br />
See the [[Divertors]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Vertical Up-Kickers ====<br />
<br />
See the [[VUK]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
== Sound ==<br />
<br />
Sound is a critical component of any pinball machine. EM games used bells and chimes to inform the player while modern games use digitized voice callouts and stereo music.<br />
<br />
Some things to consider when deciding on how to incorporate sound in a game include:<br />
<br />
* Avoid playing sounds continuously over the top of one another. For example, having an explosion sound when a pop bumper is triggered - if the ball is getting a lot of pop bumper action and it triggers three pops in very fast succession, restarting the sound event on each trigger would sound like white noise. Thus, choose not to play the same sound effect unless N time has passed (say 3 seconds), or never play the same sound affect at the same time.<br />
* Too many sound effects playing over each over mutes the effect it should have on the player and can be confusing.<br />
* Timing of sound events should be kept short, as the longer the sound, the more likely it will overlap with another switch event trigger, leading to too many overlapping sound events or the white noise problem mentioned earlier.<br />
* Normalize the volume of all the sound effects to the same level to maintain a common volume level on the machine itself. <br />
<br />
[[sound assignments]]<br />
<br />
[[Music loops]]<br />
<br />
[[Basic sounds]]<br />
<br />
[[voice callouts]]</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Fast&diff=52340Fast2018-07-07T15:00:57Z<p>Jab: /* Drivers */</p>
<hr />
<div>= Architecture =<br />
Fast Pinball offers a [http://fastpinball.com/platform/hardware pinball control systems] which consists of a controller and multiple node boards. There is currently only one controller available. It is called the [http://fastpinball.com/platform/hardware/controllers/fast-nano-controller Nano]. It supports a chain of node boards and 128 serial RGB LEDs.<br />
<br />
The following node boards are available:<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-3208 Fast IO 3208] - 32 inputs and 8 drivers<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-1616 Fast IO 1616] - 16 inputs and 16 drivers<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-0804 Fast IO 0804] - 8 inputs and 4 drivers<br />
<br />
Most machines use a 3208 for the lower playfield. The 0804 is often used as cabinet node. Upper playfield configurations differ.<br />
<br />
Node boards are connected in a Ring using RJ45 cables. Nano connects to the first board (ID 0). First board to the second and so on. Last board connects back to the Nano.<br />
<br />
== Controller ==<br />
<br />
[[File:FAST_Nano.png]]<br />
[[File:FAST_Nano_Wiring.png]]<br />
<br />
== Node boards ==<br />
<br />
[[File:FAST_0804.png]]<br />
[[File:FAST_1616.png]]<br />
[[File:FAST_3208.png]]<br />
<br />
= Switches =<br />
Switches are organized in banks of 8. They pull the voltage to 12V using an internal pull up. If you connect an switch input to ground the switch will be considered closed. You can connect normal pinball switches and optos directly to inputs.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/switches.html How to configure switches in FAST with MPF].<br />
<br />
= Drivers =<br />
Boards contain drivers in banks of 8 (except the 0804 which contains a bank of only 4 drivers). All drivers pull to ground. Connect your mechs to high voltage (HV) and connect the other side to a driver. When the driver is activated the current will flow.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/drivers.html How to configure switches in FAST with MPF].<br />
<br />
= Flipper rules =<br />
Fast supports only node local rules which means that switch and driver have to be on the same board. <br />
For instance if the switch of a popbumper is connected to switch 2 on node board 1 then the coil also has to be connected to an output on node board 1. The first 8 switches on the first board (ID 0) are special since those are local to every node board. E.g. you can connect your flipper buttons to inputs 0 and 1 on the first node board (as cabinet node board) and connect the drivers to node 2 below the playfield.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/hw_rules.html How to configure hardware rules with MPF and FAST].<br />
<br />
= DMDs =<br />
Fast offers a standalone RGB DMD display which interfaces via USB.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/rgb_dmd.html How to configure FAST DMD with MPF].<br />
<br />
= Special hardware =<br />
All Fast node board support one daughter board.<br />
Currently there is a servo daughter board for six servos.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Fast&diff=52339Fast2018-07-07T15:00:41Z<p>Jab: typos</p>
<hr />
<div>= Architecture =<br />
Fast Pinball offers a [http://fastpinball.com/platform/hardware pinball control systems] which consists of a controller and multiple node boards. There is currently only one controller available. It is called the [http://fastpinball.com/platform/hardware/controllers/fast-nano-controller Nano]. It supports a chain of node boards and 128 serial RGB LEDs.<br />
<br />
The following node boards are available:<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-3208 Fast IO 3208] - 32 inputs and 8 drivers<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-1616 Fast IO 1616] - 16 inputs and 16 drivers<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-0804 Fast IO 0804] - 8 inputs and 4 drivers<br />
<br />
Most machines use a 3208 for the lower playfield. The 0804 is often used as cabinet node. Upper playfield configurations differ.<br />
<br />
Node boards are connected in a Ring using RJ45 cables. Nano connects to the first board (ID 0). First board to the second and so on. Last board connects back to the Nano.<br />
<br />
== Controller ==<br />
<br />
[[File:FAST_Nano.png]]<br />
[[File:FAST_Nano_Wiring.png]]<br />
<br />
== Node boards ==<br />
<br />
[[File:FAST_0804.png]]<br />
[[File:FAST_1616.png]]<br />
[[File:FAST_3208.png]]<br />
<br />
= Switches =<br />
Switches are organized in banks of 8. They pull the voltage to 12V using an internal pull up. If you connect an switch input to ground the switch will be considered closed. You can connect normal pinball switches and optos directly to inputs.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/switches.html How to configure switches in FAST with MPF].<br />
<br />
= Drivers =<br />
Boards contain drivers in banks of 8 (except the 0804 which contains a bank of only 4 drivers). All drivers pull to ground. Connect your mechs to high voltage (HV) and connect the other side to a driver. When the driver is activated the current will flow.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/drivers.html How to configure switch in FAST with MPF].<br />
<br />
= Flipper rules =<br />
Fast supports only node local rules which means that switch and driver have to be on the same board. <br />
For instance if the switch of a popbumper is connected to switch 2 on node board 1 then the coil also has to be connected to an output on node board 1. The first 8 switches on the first board (ID 0) are special since those are local to every node board. E.g. you can connect your flipper buttons to inputs 0 and 1 on the first node board (as cabinet node board) and connect the drivers to node 2 below the playfield.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/hw_rules.html How to configure hardware rules with MPF and FAST].<br />
<br />
= DMDs =<br />
Fast offers a standalone RGB DMD display which interfaces via USB.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/rgb_dmd.html How to configure FAST DMD with MPF].<br />
<br />
= Special hardware =<br />
All Fast node board support one daughter board.<br />
Currently there is a servo daughter board for six servos.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Fast&diff=52338Fast2018-05-27T12:15:20Z<p>Jab: add images and links to mpf</p>
<hr />
<div>= Architecture =<br />
Fast Pinball offers a [http://fastpinball.com/platform/hardware pinball control systems] which consists of a controller and multiple node boards. There is currently only one controller available. It is called the [http://fastpinball.com/platform/hardware/controllers/fast-nano-controller Nano] and supports a chain of node boards and 128 serial RGB LEDs.<br />
<br />
The following node boards are available:<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-3208 Fast IO 3208] - 32 inputs and 8 drivers<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-1616 Fast IO 1616] - 16 inputs and 16 drivers<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-0804 Fast IO 0804] - 8 inputs and 4 drivers<br />
<br />
Most machines use a 3208 for the lower playfield. The 0804 is often used as cabinet node. Upper playfield configurations differ.<br />
<br />
Node boards are connected in a Ring using RJ45 cables. Nano connects to the first board (ID 0). First board to the second and so on. Last board connects back to the Nano.<br />
<br />
== Controller ==<br />
<br />
[[File:FAST_Nano.png]]<br />
[[File:FAST_Nano_Wiring.png]]<br />
<br />
== Node boards ==<br />
<br />
[[File:FAST_0804.png]]<br />
[[File:FAST_1616.png]]<br />
[[File:FAST_3208.png]]<br />
<br />
= Switches =<br />
Switches are organized in banks of 8. They contain pull up the voltage to 12V using an internal pull up. If you connect an switch input to ground the switch will be considered closed. You can connect normal pinball switches and optos directly to inputs.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/switches.html How to configure switch in FAST with MPF].<br />
<br />
= Drivers =<br />
Boards contain drivers in banks of 8 (except the 0804 which contains a bank of only 4 drivers). All drivers pull to ground. Connect your mechs to high voltage (HV) and connect the other side to a driver. When the driver is activated the current will flow.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/drivers.html How to configure switch in FAST with MPF].<br />
<br />
= Flipper rules =<br />
Fast supports only node local rules which means that switch and driver have to be on the same board. <br />
For instance if the switch of a popbumper is connected to switch 2 on node board 1 then the coil also has to be connected to an output on node board 1. The first 8 switches on the first board (ID 0) are special since those are local to every node board. E.g. you can connect your flipper buttons to inputs 0 and 1 on the first node board (as cabinet node board) and connect the drivers to node 2 below the playfield.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/hw_rules.html How to configure hardware rules with MPF and FAST].<br />
<br />
= DMDs =<br />
Fast offers a standalone RGB DMD display which interfaces via USB.<br />
See [http://docs.missionpinball.org/en/latest/hardware/fast/rgb_dmd.html How to configure FAST DMD with MPF].<br />
<br />
= Special hardware =<br />
All Fast node board support one daughter board.<br />
Currently there is a servo daughter board for six servos.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=File:FAST_3208.png&diff=52337File:FAST 3208.png2018-05-27T12:11:03Z<p>Jab: </p>
<hr />
<div></div>Jabhttps://pinballmakers.com/wiki/index.php?title=File:FAST_1616.png&diff=52336File:FAST 1616.png2018-05-27T12:10:51Z<p>Jab: </p>
<hr />
<div></div>Jabhttps://pinballmakers.com/wiki/index.php?title=File:FAST_0804.png&diff=52335File:FAST 0804.png2018-05-27T12:10:19Z<p>Jab: </p>
<hr />
<div></div>Jabhttps://pinballmakers.com/wiki/index.php?title=File:FAST_Nano.png&diff=52334File:FAST Nano.png2018-05-27T12:08:20Z<p>Jab: </p>
<hr />
<div></div>Jabhttps://pinballmakers.com/wiki/index.php?title=File:FAST_Nano_Wiring.png&diff=52333File:FAST Nano Wiring.png2018-05-27T12:07:12Z<p>Jab: </p>
<hr />
<div></div>Jabhttps://pinballmakers.com/wiki/index.php?title=Basics&diff=52296Basics2018-05-07T22:50:43Z<p>Jab: /* Direct versus Serial */</p>
<hr />
<div>'''Pinball Makers''' is focused primarily on providing practical, real world information for the creation of pinball machines from scratch, but there is a large segment of people who are interested in building a game but do not have experience with the basic components involved inside a pinball. This section is meant to help those people understand the basics of what makes up a pinball machine in terms of the mechanical parts and electronics.<br />
<br />
= Mechanical =<br />
<br />
Although every pinball machine is different, the basic principle is that a steel ball rolls on a wooden surface, interacting with switches and mechanical devices that either passive (such as rubber bumpers) or active (flippers, slingshots), and information is passed to the player via lights and displays. Ultimately, most pinball mechanisms can be broken down into three devices: '''Coils''' (or solenoids), '''Lamps''' (incandescent or LED) and '''Switches'''. Additionally, there are '''Electromagnets''' and '''Motors''' but they are related to coils since they all use magnetism as their motive force.<br />
<br />
Here is a diagram showing some of the devices you will find in most pinball machines.<br />
<br />
[[File:playfield-diagram.png|Playfield Devices]]<br />
<br />
== Mechanism Types ==<br />
<br />
From the top:<br />
<br />
* '''Rollover''': A switch located on the underside of the playfield that is triggered when a ball rolls over it. They can be slot switches, or star rollovers, or even inductive switches you cannot see from the topside.<br />
* '''Spinner''': The ball hitting the flat part of the spinner causes it to spin in place, activating a switch for each turn.<br />
* '''Scoop''': A ball enters from the top of the playfield to under the playfield. At that point it may enter a '''Subway''' and travel to a different part of the playfield, or it may simply rest in place to be ejected back out, similar to a '''Saucer'''.<br />
* '''Drop Target''': When hit by the ball, it drops down into the playfield so that it cannot be hit again, usually exposing other targets or ball paths behind. They come in singles, banks of multiples, and can sometimes be computer controlled to drop without player interaction.<br />
* '''Standups''': These are switches that sit above the playfield and are activated by the ball.<br />
* '''Pop Bumper''': A device that detects a ball nearby via the plastic ring on the bottom that fires a coil and drops a ring to propel the ball in the opposite direction.<br />
* '''Inserts''': Clear or coloured plastic disks or other shapes that have lights - either incandescent or LED - underneath that are controlled by the game electronics.<br />
* '''Slingshot''': A mechanism comprising one or two standup switches (without plastic shields) and a kicker mechanism that when activated by the ball, kicks out in a single direction.<br />
* '''Flipper''': A player controlled bat that propels the ball in multiple directions.<br />
* '''Trough''': The storage tray that holds all the balls used in the game that receives the ball and serves it to the shooter lane as needed.<br />
<br />
= Electrical =<br />
<br />
With the mechanisms covered, there needs to be a way to connect them all together and control them. That is where the electrical wiring and circuit boards come in. The following is a diagram of the underside of the same playfield in the diagram above with all the same mechanisms highlighted.<br />
<br />
[[File:playfield-underside.png|Playfield Underside]]<br />
<br />
Looking at the photo with the massive number of wires and connectors, it might seem daunting to understand it all, but all wiring can be broken down into three distinct harnesses - '''Coils''', '''Lamps''' and '''Switches''', just like the devices themselves. There will be specific wiring for all three types.<br />
<br />
== Wiring ==<br />
<br />
The details about what kind of wire, what thickness, and where to get it is covered in the Construction article under [[Construction#Wiring|Wiring]] . For this section the discussion is about the basics of wiring and how it connects together.<br />
<br />
=== Power ===<br />
<br />
At the heart of the system is a power supply, separated into '''Low''' and '''High''' current types. The ''low'' current supply would be for running the computer - say 5 volts or 12 volts - while the ''high'' current supply is for driving the coils. The reason there need to be multiple voltages and current capacities is because each device has different load characteristics. A computer can run on low current 5 volts (or even 3.3 volts) because it runs at ''transistor-to-transistor level'', or '''TTL''', which is fine for logic and other functions. On the other end, the ''high'' current supply - running 24-70 volts - is needed for coils, as creating magnetic fields uses a lot of current.<br />
<br />
Older games used '''Linear''' power supplies, where all the voltages needed for a game were stepped down from 110VAC/220VAC using a ''transformer'', then converted to DC power. Linear power supplies are extremely inefficient and produce a lot of waste heat, and are subject to changing voltage fluctuations depending on power quality. "Weak Flippers" on older games can often be attributed to this issue.<br />
<br />
Modern games use '''Switching''' power supplies, which are more efficient and deliver a set voltage regardless of minor fluctuations. However, the readily available units are generally only made to produce a single voltage and as such, most modern games - and thus, custom machines - will have multiple power supplies to handle the different requirements. Some typical ones are:<br />
<br />
* '''5V''': Used for logic-level devices like computers and electronics. USB, for example, is a 5V connector.<br />
* '''12V''': Used for switch matrices and LED light strips. <br />
* '''50V''': Used for coils, motors and other high current devices.<br />
<br />
=== Coils ===<br />
<br />
Coils (or ''solenoids'') are just giant spools of wire around a non-conductive plastic tube. When electricity is applied to each end of the wire, a magnetic field is produced. <br />
<br />
[[File:coil-basics.png|Basic operation of a coil]]<br />
<br />
The strength of that field depends on the wire thickness, length and voltage used. Single-wound coils - ones with two connectors - do not have a polarity and can be hooked up in any direction. This magnetic field can be then used to impart movement on a metal plunger that slides inside the plastic tube. In pinball, that plunger is connected to things like flippers, slingshots, pop bumper rings, and so on, in order to impart that kinetic energy to the pinball in the game.<br />
<br />
[[File:Coil.jpg|Typical Single-Wound Pinball Coil]]<br />
<br />
Coils are generally connected using a '''Ground Sink''' method, where one connector of the coil is attached to the ''positive'' lead of the high current power supply and the other connector goes to the controller board, where it attaches to a transistor, and when that transistor is activated by the game, the ''negative'' (ground) lead of the power supply is connected inside the transistor, allowing current to flow through the connected coil, which generates the magnetic field. It is done this way to lower the current load on the transistor.<br />
<br />
For an example of this wiring, here is the wiring diagram for the ''Open Pinball Project'' solenoid wing.<br />
<br />
[[File:Solenoid-wiring.png|Solenoid wiring for Open Pinball Project]]<br />
<br />
It shows a number of different devices but the key connections are between the high current power supply, the board, and the coils, showing how the ''negative'' lead of the power supply goes to the board, while the ''positive'' goes directly to the coil.<br />
<br />
For ''P-ROC'', the connection method is slightly different, in that voltages and ground are connected from the board instead of from the power supplies separately, as per this diagram.<br />
<br />
[[File:pd16-diagram.png|PD-16 wiring diagram]]<br />
<br />
==== Diode ====<br />
<br />
Depending on your controller, you may or may not need a '''Diode''' connecting the two leads on your coils. The reason for this diode is that when a coil's magnetic field collapses when power is stopped, it produces an in-rush of current in the opposite direction - a '''Flyback''' voltage. The diode is there to shunt that back into the coil to avoid damaging the transistors. <br />
<br />
''P-ROC'' and ''FAST'' controllers do not need them as they have built-in flyback protection, while ''OPP'' and other original manufacturer boards do require external diodes. Make sure to confirm the need for diodes prior to wiring a game.<br />
<br />
=== Lamps ===<br />
<br />
Lamps could be incandescent, and thus work similarly to how coils work, with similar wiring. However all modern games have moved to LED lighting which comes in two types - '''direct wired''' or '''serial chain'''. <br />
<br />
==== Direct Wired LEDs ====<br />
<br />
''Direct wired'' LEDs are driven individually. The [https://www.multimorphic.com/store/circuit-boards/pd-led PD-LED] works - can drive up to 84 single color LEDs or 28 RGB LEDs, for example.<br />
<br />
The below diagram shows how to connect an LED to the PD-LED.<br />
<br />
[[File:pw-led-hookup.png|PD-LED Connection Example]]<br />
<br />
<br />
There are a number of options for under playfield mounting of LEDs, such as the [https://www.multimorphic.com/store/circuit-boards/rgb-led/ Multimorphic RGB LED board] or the [https://www.pinballlife.com/index.php?p=product&id=4942 Pinball Life RGB LED].<br />
<br />
[[File:multi-led-board.png|Multimorphic RGB LED]] [[File:pbl-led-board.jpg|Pinball Life RGB LED]]<br />
<br />
==== Serial Chain LEDs ====<br />
<br />
[[File:serial-led.png|String of WS281x RGB LEDs]]<br />
<br />
''Serial Chain'' LEDs are LEDs that are daisy-chained together and use a serial protocol to accept commands to light up and are usually full colour '''RGB''' (red/green/blue). This means they can be programmed to light any colour.<br />
<br />
They use a four-wire hookup - '''Power''' plus '''TX''' (Transmit) and '''RX''' (Receive). Very simply, you send commands via the '''Serial Protocol''' to say ''"Lamp 5, turn Red"'', and the command is sent down the line until the fifth lamp sees it and turns red.<br />
<br />
[[File:daisy-chain-led.jpg|Example of a daisy-chained LED string]]<br />
<br />
Thanks to modern pinball frameworks, all this low-level signalling is handled for you, so they can be labelled and addressed almost as simply as explained above.<br />
<br />
==== Direct versus Serial ====<br />
<br />
At first glance, serial LEDs would seem to have a big advantage over direct LEDs as the packing and wiring is much simpler, and overall are much cheaper as RGB LED strings are available for pennies per light on eBay and Aliexpress. However, they have two important drawbacks:<br />
<br />
* '''Susceptible to interference''': The underside of a pinball machine is a very ''noisy'' place in terms of EM emissions due to all the coils and mechs. As such, it can interfere with the serial communications, making lights not work, or light the wrong colour.<br />
* '''Slower response time''': Since the serial commands need to be sent from one light to the next in series versus in parallel for the direct LEDs, often the lights can be a bit slower to react to commands and cause issues with a complex lightshow.<br />
<br />
For this reason, it's recommended to use direct LEDs ''under'' the playfield, while you can use limited strings of serial LEDs ''above'' the playfield. However, some manufacturer (notable Stern and JJP) exclusively use serial LEDs in their newer machines (2013 and newer). They probably do that because of lower costs and reduced wiring. Admittedly, JJP had problems with that in their first machine (WoZ).<br />
<br />
[[File:fadecandy.png|FadeCandy from AdaFruit]]<br />
<br />
One option for controlling serial LEDs is the [https://www.adafruit.com/product/1689 FadeCandy], which can control up to '''eight LED chains''' (with 64 LEDs each for a total of 512 LEDs) via the USB interface and is natively supported by [https://missionpinball.org/ MPF]. It can update them at up to 400Hz and provides temporal dithering and smooth hardware fades.<br />
<br />
The PD-LED can also drive ''both'' types of LEDs: '''Connector J8''' is designated for serial LEDs specifically and can drive up to '''six LED chains'''.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Basics&diff=52287Basics2018-05-07T22:06:34Z<p>Jab: fadecandy details</p>
<hr />
<div>'''Pinball Makers''' is focused primarily on providing practical, real world information for the creation of pinball machines from scratch, but there is a large segment of people who are interested in building a game but do not have experience with the basic components involved inside a pinball. This section is meant to help those people understand the basics of what makes up a pinball machine in terms of the mechanical parts and electronics.<br />
<br />
= Mechanical =<br />
<br />
Although every pinball machine is different, the basic principle is that a steel ball rolls on a wooden surface, interacting with switches and mechanical devices that either passive (such as rubber bumpers) or active (flippers, slingshots), and information is passed to the player via lights and displays. Ultimately, most pinball mechanisms can be broken down into three devices: '''Coils''' (or solenoids), '''Lamps''' (incandescent or LED) and '''Switches'''. Additionally, there are '''Electromagnets''' and '''Motors''' but they are related to coils since they all use magnetism as their motive force.<br />
<br />
Here is a diagram showing some of the devices you will find in most pinball machines.<br />
<br />
[[File:playfield-diagram.png|Playfield Devices]]<br />
<br />
== Mechanism Types ==<br />
<br />
From the top:<br />
<br />
* '''Rollover''': A switch located on the underside of the playfield that is triggered when a ball rolls over it. They can be slot switches, or star rollovers, or even inductive switches you cannot see from the topside.<br />
* '''Spinner''': The ball hitting the flat part of the spinner causes it to spin in place, activating a switch for each turn.<br />
* '''Scoop''': A ball enters from the top of the playfield to under the playfield. At that point it may enter a '''Subway''' and travel to a different part of the playfield, or it may simply rest in place to be ejected back out, similar to a '''Saucer'''.<br />
* '''Drop Target''': When hit by the ball, it drops down into the playfield so that it cannot be hit again, usually exposing other targets or ball paths behind. They come in singles, banks of multiples, and can sometimes be computer controlled to drop without player interaction.<br />
* '''Standups''': These are switches that sit above the playfield and are activated by the ball.<br />
* '''Pop Bumper''': A device that detects a ball nearby via the plastic ring on the bottom that fires a coil and drops a ring to propel the ball in the opposite direction.<br />
* '''Inserts''': Clear or coloured plastic disks or other shapes that have lights - either incandescent or LED - underneath that are controlled by the game electronics.<br />
* '''Slingshot''': A mechanism comprising one or two standup switches (without plastic shields) and a kicker mechanism that when activated by the ball, kicks out in a single direction.<br />
* '''Flipper''': A player controlled bat that propels the ball in multiple directions.<br />
* '''Trough''': The storage tray that holds all the balls used in the game that receives the ball and serves it to the shooter lane as needed.<br />
<br />
= Electrical =<br />
<br />
With the mechanisms covered, there needs to be a way to connect them all together and control them. That is where the electrical wiring and circuit boards come in. The following is a diagram of the underside of the same playfield in the diagram above with all the same mechanisms highlighted.<br />
<br />
[[File:playfield-underside.png|Playfield Underside]]<br />
<br />
Looking at the photo with the massive number of wires and connectors, it might seem daunting to understand it all, but all wiring can be broken down into three distinct harnesses - '''Coils''', '''Lamps''' and '''Switches''', just like the devices themselves. There will be specific wiring for all three types.<br />
<br />
== Wiring ==<br />
<br />
The details about what kind of wire, what thickness, and where to get it is covered in the Construction article under [[Construction#Wiring|Wiring]] . For this section the discussion is about the basics of wiring and how it connects together.<br />
<br />
=== Power ===<br />
<br />
At the heart of the system is a power supply, separated into '''Low''' and '''High''' current types. The ''low'' current supply would be for running the computer - say 5 volts or 12 volts - while the ''high'' current supply is for driving the coils. The reason there need to be multiple voltages and current capacities is because each device has different load characteristics. A computer can run on low current 5 volts (or even 3.3 volts) because it runs at ''transistor-to-transistor level'', or '''TTL''', which is fine for logic and other functions. On the other end, the ''high'' current supply - running 24-70 volts - is needed for coils, as creating magnetic fields uses a lot of current.<br />
<br />
Older games used '''Linear''' power supplies, where all the voltages needed for a game were stepped down from 110VAC/220VAC using a ''transformer'', then converted to DC power. Linear power supplies are extremely inefficient and produce a lot of waste heat, and are subject to changing voltage fluctuations depending on power quality. "Weak Flippers" on older games can often be attributed to this issue.<br />
<br />
Modern games use '''Switching''' power supplies, which are more efficient and deliver a set voltage regardless of minor fluctuations. However, the readily available units are generally only made to produce a single voltage and as such, most modern games - and thus, custom machines - will have multiple power supplies to handle the different requirements. Some typical ones are:<br />
<br />
* '''5V''': Used for logic-level devices like computers and electronics. USB, for example, is a 5V connector.<br />
* '''12V''': Used for switch matrices and LED light strips. <br />
* '''50V''': Used for coils, motors and other high current devices.<br />
<br />
=== Coils ===<br />
<br />
Coils (or ''solenoids'') are just giant spools of wire around a non-conductive plastic tube. When electricity is applied to each end of the wire, a magnetic field is produced. <br />
<br />
[[File:coil-basics.png|Basic operation of a coil]]<br />
<br />
The strength of that field depends on the wire thickness, length and voltage used. Single-wound coils - ones with two connectors - do not have a polarity and can be hooked up in any direction. This magnetic field can be then used to impart movement on a metal plunger that slides inside the plastic tube. In pinball, that plunger is connected to things like flippers, slingshots, pop bumper rings, and so on, in order to impart that kinetic energy to the pinball in the game.<br />
<br />
[[File:Coil.jpg|Typical Single-Wound Pinball Coil]]<br />
<br />
Coils are generally connected using a '''Ground Sink''' method, where one connector of the coil is attached to the ''positive'' lead of the high current power supply and the other connector goes to the controller board, where it attaches to a transistor, and when that transistor is activated by the game, the ''negative'' (ground) lead of the power supply is connected inside the transistor, allowing current to flow through the connected coil, which generates the magnetic field. It is done this way to lower the current load on the transistor.<br />
<br />
For an example of this wiring, here is the wiring diagram for the ''Open Pinball Project'' solenoid wing.<br />
<br />
[[File:Solenoid-wiring.png|Solenoid wiring for Open Pinball Project]]<br />
<br />
It shows a number of different devices but the key connections are between the high current power supply, the board, and the coils, showing how the ''negative'' lead of the power supply goes to the board, while the ''positive'' goes directly to the coil.<br />
<br />
For ''P-ROC'', the connection method is slightly different, in that voltages and ground are connected from the board instead of from the power supplies separately, as per this diagram.<br />
<br />
[[File:pd16-diagram.png|PD-16 wiring diagram]]<br />
<br />
==== Diode ====<br />
<br />
Depending on your controller, you may or may not need a '''Diode''' connecting the two leads on your coils. The reason for this diode is that when a coil's magnetic field collapses when power is stopped, it produces an in-rush of current in the opposite direction - a '''Flyback''' voltage. The diode is there to shunt that back into the coil to avoid damaging the transistors. <br />
<br />
''P-ROC'' and ''FAST'' controllers do not need them as they have built-in flyback protection, while ''OPP'' and other original manufacturer boards do require external diodes. Make sure to confirm the need for diodes prior to wiring a game.<br />
<br />
=== Lamps ===<br />
<br />
Lamps could be incandescent, and thus work similarly to how coils work, with similar wiring. However all modern games have moved to LED lighting which comes in two types - '''direct wired''' or '''serial chain'''. <br />
<br />
==== Direct Wired LEDs ====<br />
<br />
''Direct wired'' LEDs are driven individually. This is how the [https://www.multimorphic.com/store/circuit-boards/pd-led PD-LED] works - it can drive up to 84 single color LEDs or 28 RGB LEDs.<br />
<br />
For example, the below diagram shows how to connect an LED to the PD-LED.<br />
<br />
[[File:pw-led-hookup.png|PD-LED Connection Example]]<br />
<br />
<br />
==== Serial Chain LEDs ====<br />
<br />
[[File:serial-led.png|String of WS281x RGB LEDs]]<br />
<br />
''Serial Chain'' LEDs are LEDs that are daisy-chained together and use a serial protocol to accept commands to light up and are usually full colour '''RGB''' (red/green/blue). This means they can be programmed to light any colour.<br />
<br />
They use a four-wire hookup - '''Power''' plus '''TX''' (Transmit) and '''RX''' (Receive). Very simply, you send commands via the '''Serial Protocol''' to say ''"Lamp 5, turn Red"'', and the command is sent down the line until the fifth lamp sees it and turns red.<br />
<br />
[[File:daisy-chain-led.jpg|Example of a daisy-chained LED string]]<br />
<br />
Thanks to modern pinball frameworks, all this low-level signalling is handled for you, so they can be labelled and addressed almost as simply as explained above.<br />
<br />
==== Direct versus Serial ====<br />
<br />
At first glance, serial LEDs would seem to have a big advantage over direct LEDs as the packing and wiring is much simpler, and overall are much cheaper as RGB LED strings are available for pennies per light on eBay and Aliexpress. However, they have two important drawbacks:<br />
<br />
* '''Susceptible to interference''': The underside of a pinball machine is a very ''noisy'' place in terms of EM emissions due to all the coils and mechs. As such, it can interfere with the serial communications, making lights not work, or light the wrong colour.<br />
* '''Slower response time''': Since the serial commands need to be sent from one light to the next in series versus in parallel for the direct LEDs, often the lights can be a bit slower to react to commands and cause issues with a complex lightshow.<br />
<br />
<br />
For this reason, it's recommended to use direct LEDs ''under'' the playfield, while you can use limited strings of serial LEDs ''above'' the playfield.<br />
<br />
[[File:fadecandy.png|FadeCandy from AdaFruit]]<br />
<br />
One option for controlling serial LEDs is the [https://www.adafruit.com/product/1689 FadeCandy], which can control up to '''eight LED chains''' (with 64 LEDs each = 512 LEDs) via the USB interface and is natively supported by [https://missionpinball.org/ MPF]. It can update them at 50Hz and provides temporal dithering and smooth hardware fades.<br />
<br />
The PD-LED can also drive ''both'' types of LEDs: '''Connector J8''' is designated for serial LEDs specifically and can drive up to '''six LED chains'''.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=OPP&diff=52263OPP2018-05-03T21:36:44Z<p>Jab: </p>
<hr />
<div>== Open Pinball Project ==<br />
<br />
The [https://openpinballproject.wordpress.com/ Open Pinball Project (OPP)] was started in 2012 as a resource for pinball makers to have an inexpensive, fully open sourced project for controlling custom pinball machines. It is currently on a second generation design and has had a successful Kickstarter run of boards and components currently in the hands of makers all over the world.<br />
<br />
== Hardware ==<br />
<br />
The '''OPP''' hardware is made up of three main components: <br />
<br />
* The '''Processor''' board is a [http://www.cypress.com/documentation/development-kitsboards/psoc-4-cy8ckit-049-4xxx-prototyping-kits Cypress Semiconductor CY8CKIT-049-42XX PSoC] prototyping board that can be purchased from [http://www.mouser.com/ProductDetail/Cypress-Semiconductor/CY8CKIT-049-42XX/ Mouser] or [http://www.digikey.com/product-detail/en/cypress-semiconductor-corp/CY8CKIT-049-42XX/428-3344-ND/4805328 Digikey].<br />
* The '''Interface''' board allows communications between '''Processor''' boards via a custom serial communications protocol.<br />
* The '''Wing''' boards allow the control of solenoids, lamps, LEDs or input from switches.<br />
<br />
<br />
Additionally, there is a '''Power Filter Board''' to allow the use of inexpensive switching power supplies.<br />
<br />
The following is an example of some fully assembled and wired OPP ''Processors'' with ''Wing'' boards.<br />
<br />
[[Image:fully-assembled-opp.jpg]]<br />
<br />
=== Processor Boards ===<br />
<br />
The ''Processor'' board can have up to four ''Wing'' boards controlling solenoids, incandescent lamps, or allowing input for switches. The ''Wing'' boards themselves can be combined in any configuration, so a single ''Processor'' board can support up to 16 solenoids (with 16 direct switch inputs), 32 switch inputs or 32 lamps. Each ''Wing'' board uses eight pins while the ''Interface'' board uses four. <br />
<br />
All other pins are unused, except on the first board in the chain where the USB plug from the host controller is connected to the ''Interface'' board to provide power and serial connections for the other ''Processors'' in the chain.<br />
<br />
[[Image:opp-processor.png]]<br />
<br />
The ''Processor'' itself does not run game rules or other game logic - a ''Controller'' like [https://missionpinball.com/ Mission Pinball] running on a separate PC is still required to handle scoring and other game logic and to fire coils and light lamps as needed. The ''Processor'' simply provides the physical connection to playfield devices. (Coils can automatically be fired using the direct switch input for the coil to allow a "white wood" mode that does not require a controller).<br />
<br />
==== Serial Chain ====<br />
<br />
When needing to control more devices or have more switches than a single ''Processor'' board can handle, you can chain multiple ''Processors'' together via a '''Serial Chain''' using a series of 8-pin ribbon cables connected to '''IN''' and '''OUT''' connectors on the ''Interface'' wing.<br />
<br />
The ribbon cable serial link between boards works in a similar fashion to a [https://en.wikipedia.org/wiki/Token_ring Token Ring] network, where each ''Processor'' receives messages via the serial line, looks for commands addressed to its ID, removes that command from the message and then passes the remaining message to the next ''Processor'' in the chain. The ''Processor'' then performs the requested action such as firing a solenoid or turning on a lamp. Switch events are passed back to the primary board and up to the host controller.<br />
<br />
The following image gives a visual idea of how messages flow between the ''Processors'':<br />
<br />
[[Image:token-ring.gif]]<br />
<br />
Like in the above image, each ''Processor'' assigns itself an ID on power-up (starting with '''0x20''' and increasing with each additional ''Processor'') based on its '''physical position''' in the serial chain. IDs are not saved between power cycles.<br />
<br />
Note that inserting a new card in the middle of a chain will ''change the ID of every board after it''. This will effect any hard-coded ID numbering in controllers like MPF, for example, but should not pose a big problem once the game is complete and no additional boards are added.<br />
<br />
=== Interface Wing ===<br />
<br />
The ''Interface'' wing has no transistors or other electronic parts on it other than connectors. Its purpose is to distribute low voltage power (primarily '''5V''') and serial signals between each ''Processor'' board. <br />
<br />
'''Note:''' The '''12V''' connection is only necessary if using surface mount incandescent wing boards configured as high side switches. Normally the '''12V''' connector can be left unpopulated.<br />
<br />
[[Image:interface-wing.png]]<br />
<br />
=== Solenoid Wing ===<br />
<br />
The ''Solenoid'' wing uses [http://www.digikey.com/product-search/en?keywords=FQP13N06L FQP13N06L MOSFETs] to control up to four individual coils via a ''ground sink'' method, where the coils themselves are wired to the positive side of the high voltage power supply and the MOSFET provides a ground path when activated, firing the coil.<br />
<br />
Standard coil voltages are '''24V''' to '''48V''' and upwards of '''10A''' of current. <br />
<br />
[[Image:solenoid-wing.png]]<br />
<br />
There are two connectors on the ''Solenoid'' wing - the larger 6-pin has four pins for the coil connections and two for ground. The 4-pin connector is for ''direct control'' switch inputs to control special solenoids.<br />
<br />
==== Special Solenoids ====<br />
<br />
For devices like flippers, slingshots or pop bumpers that require fast response to switch hits in order to fire coils, the ''Solenoid'' wing has four '''Direct Inputs''' that are used to directly activate the associated coil without the computer needing to detect a switch closure and send a solenoid activation command. These are known as ''Autofire'' coils.<br />
<br />
As of this writing, '''OPP''' only supports ''Autofire'' coils using the direct inputs or switch inputs on the '''same controller as the solenoid itself'''. This means you can't have an ''Autofire'' switch on another controller.<br />
<br />
Another advantage to using the direct switches is that it allows the game to be tested without a host controller, since pop bumpers, slingshots and flippers will work at power-on.<br />
<br />
The 4-pin connector for the direct switches can cause some packaging issues with the solenoid connector, so it is recommended to leave it out when building the boards if there is no need for ''Autofire'' coils.<br />
<br />
=== Incandescent Wing ===<br />
<br />
The ''Incandescent'' wing uses [http://www.digikey.com/product-detail/en/fairchild-semiconductor/2N7000/2N7000FS-ND/244278 2N7000 MOSFETs] to control up to eight direct wired incandescent lamps via the same ''ground sink'' method as the coils.<br />
<br />
Lamps require a high current '''6.3V''' power supply as each bulb needs about '''.25A''' at full brightness. <br />
<br />
[[Image:incandescent-wing.png]]<br />
<br />
''Direct wired'' means that each lamp is wired up and controlled individually via the 8-pin connector, rather than in the ''Matrix'' style that most commercial pinball machines used until recently. <br />
<br />
The other 2-pin connector is for the '''Ground''' connection.<br />
<br />
=== Switch Wing ===<br />
<br />
Switches are wired directly to the ''Processor'' board via an 8-pin 2.54mm locking header. <br />
<br />
[[Image:switch-example.jpg]]<br />
<br />
Unlike the ''Solenoid'' and ''Incandescent'' wings, the ''Switch'' wing is set up as ''High-side'', where the switch pins are at '''5V''' and playfield and cabinet switches are tied to '''Ground''', so that when a switch is activated, the pins are grounded and the switch is considered 'closed'. It is set up this way since the ''Processor'' pins have a '''Pull-Up''' resistor on them that is tied to 5V.<br />
<br />
The switches provide a ground path for the normally-high inputs.<br />
<br />
=== Power Filter Board ===<br />
<br />
[[image:Poppwrfilt1.jpg|Power Filter Board]]<br />
<br />
When firing solenoids, there is a large instantaneous draw of current from the power supply. A standard switching power supply may detect this as a short, and turn off. To prevent this from occurring, a large amount of bulk capacitance can be added, so the instantaneous current can be drawn from the bulk capacitors. Also, when initially charging the bulk capacitors, a large amount of current is drawn. A high power negative temperature coefficient (NTC) thermistor is used to reduce the initial current draw to charge the capacitors. This is the basis of the design for the ''Power Filter Board''.<br />
<br />
[[Image:power-filter-pinout.png]]<br />
<br />
The board contains the following additional features:<br />
<br />
* An LED to indicate when the capacitors are charged<br />
* Ability to turn on/off the power by grounding a pin<br />
* Output pin that can be used as an input to a processor for detecting if high voltage is enabled<br />
* Board can be configured for one or two different high voltages through board population<br />
<br />
<br />
The power filter board can be configured to provide bulk capacitance for one or two power supplies. If two power supplies are needed, a second P-Channel MOSFET and inrush current limiter must be bought.<br />
<br />
If the ability to enable/disable the high power voltage isn't needed, a jumper can be added instead of the P-channel MOSFETs.<br />
<br />
== Before You Start ==<br />
<br />
Prior to ordering and assembling the '''OPP''' boards, a number of tools and materials will need to be on hand, and a number of decisions will be made based on the pinball machine being built<br />
<br />
==== Tools and Materials Required ====<br />
<br />
To build and wire the '''OPP''' boards, you will need:<br />
<br />
* '''Wire:''' Look on eBay for stranded wire in the 22-24AWG size.<br />
* '''Side Cutters'''<br />
* '''Pliers'''<br />
* '''Soldering Iron:''' The [https://www.amazon.com/Hakko-FX888D-23BY-Digital-Soldering-FX-888D/dp/B00ANZRT4M/ref=sr_1_6?ie=UTF8&qid=1471620603&sr=8-6&keywords=soldering+station Hakko FX888D] is a popular, inexpensive brand. A lower-priced option is this iron from [http://www.dx.com/p/yf-951-thermostat-soldering-iron-110v-135519 DX].<br />
* '''Solder:''' [https://www.amazon.com/Kester-Rosin-Core-Solder-Spool/dp/B00068IJWC Kester 44] is an excellent 63/37 solder. [http://www.dx.com/p/0-81mm-tin-solder-soldering-welding-iron-wire-silvery-grey-109m-193930 DX] also has a less expensive option.<br />
* '''Crimping Tool:''' [http://www.marcospecialties.com/pinball-parts/77-CTW Marco Specialities] offers an inexpensive tool. Another option is the '''SN-28B''' ratcheting crimp tool - it can be purchased for less than $15 on eBay.<br />
* '''Pin Extractor:''' [http://www.digikey.com/short/3hvfr2 Digikey] has the Molex-branded tool for extracting the Mini-Fit Jr. style of square connectors used on the ''Solenoid'' wings.<br />
<br />
==== Determine Board Layout ====<br />
<br />
Prior to purchasing the '''OPP''' boards and components, you need to know how many '''solenoids, lamps''' and '''switches''' you need to support, where to put them, and how they will be mounted. <br />
<br />
For example, a custom game might require 31 inputs, 10 solenoids (with 10 direct inputs), and 43 incandescent bulbs. This could be accomplished with four ''Processor'' boards and four ''Interface'' wings, three ''Solenoid'' wings, six ''Incandescent'' wings and five ''Switch'' wings. Technically this is more boards and wings than are strictly required, as the ''Processor'' boards could handle a denser wing configuration, but this layout cuts down on the total wiring required by placing ''Processors'' close to the devices they are controlling, saving significant time and materials.<br />
<br />
Alternatively, consider a ''Williams Jokerz'' machine. It has 19 solenoids (including direct inputs), 39 switches and 63 incandescent bulbs (which includes 9 flashers). A possible layout for that is five ''Processor'' boards with five ''Interface'' wings, four ''Solenoid'' wings, eight ''Incandescent'' wings and five ''Switch'' wings.<br />
<br />
You can place ''Processors'' near what is being controlled, or put them all together in the head of the machine like a traditional commercial pinball - it is entirely up to the maker as to where to place ''Processors'', but placement ''will'' determine the final number of ''Processors'' and wings required.<br />
<br />
Once the total number of ''Processor'' and ''Wing'' boards has been determined, and their approximate location in the final machine, parts can be ordered.<br />
<br />
==== Power Supply Needs ====<br />
<br />
When running solenoids and lamps, you'll need three voltages: '''5V 3A''' for logic, '''6.3V 10A''' for lamps and '''24V to 48V 10A''' for solenoids (depending on what coils you use). See the [[Construction#Power_Supplies|Power Supply]] section for details of what is available.<br />
<br />
An inexpensive option is to use a PC power supply, which provides high current '''5V''' for logic and '''12V''' for lamps. A high power DC-DC step down ''Buck Converter'' can be used to convert '''12V''' to '''6.3V''' for incandescents.<br />
<br />
You can use a separate '''24V to 48V 10A''' switcher for solenoids if you also use the '''Power Filter Board'''.<br />
<br />
== Getting Blank Boards ==<br />
<br />
The '''OPP''' site itself does not sell blank boards and there currently is no one selling fully populated and tested boards. However, given the open source nature of the project, there are multiple ways to get the blanks.<br />
<br />
The easiest is to order boards from [http://mezelmods.com/collections/open-pinball-project-parts MezelMods] as they offer blanks for a very reasonable $1US per board.<br />
<br />
The next option is to create '''Gerber''' files from the [http://kicad-pcb.org/download/KiCad KiCad] files located in the OPP [https://svn.code.sf.net/p/open-pinball-project/code/trunk SVN] repository. For this you'll need to download '''KiCad''', which is a printed circuit board design tool that was used to create the '''OPP''' boards. Once you have the ''Gerber'' files, they can be uploaded to a number of low-cost PCB manufacturers such as:<br />
<br />
* [https://www.oshstencils.com/ OSH Stencils]<br />
* [https://oshpark.com/ OSH Park]<br />
* [https://www.seeedstudio.com/fusion_pcb.html SeeedStudio]<br />
* [https://www.itead.cc/open-pcb/pcb-prototyping.html iTEAD]<br />
<br />
<br />
Each PCB maker has plusses and minuses that are too involved to go into in this wiki, but '''SeeedStudio''' has good prices and fast shipping.<br />
<br />
Getting PCBs made can be a fairly advanced process, so it is recommended to simply purchase the already-made boards via [http://mezelmods.com/collections/open-pinball-project-parts MezelMods]. They also offer additional parts that are less expensive than purchasing through Digikey or Mouser such as the '''FC-8P''' connectors and the '''1x40 2.54 mm''' headers.<br />
<br />
== Getting Components ==<br />
<br />
Once you have the bare boards, they will need to be fully populated with components, which are not included - they will need to be sourced separately. The following is a '''Bill of Materials''' (BoM) for each ''Processor'' and ''Wing'' board.<br />
<br />
==== Processor Board ====<br />
<br />
{| class="wikitable"<br />
|-<br />
! Quantity<br />
! Mouser Part #<br />
! Description<br />
! Price Est.<br />
! Mezel Price<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Cypress-Semiconductor/CY8CKIT-049-42XX/ 727-CY8CKIT-049-42XX]<br />
| Cypress Semiconductor PSoC 4200 Prototyping Kit<br />
| $3.98/ea<br />
| N/A<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Amphenol-FCI/68602-108HLF/ 649-68602-108HLF]<br />
| 2 x 4 position 2.54 mm Header<br />
| $0.45/ea<br />
| [http://mezelmods.com/collections/under20/products/4-pin-2-54mm-dual-in-line-row-male-header-connector $0.20/ea]<br />
|-<br />
| 2<br />
| [http://www.mouser.com/ProductDetail/TE-Connectivity/9-146278-0/ 571-9-146278-0]<br />
| 40-pin 2.54 mm Header<br />
| $2.51/ea<br />
|[http://mezelmods.com/collections/under20/products/2-54mm-40-pin-male-single-row-pin-header-strip $0.50/ea]<br />
|-<br />
| 2<br />
| [http://www.mouser.com/ProductDetail/Kycon/SX1100-B/ SX1100-B]<br />
| 2.54 mm Jumper<br />
| $0.10/ea<br />
| N/A<br />
|}<br />
<br />
'''Note:''' The 40-pin header is available much cheaper in larger quantities from eBay - search for "1x40 2.54mm header". These parts are also available through Mezel Mods.<br />
<br />
==== Solenoid Wing ====<br />
<br />
{| class="wikitable"<br />
|-<br />
! Quantity<br />
! Mouser Part #<br />
! Description<br />
! Price Est.<br />
|-<br />
| 4<br />
| [http://www.mouser.com/ProductDetail/Fairchild-Semiconductor/FQP13N06L 512-FQP13N06L]<br />
| FQP13N06L MOSFET<br />
| $0.67/ea<br />
|-<br />
| 4<br />
| [http://www.mouser.com/ProductDetail/Yageo/CFR-12JR-52-10K/ 603-CFR-12JR-5210K]<br />
| 10K Ohm Resistor (1/6W 5%)<br />
| $0.02/ea<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Molex/35317-0620/ 538-35317-0620]<br />
| Molex 6-pin 4.2 mm Mini-Fit Header<br />
| $0.28/ea<br />
|-<br />
| 6<br />
| [http://www.mouser.com/ProductDetail/Molex/39-00-0039/ 538-39-00-0039]<br />
| Molex Crimp-Style 4.2 mm 24-18AWG Female Pins<br />
| $0.19/ea<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Molex/39-01-2065/ 538-39-01-2065]<br />
| Molex 6-pin 4.2 mm Mini-Fit Housing<br />
| $0.52/ea<br />
|-<br />
|colspan=4|Parts Needed ONLY If Adding Direct Switches <br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/TE-Connectivity/640454-4/ 640454-4]<br />
| 4-pin Polarized 2.54 mm Header<br />
| $0.12/ea<br />
|-<br />
| 6<br />
| [http://www.mouser.com/ProductDetail/Molex/08-50-0136/ 538-08-50-0136]<br />
| Molex Crimp-Style 2.54 mm KK Pins<br />
| $0.13/ea<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Molex/22-01-2047/ 538-22-01-2047]<br />
| Molex 4-Pin 2.54 mm Housing<br />
| $0.17/ea<br />
|-<br />
|colspan=4|Pin-Compatible Higher Current MOSFET (Flippers, etc.) <br />
|-<br />
| 4<br />
| [http://www.mouser.com/ProductDetail/Infineon-Technologies/IRL540NPBF 942-IRL540NPBF]<br />
| N-Channel MOSFET 100V 36A<br />
| $1.55/ea<br />
|}<br />
<br />
'''Note:''' The total number of crimp-style pins included in the BoM is higher than actually needed to account for re-crimping.<br />
<br />
==== Incandescent Wing ====<br />
<br />
{| class="wikitable"<br />
|-<br />
! Quantity<br />
! Mouser Part #<br />
! Description<br />
! Price Est.<br />
|-<br />
| 8<br />
| [http://www.mouser.com/ProductDetail/Fairchild-Semiconductor/2N7000TA/ 512-2N7000TA]<br />
| MOSFET 60V N-Channel<br />
| $0.33/ea<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Molex/35317-0220/ 538-35317-0220]<br />
| Molex 2-pin 4.2 mm Header<br />
| $0.12/ea<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Molex/39-01-2025/ 538-39-01-2025]<br />
| Molex 2-pin 4.2 mm Housing<br />
| $0.33/ea<br />
|-<br />
| 3<br />
| [http://www.mouser.com/ProductDetail/Molex/39-00-0039 538-39-00-0039]<br />
| Molex Crimp-Style 4.2 mm 24-18AWG Female Pins<br />
| $0.19/ea<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/TE-Connectivity/640454-8/ 571-6404548]<br />
| 8-pin 2.54 mm Polarized Header<br />
| $0.45/ea<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Molex/22-01-2087/ 538-22-01-2087]<br />
| Molex 8-pin 2.54 mm Housing<br />
| $0.32/ea<br />
|-<br />
| 10<br />
| [http://www.mouser.com/ProductDetail/Molex/08-50-0136/ 538-08-50-0136]<br />
| Molex Crimp-Style 2.54 mm KK Pins<br />
| $0.13/ea<br />
|-<br />
|colspan=4|Higher Current alternative MOSFET<br />
|-<br />
| 8<br />
| [http://www.mouser.com/ProductDetail/Fairchild-Semiconductor/BS170 512-BS170]<br />
| N-Channel MOSFET 60V 500mA<br />
| $0.39/ea<br />
|}<br />
<br />
==== Switch Wing ====<br />
<br />
{| class="wikitable"<br />
|-<br />
! Quantity<br />
! Mouser Part #<br />
! Description<br />
! Price Est.<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/TE-Connectivity/640454-8/ 571-6404548]<br />
| 8-pin 2.54 mm Polarized Header<br />
| $0.45/ea<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/Molex/22-01-2087/ 538-22-01-2087]<br />
| Molex 8-pin 2.54 mm Housing<br />
| $0.32/ea<br />
|-<br />
| 10<br />
| [http://www.mouser.com/ProductDetail/Molex/08-50-0136/ 538-08-50-0136]<br />
| Molex Crimp-Style 2.54 mm KK Pins<br />
| $0.13/ea<br />
|}<br />
<br />
'''Note:''' The ''Switch'' wing is just the 8-pin headers soldered directly to the ''Processor'' board with the upright lock facing out from the board.<br />
<br />
==== Interface Wing ====<br />
<br />
{| class="wikitable"<br />
|-<br />
! Quantity<br />
! Mouser Part #<br />
! Description<br />
! Price Est.<br />
! Mezel Price<br />
|-<br />
| 2<br />
| [http://www.mouser.com/ProductDetail/Amphenol-FCI/68602-108HLF/ 649-68602-108HLF]<br />
| 2 x 4 position 2.54 mm Header<br />
| $0.45/ea<br />
| [http://mezelmods.com/collections/under20/products/4-pin-2-54mm-dual-in-line-row-male-header-connector $0.20/ea]<br />
|-<br />
| 1<br />
| [http://www.mouser.com/ProductDetail/TE-Connectivity/640454-4/ 640454-4]<br />
| Molex 4-Pin 2.54 mm Polarized Header<br />
| $0.12/ea<br />
| N/A<br />
|-<br />
| 2<br />
| [http://www.mouser.com/ProductDetail/Molex/22-01-2047/ 538-22-01-2047]<br />
| Molex 4-Pin 2.54 mm Housing<br />
| $0.17/ea<br />
| N/A<br />
|-<br />
| 10<br />
| [http://www.mouser.com/ProductDetail/Molex/08-50-0136/ 538-08-50-0136]<br />
| Molex Crimp-Style 2.54 mm KK Pins<br />
| $0.13/ea<br />
| N/A<br />
|-<br />
| 2<br />
| eBay (search "FC-8P")<br />
| FC-8P IDC Socket 2.54 mm<br />
| ~ $0.10/ea<br />
| [http://mezelmods.com/collections/under20/products/fc-8p-2-54mm-idc-connector-8-pin-cable-socket $0.20/ea]<br />
|-<br />
| ~10ft<br />
| eBay (search "8 pin IDC cable")<br />
| 8-pin IDC Flat cable<br />
| ~$1/ft<br />
| N/A<br />
|}<br />
<br />
'''Note:''' Neither Mouser nor Digikey have FC-8P connectors or flat cable in stock, so eBay is the best source for these parts. Mezel Mods sells FC-8P connectors and 2x4 Pin headers for a lower price.<br />
<br />
==== Power Filter Board ====<br />
<br />
{| class="wikitable"<br />
|-<br />
! Qty / 1 Switcher<br />
! Qty / 2 Switcher<br />
! Mouser Part #<br />
! Description<br />
! Price Est.<br />
|-<br />
| 1<br />
| 1<br />
| [https://mezelmods.com/collections/open-pinball-project-parts/products/open-pinball-project-power-supply-filter-board PCB]<br />
| PCB from Mezel Mods<br />
| $5.00/ea<br />
|-<br />
| 3<br />
| 3<br />
| [http://www.mouser.com/ProductDetail/Cornell-Dubilier/SLPX822M063H5P3/ 598-SLPX822M063H5P3]<br />
| Bulk Capacitor, 8.2mF, 63V<br />
| $4.28/ea<br />
|-<br />
| 1<br />
| 2<br />
| [http://www.mouser.com/ProductDetail/Ametherm/SG26/ 995-SG26]<br />
| Inrush current limiter (NTC Thermistor)<br />
| $2.28/ea<br />
|-<br />
| 2<br />
| 3<br />
| [http://www.mouser.com/ProductDetail/Molex/35317-0620/ 538-35317-0620]<br />
| Molex 6-pin 4.2 mm Mini-Fit Header<br />
| $0.28/ea<br />
|-<br />
| 1<br />
| 2<br />
| [http://www.mouser.com/ProductDetail/STMicroelectronics/STF10P6F6/ 511-STF10P6F6]<br />
| P - Channel MOSFET<br />
| $0.85/ea<br />
|-<br />
| 3<br />
| 6<br />
| [http://www.mouser.com/ProductDetail/Ohmite/OK1045E-R52/ 588-OK1045E-R52]<br />
| 100K Ohm Resistor<br />
| $0.02/ea<br />
|-<br />
| 1<br />
| 2<br />
| [http://www.mouser.com/ProductDetail/Lumex/SLX-LX5093ID/ 696-SLX-LX5093ID]<br />
| High voltage 5mm (T-1 3/4) indicator LED<br />
| $0.06/ea<br />
|-<br />
| 12<br />
| 18<br />
| [http://www.mouser.com/ProductDetail/Molex/39-00-0039/ 538-39-00-0039]<br />
| Molex Crimp-Style 4.2 mm 24-18AWG Female Pins<br />
| $0.19/ea<br />
|-<br />
| 2<br />
| 3<br />
| [http://www.mouser.com/ProductDetail/Molex/39-01-2065/ 538-39-01-2065]<br />
| Molex 6-pin 4.2 mm Mini-Fit Housing<br />
| $0.52/ea<br />
|-<br />
| 1<br />
| 1<br />
|[http://mouser.com/ProductDetail/TE-Connectivity-AMP/640456-6/ 571-6404566]<br />
| FRICTION LCK 6P Header<br />
| $0.38/ea<br />
|}<br />
<br />
The power filter board can be configured to provide bulk capacitance for one or two power supplies. If two power supplies are needed, a second P-Channel MOSFET and inrush current limiter must be bought.<br />
<br />
If the ability to enable/disable the high power voltage isn't needed, a jumper can be added instead of the P-channel MOSFETs.<br />
<br />
'''Note:''' Another through-hole resistor is needed if planning to allow a processor to read if the voltage is enabled or not. A simple voltage divider is used to convert the high voltage to the processor input voltage. The value of that resistor is different depending on the input voltage from your power supply and the input voltage of the processor. The table lists the 1% and 5% standard value resistor. (Choose the cheapest):<br />
<br />
{| class="wikitable"<br />
|-<br />
! Input Voltage<br />
! Processor Voltage<br />
! Resistor Ohm<br />
! 1% Resistor<br />
! 5% Resistor<br />
|-<br />
| 24V<br />
| 5V<br />
| 380K<br />
| 383K<br />
| 390K<br />
|-<br />
| 48V<br />
| 5V<br />
| 860K<br />
| 866K<br />
| 910K<br />
|-<br />
| 70V<br />
| 5V<br />
| 1.3M<br />
| 1.3M<br />
| 1.3M<br />
|-<br />
| 24V<br />
| 3.3V<br />
| 628K<br />
| 634K<br />
| 680K<br />
|- <br />
| 48V<br />
| 3.3V<br />
| 1.35M<br />
| 1.37M<br />
| 1.5M<br />
|-<br />
| 70V<br />
| 3.3V<br />
| 2.02M<br />
| 2.05M<br />
| 2.2M<br />
|-<br />
|}<br />
<br />
The equation to calculate the resistor value is:<br />
<br />
<code>(Power Supply Voltage * 100K) / Processor Voltage - 100K = Resistor</code><br />
<br />
== Assembly ==<br />
<br />
Once all the boards and the components are available, you can begin assembly. <br />
<br />
==== Processor Board Assembly ====<br />
<br />
As delivered, the Cypress PSoC 4200 board needs to have two traces on the USB to Serial portion of the board cut - the TX and RX lines. Use an X-Acto knife to cut the thin traces on both sides of the board and use a Multimeter to test between the two through holes to confirm there is no connectivity. This is important to prevent crosstalk on the serial lines.<br />
<br />
After the lines are cut, the headers (or lock connectors if being used for switches) can be soldered in, along with the 2x4 header between the USB-to-Serial interface and the main board.<br />
<br />
[[Image:processor-assembly.png]]<br />
<br />
==== Interface Wing Assembly ====<br />
<br />
The main parts of the ''Interface'' wing are the two 2x4 headers for the serial connection and the 4-pin locking header that is used on the first ''Processor'' board to bring the Serial output from the USB-to-Serial card into the ''Interface'' wing. The 4-pin header is only required for the first ''Processor'' board in the chain, and can be left out when building the wing for subsequent boards.<br />
<br />
[[Image:interface-assembly.png]]<br />
<br />
It is best to start with the smallest components and work up - solder the two termination jumpers (marked as '''R2''' and '''R3''') and the serial connector enable jumper as depicted in the diagram, then the 2x4 headers, and finally the 4-pin header if needed.<br />
<br />
Once assembled, the ''Interface'' board can be soldered to the ''Processor'' board on the last four pins marked '''4.0''' through '''4.3''' as per the diagram.<br />
<br />
The final step is to connect VDD and GND to the ''Interface'' wing by soldering wire from the ''Processor'' board to the ''Interface'' wing as per the diagram - GND to '''Pin 1''' and 5V to '''Pin 2'''. This is required to power all the downstream ''Processor'' boards as none of them will be plugged into the USB connector which normally provides power. The 8-pin ribbon cable used for serial communications also provides 5V and ground connections.<br />
<br />
==== Solenoid Wing Assembly ====<br />
<br />
The parts for the ''Solenoid'' wing are the four MOSFETs, four 10K Resistors, a 2x3 header and a 4-pin locking header. If you are not using the ''direct switch'' capabilities of the ''Solenoid'' wing, it is recommended to leave the 4-pin out of the build as it causes some packaging issues when placing wings next to each other, as the 2x3 header sticks off the end of the board slightly and makes contact with the 4-pin header on the adjacent wing.<br />
<br />
[[Image:solenoid-assembly.png]]<br />
<br />
As with the ''Interface'' wing, start with the smallest components and work upwards - resistors, MOSFETs then headers. The 2x3 header should be installed with the locking tab facing "up" as in the above diagram. <br />
<br />
After assembly, it can be soldered in the appropriate spot on the ''Processor'' board. It is recommended to place ''Solenoid'' boards in the '''Wing 0''' and '''Wing 1''' positions as this allows a short jumper to connect the logic (5V) ground wiring for the pulldown, as well as slightly better fitment due to the chip packaging on the ''Processor'' boards. However, it is not a requirement - ''Solenoid'' wings can be placed in any position, as long as the pulldown ground is properly wired.<br />
<br />
After soldering the ''Solenoid'' wing to the ''Processor'' board, use a solid wire jumper to tie it and the ''Interface'' board together on the very end through holes. This is a purely physical connection that helps add stability to the board - there is no electrical connection on those holes. A good source for a jumper wire are the leftover legs from the resistors after they've been soldered in and cut to length.<br />
<br />
==== Incandescent Wing Assembly ====<br />
<br />
The through-hole ''Incandescent'' wing parts are eight 2N7000 MOSFETs, an 1x8 locking header for lamp connections and a 2-pin header for the 12V ground connection. No resistors are required, so all resistor spots are left empty.<br />
<br />
[[Image:incandescent-assembly.png]]<br />
<br />
'''NOTE:''' As the board was originally designed for BS170s, the screened artwork reflects the pinout for that part, but the pinout is reversed for the 2N7000, so it is critically important to install the MOSFETs in the '''REVERSED''' orientation from the artwork.<br />
<br />
The tab for the 2-pin header should face inwards towards the center of the board.<br />
<br />
Once assembly is complete and the wing is installed on the ''Processor'', a solid wire jumper should be installed on the end holes to provide stability. As with all wing boards other than the ''Interface'' board, the ''Incandescent'' wing can be installed in any of the four positions.<br />
<br />
==== Switch Wing Assembly ====<br />
<br />
There is no physical wing board required for the ''Switch'' wing - it consists entirely of a single 8-pin 2.54mm locking header connected directly to the ''Processor'' board.<br />
<br />
[[Image:switch-assembly.png]]<br />
<br />
==== Power Filter Board ====<br />
<br />
Install jumpers, resistors, LEDs, MOSFETs and connectors first, then thermistors and finally the three capacitors with the negative leg facing towards the bottom of the board. LEDs are installed with the flat part facing down.<br />
<br />
If not using the power control capability of the board, the MOSFETs and their associated resistors are not needed.<br />
<br />
[[Image:Power-filter-assembly.png]]<br />
<br />
==== Power Filter Board, One Voltage Supply, No Controls ====<br />
<br />
The power filter board tries to be all things to all people. As such, it can be confusing to know how to populate the board. This section describes how to populate a power filter board for a single power supply, no processor control or feedback to detect if power supply is on, and no safety LED for indicating capacitors are charged. <br />
<br />
Purchase the first four items (first column quantities) from this table [http://pinballmakers.com/wiki/index.php/OPP#Power_Filter_Board_2 Filter Board Parts]. Install the three bulk capacitors, one NTC thermistor (install in left position), and two 6-pin Molex connectors (install in top and left positions). Using the clipped off leads from the NTC thermistor, add the red and blue jumpers as seen in the image above. Lastly, add the two light green jumpers that are marked by Q1 and Q2 on the silkscreen. (Only one is shown in the above image, while the second is shown as a MOSFET. In both positions, the jumper needs to go between the middle and right holes as shown in the image)<br />
<br />
== Firmware ==<br />
<br />
The '''OPP''' boards aren't just about the physical hardware, there's also an operating system - to handle the serial communication with the host, moving messages along the serial chain, activating coils and lamp, and maintaining state for all the above. This software is known as '''Firmware''' and it runs on each ''Processor'' board. This is what talks to the host computer over USB.<br />
<br />
The firmware is available for download via the [https://openpinballproject.wordpress.com/repository/ OPP SVN] repo. It must be copied to each ''Processor'' individually in order for them to work - it cannot be done while the ''Processors'' are connected via the Serial Chain, unless you're performing an upgrade of existing ''Processors''.<br />
<br />
==== RX/TX Jumpers ====<br />
<br />
As part of the initial board setup, the ''RX/TX'' traces were cut on the ''Processor'' board. In order to copy the firmware to the board, jumpers will need to be put in place to connect the two serial pins on the USB-to-Serial interface to the board itself.<br />
<br />
[[Image:usb-jumpers.png]]<br />
<br />
==== Determine your USB Device ====<br />
<br />
In order to talk to the ''Processor'' via the host computer's USB port, a '''device driver''' will likely need to be installed. Cypress offers [http://www.cypress.com/documentation/software-and-drivers/usb-serial-software-development-kit device drivers] for Windows, Linux and Mac. <br />
<br />
Install the appropriate driver for your host computer following the instructions from the Cypress site. <br />
<br />
Once installed, plugging the ''Processor'' into a USB port on the host computer should result in a device being mounted on your system, with an associated serial device - a '''COM''' port on Windows or a <code>tty</code> or <code>cu</code> file in the <code>/dev</code> directory for Linux and Mac.<br />
<br />
Some typical Serial devices are listed below. Please note that this is not a definitive list as the operating systems will assign Serial ports dynamically, so for example on Windows it might be COM8 or COM10, or on OSX it might be /dev/cu.usbmodem1421, and so on.<br />
<br />
{| class="wikitable"<br />
|-<br />
! OS<br />
! Device<br />
|-<br />
| Windows<br />
| COM9<br />
|-<br />
| Linux<br />
| /dev/ttys1<br />
|-<br />
| OSX<br />
| /dev/cu.usbmodem1411<br />
|-<br />
| Raspbian (Raspberry Pi Linux)<br />
| /dev/ttyACM0<br />
|-<br />
|}<br />
<br />
To determine the port, check the syslog on Mac/Linux or the ''System Console'' on WIndows.<br />
<br />
Whatever the device name is, write it down as it will be needed for copying the firmware and all future communication with the ''Processor'' boards. <br />
<br />
===== Raspberry Pi Serial =====<br />
<br />
Specific to the Raspberry Pi setup, the default driver for the Cypress controller in the OS sees it as a thermometer, so the driver needs to be disabled. This is done by editing the <code>/etc/modprobe.d/raspi-blacklist.conf</code> file and inserting the following:<br />
<br />
<code>blacklist cytherm</code><br />
<br />
If the file doesn't exist, create it. <br />
<br />
After saving the file and exiting, do <code>chmod 600 /etc/modprobe.d/raspi-blacklist.conf</code> and then reboot the RPi. The processor should then appear as a USB device using the default serial driver.<br />
<br />
==== cyflash ====<br />
<br />
'''cyflash''' is a Python utility provided by Cypress to copy firmware to the board. It is included as part of the [https://openpinballproject.wordpress.com/repository/ OPP SVN] repo under the <code>Python/cyflash</code> directory. <br />
<br />
The instructions for downloading the SVN repo are detailed on the main SVN page. Once downloaded to the local filesystem into a directory called <code>opp</code>, do a directory listing to confirm the cyflash files are in place.<br />
<br />
[[Image:cyflash-directory.png]]<br />
<br />
How the firmware is uploaded depends on which OS you use - Windows, Linux or Mac. Linux and Mac are a bit simpler as they already have the correct version of ''Python'' installed by default. <br />
<br />
For Windows, download the [https://www.python.org/downloads/windows/ Latest Version] of Python 2.7 and follow the install instructions as listed. It should be in the <code>C:\Python27</code> directory (the default).<br />
<br />
From the command line, change into the <code>opp/Python/cyflash/</code> directory. The ''cyflash'' utility can be envoked with the following parameters:<br />
<br />
'''Linux/Mac'''<br />
<code>python -m cyflash.__main__ --serial /dev/[serial-device] --serial_baudrate 115200 ../../Creator/Gen2Images/Gen2.rev0.2.0.0.cyacd</code><br />
<br />
'''Windows'''<br />
<code>c:\Python27\Python.exe -m cyflash.__main__ --serial COM[serial-device] --serial_baudrate 115200 ..\..\Creator\Gen2Images\Gen2.rev0.2.0.0.cyacd</code><br />
<br />
Before running the command, you must put the ''Processor'' into '''bootloader''' mode. Plug the board in while holding down the small button at the end of the board, which will cause the blue LED to flash rapidly. <br />
<br />
Running ''cyflash'' should begin to upload the firmware to the board.<br />
<br />
<pre><br />
% python -m cyflash.__main__ --serial /dev/cu.usbmodem1411 --serial_baudrate 115200 ../../Creator/Gen2Images/Gen2.rev0.2.0.0.cyacd<br />
CyFlash version: 1.07<br />
Initialising bootloader.<br />
Silicon ID 0x04c81193, revision 17.<br />
Bootloader version: 1.20<br />
Array 0: first row 32, last row 255.<br />
Uploading data (128/128)<br />
Device checksum verifies OK.<br />
Rebooting device.<br />
</pre><br />
<br />
When it is complete, the board should reboot and the LED stop flashing. The board is now ready for configuring the Wing layout.<br />
<br />
For versions of firmware greater than 0.2.0.1 it is possible to upgrade without having to disconnect each processor board and program separately. This is covered in the next section.<br />
<br />
==== Gen2Test ====<br />
<br />
'''Gen2Test''' is the '''OPP''' utility used to check ''Processor'' status, as well as '''erase''', '''load''' and '''save''' the ''Wing'' configuration prior to using it with the host controller. It uses an additional ''Python'' script as a config file that you define. Even if you use a framework like ''MPF'' that automatically sets up the ''Processor'' configs for you on startup, it is a good idea to configure each board and save the configs separately to prevent coil or lamp lock-on due to a wing being defined as a switch or other issues.<br />
<br />
==== Example Configuration Files ====<br />
<br />
Here are some examples of wing config files. They are not included in the SVN repo, but can be copied and used for configuring boards if saved with a <code>.py</code> extension.<br />
<br />
'''2sol2switch.py:''' This config sets Wing 0-1 to ''Solenoid'' wings, and Wing 2-3 to ''Switch'' wings.<br />
<br />
<pre><br />
testVers = '00.00.01'<br />
<br />
import rs232Intf<br />
<br />
# Config inputs as all state inputs<br />
wingCfg = [ [ rs232Intf.WING_SOL, rs232Intf.WING_SOL, rs232Intf.WING_INP, rs232Intf.WING_INP ] ]<br />
<br />
# Config inputs as all state inputs<br />
inpCfg = [ [ rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE ] ]<br />
<br />
# solenoid config<br />
solCfg = [ [ rs232Intf.CFG_SOL_USE_SWITCH, '\x20', '\x00', rs232Intf.CFG_SOL_USE_SWITCH, '\x20', '\x00', \<br />
rs232Intf.CFG_SOL_USE_SWITCH, '\x20', '\x00', rs232Intf.CFG_SOL_USE_SWITCH, '\x20', '\x00', \<br />
rs232Intf.CFG_SOL_USE_SWITCH, '\x20', '\x00', rs232Intf.CFG_SOL_USE_SWITCH, '\x20', '\x00', \<br />
rs232Intf.CFG_SOL_USE_SWITCH, '\x20', '\x00', rs232Intf.CFG_SOL_USE_SWITCH, '\x20', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00' ] ]<br />
</pre><br />
<br />
'''4incand.py:''' This config sets all four wings to ''Incandescent''.<br />
<br />
<pre><br />
testVers = '00.00.01'<br />
<br />
import rs232Intf<br />
<br />
# Config inputs as all state inputs<br />
wingCfg = [ [ rs232Intf.WING_INCAND, rs232Intf.WING_INCAND, rs232Intf.WING_INCAND, rs232Intf.WING_INCAND ] ]<br />
<br />
# Config inputs as all state inputs<br />
inpCfg = [ [ rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE ] ]<br />
<br />
# solenoid config<br />
solCfg = [ [ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00' ] ]<br />
</pre><br />
<br />
'''2incand2switch.py''': This config sets Wing 0-1 as ''Incandescent'' and Wing 2-3 as ''Switch''.<br />
<br />
<pre><br />
testVers = '00.00.01'<br />
<br />
import rs232Intf<br />
<br />
# Config inputs as all state inputs<br />
wingCfg = [ [ rs232Intf.WING_INCAND, rs232Intf.WING_INCAND, rs232Intf.WING_INP, rs232Intf.WING_INP ] ]<br />
<br />
# Config inputs as all state inputs<br />
inpCfg = [ [ rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, \<br />
rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE, rs232Intf.CFG_INP_STATE ] ]<br />
<br />
# solenoid config<br />
solCfg = [ [ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', \<br />
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00' ] ]<br />
</pre><br />
<br />
The key lines in each file are <code>wingCfg</code>, which defines the layout, and <code>solCfg</code>, which sets the default values for each solenoid if a ''Solenoid'' wing is used on the ''Processor''. <code>InpCfg</code> and the rest of the file are the same for each config.<br />
<br />
<code>wingCfg</code> lists each wing type in order of wing position from 0 to 3. <code>solCfg</code> has three parameters per coil - the type of solenoid (USE_SWITCH, AUTO_CLR, ON_OFF_SOL, or DLY_KICK_SOL), initial kick time in milliseconds ("\x20" equals 32ms), and the last is the PWM duty cycle. "\x00" disables PWM. All values are in [https://en.wikipedia.org/wiki/Hexadecimal hexadecimal] notation. <br />
<br />
For a detailed explanation of what each value means, you can reference the documentation for the serial protocol (<code>opp/Docs/brdIntf.pdf</code>) in the SVN repo, as well as see the definitions for each value in the <code>opp/Python/Gen2Test/rs232Intf.py</code> script. <br />
<br />
However, any of the above examples, or the included <code>mdCfg</code> file, will work as-is without needing a deep understanding of the firmware internals.<br />
<br />
==== Check Processor Configurations ====<br />
<br />
From the command line, change into the <code>opp/Python/Gen2Test</code> directory.<br />
<br />
Plug in the ''Processor'' with the USB jumpers installed and run the command (with either <code>C:\Python27\Python.exe</code> or just <code>python</code> depending on your system):<br />
<br />
<code>Gen2Test.py -port=[serial-device]</code> <br />
<br />
Where the <code>serial-device</code> is the appropriate serial port on the host computer saved from earlier. The command should provide an inventory of the ''Wings'' as set by the firmware when it was uploaded. The default is all wings set to ''Switch''.<br />
<br />
<pre><br />
% python Gen2Test.py -port=/dev/cu.usbmodem1411<br />
Sending inventory cmd<br />
Found 1 Gen2 brds.<br />
Addr = ['0x20']<br />
0x20 WingCfg = 0x02020202<br />
0x20 INP_WING INP_WING INP_WING INP_WING<br />
</pre><br />
<br />
If there are additional processors in the chain, it will display the configuration for all attached processors.<br />
<br />
==== Erase Wing Configuration ====<br />
<br />
To erase the existing config, run the command with the '''eraseCfg''' option:<br />
<br />
<pre><br />
% python Gen2Test.py -port=/dev/cu.usbmodem1411 -eraseCfg<br />
Sending inventory cmd<br />
Found 1 Gen2 brds.<br />
Addr = ['0x20']<br />
0x20 WingCfg = 0x02020202<br />
0x20 INP_WING INP_WING INP_WING INP_WING<br />
Sent erase cfg command.<br />
</pre><br />
<br />
==== Save Wing Configuration ====<br />
<br />
To save a new config, run the command with the '''saveCfg''' option and specify the config file with the '''loadCfg''' command.<br />
<br />
<pre><br />
% python Gen2Test.py -port=/dev/cu.usbmodem1411 -saveCfg -loadCfg=2sol2switch.py<br />
Sending inventory cmd<br />
Found 1 Gen2 brds.<br />
Addr = ['0x20']<br />
0x20 WingCfg = 0x02020202<br />
0x20 INP_WING INP_WING INP_WING INP_WING<br />
loadFileName = 2sol2switch<br />
Sending wing cfg.<br />
Sending input cfg.<br />
Sending solenoid cfg.<br />
Skipping sending color table.<br />
Sending save cfg command.<br />
Done save cfg command.<br />
</pre><br />
<br />
Run Gen2Test again with just the port parameter to check the new configuration.<br />
<br />
<pre><br />
% python Gen2Test.py -port=/dev/cu.usbmodem1411<br />
Sending inventory cmd<br />
Found 1 Gen2 brds.<br />
Addr = ['0x20']<br />
0x20 WingCfg = 0x01010202<br />
0x20 SOL_WING SOL_WING INP_WING INP_WING<br />
</pre><br />
<br />
This configuration will persist between power cycles, so once this step is complete, Gen2Test will not be needed again except to test the connection between the host computer and the '''OPP''' boards. To perform that test, unplug and plug-in the ''Processor'' and run Gen2Test again to confirm the configuration is saved as above.<br />
<br />
==== Upgrade Firmware ====<br />
<br />
If you are at firmware revision ''0.2.0.1'' or higher, the following command should work to upgrade a whole chain of processors:<br />
<br />
<code>python Gen2Test.py -port=/dev/cu.usbmodem1411 -upgrade</code><br />
<br />
It checks to see if all the cards have firmware version 0.2.0.1 or higher. At that point, it goes to the <code>OPP/Creator/Gen2Images</code> folder and looks for the newest version in that directory. Note that the files must end with the <code>.cvacd</code> extension.<br />
<br />
It then upgrades each of the cards in turn, starting with the first card, ending with the last card in the chain. This process replaces the cumbersome single processor method for lower firmware revisions.<br />
<br />
==== Display Switch Inputs ====<br />
<br />
To debug switch inputs, you can run <code>Gen2Test</code> with the following command:<br />
<br />
<code>python Gen2Test.py -port=/dev/cu.usbmodem1411 -test=1 -card=0</code><br />
<br />
The '''test=1''' command reads the inputs from the card, and displays them on the screen as a single continuously updated line. <br />
<br />
'''card=0''' tells the test to display the inputs for the first card in the chain. This even works with switch matrices, so it gives you the direct inputs and the 64 switch matrix inputs. It can only do a single card at a time because it continuously overwrites the line.<br />
<br />
== Connecting Multiple Boards ==<br />
<br />
Once each individual board is configured, the next step is to create the serial connection between boards by chaining them together via multiple 8-wire ribbon cables.<br />
<br />
==== Serial Cables ====<br />
<br />
The serial cables consist of standard 8-wire '''ribbon cable''' - usually a light grey or sometimes in rainbow colors - with '''FC-8P''' connectors on each end. These are '''IDC''' connectors, which is an acronym for ''Insulation Displacement Contact''. IDC connectors ''displace'' the insulation on a wire to make a connection.<br />
<br />
[[Image:fc-8p.jpg]]<br />
<br />
You place the wire flat inside the connector and compress the cover (using pliers or similar) to cut into the insulation and connect the wires. The cover locks and all 8 pins should now be connected. The ends can be trimmed with a side cutter or X-Acto knife. The connector should include a cap, used for extra support for the cable, under which the wire is bent prior to crimping.<br />
<br />
Each FC-8P connector will have a positioning tab on the housing, and it is recommended to have the tab facing down towards the cable on one end and facing out on the other, so the tab is the same direction at the top and bottom. It isn't critical but it makes it easier to install cables knowing the tab always faces the same direction.<br />
<br />
The finished cable should look similar to this example.<br />
<br />
[[Image:ribbon-cable.png]]<br />
<br />
==== First Processor ====<br />
<br />
The first board in the chain connects to the host controller via USB, and uses the integrated USB-to-Serial interface to connect to the ''Interface'' board via a 4-wire cable that must be constructed. This cable consists of two '''Molex 2.54mm''' housings and pins, which are part of the '''BoM''' for the ''Interface'' wing. <br />
<br />
It connects 5V and Ground to power the other boards in the chain, as well as the TX and RX serial lines used for communicating between ''Processors''.<br />
<br />
If you are not familiar with crimping Molex connectors, you can read a [http://www.pinrepair.com/connect/#good detailed tutorial] on the [http://www.pinrepair.com PinRepair] site that covers proper connection crimping prior to constructing the cable.<br />
<br />
Once both the 4-wire and ribbon cables are done, they can be connected to the ''Processor'' per the following diagram:<br />
<br />
[[Image:first-processor.png]]<br />
<br />
The ''Interface'' wing has two 2 x 4 2.54mm connectors labelled '''IN''' and '''OUT'''. The ribbon cable is connected to the '''OUT''' with the ribbon running down from the wing.<br />
<br />
==== Middle Processor ====<br />
<br />
The ribbon cable from the first board connects to the '''IN''' connector on the ''Interface'' wing of the middle ''Processor'' with the ribbon facing up, and another ribbon cable is connected to the '''OUT''' connector to lead to the next ''Processor''. This is repeated for each additional ''Processor'' in the chain until the last one, so you will need multiple ribbon cables.<br />
<br />
[[Image:middle-processor.png]]<br />
<br />
==== Last Processor ====<br />
<br />
On the last ''Processor'' in the Serial Chain, the ribbon cable from the previous ''Processor'' is attached to the '''IN''' connector and a '''Jumper''' is placed between '''Pins 3-4''' on the '''OUT''' connector, or the top right two pins, to ''terminate'' the chain by looping the serial connection together.<br />
<br />
Without the jumper, the serial connection chain will not work and any commands will fail.<br />
<br />
[[Image:last-processor.png]]<br />
<br />
==== Testing the Chain ====<br />
<br />
With the first ''Processor'' plugged into USB, all ''Processors'' should light up if wired correctly. If not, check the ribbon cables for correct orientation. Plugging them in backwards will not damage the boards but it will prevent them from getting power.<br />
<br />
Note on this example of a two board chain, the yellow LEDs are lit on both boards, indicating a successful connection:<br />
<br />
[[Image:chained-processors.jpg]]<br />
<br />
Running <code>Gen2Test</code> with only the port parameter should generate an inventory of all cards:<br />
<br />
<pre><br />
% python Gen2Test.py -port=/dev/cu.usbmodem1411<br />
Sending inventory cmd<br />
Found 2 Gen2 brds.<br />
Addr = ['0x20', '0x21']<br />
0x20 WingCfg = 0x01010202<br />
0x20 SOL_WING SOL_WING INP_WING INP_WING<br />
0x21 WingCfg = 0x02020202<br />
0x21 INP_WING INP_WING INP_WING INP_WING<br />
</pre><br />
<br />
== Wiring Examples ==<br />
<br />
At this point the controller boards are ready to be installed in the game and wired up to all solenoids, lamps and switches.<br />
<br />
[[Image:connected-boards.jpg]]<br />
<br />
==== Solenoids ====<br />
<br />
Solenoids are wired with positive voltage from the high voltage power supply (24V to 70V depending on your game) and the other lug to the ''Solenoid'' wing via the 2x6 Molex connector. When the MOSFET is triggered, it connects ground for that solenoid and it activates.<br />
<br />
'''NOTE:''' a '''4004 or similar''' diode must be placed across the positive and ground connections with the band towards the positive wire. This allows for the flyback voltage that is generated when a coil's magnetic field collapses. Without it, that voltage travels back to the ''Solenoid'' wing and will likely destroy the MOSFETs, so it is '''critical''' that the diode be in place.<br />
<br />
Direct switches are connected via the 1x4 Molex connector and wired to the Logic (5V) ground.<br />
<br />
[[Image:solenoid-wiring.png]]<br />
<br />
==== Incandescent Lamps ====<br />
<br />
Lamps are wired with positive voltage from the 6.3V power supply and connected to an ''Incandescent'' wing via the 1x8 Molex connector. The ground for the lamps is provided by the 1x2 Molex connector, which should be connected to the 6.3V power supply ground.<br />
<br />
[[Image:lamp-wiring.png]]<br />
<br />
==== Switches ====<br />
<br />
Switches are wired with ground from the logic (5V) power supply and connected to the ''Switch'' wing (directly to the ''Processor'') via the 1x8 Molex connector. Power is provided via the ''Interface'' card from the USB connection.<br />
<br />
[[Image:switch-wiring.png]]<br />
<br />
==Arduino and OPP ==<br />
<br />
Although designed specifically to be used with the Cyruss processors boards, the wings can be driven by alternative microcontrollers, such as ''Arduino'' and others.<br />
<br />
==== Connecting a Coil Wing to an Arduino ====<br />
<br />
The +5V and +12V pins near R4 are unused for the basic operation of the MOSFETs. Only the ground pin near R4 is required. This should be connected to the ground coming from the +5V logic power source. It would also work to connect this directly to a ground pin on the ''Arduino''. If this pin is not grounded correctly or has an intermittent connection, you will see random MOSFET firing. <br />
<br />
Connect pins 4 - 7 to an ''Arduino'' pin configured for ''output'' and drive them ''high'' (+5V with the standard MOSFETs) to activate a solenoid. <br />
<br />
The '''Auto Fire''' pin header is not used directly by the boards. It is simply a pass thru to pins 0 - 3. You can leave the 4 pin header off for most purposes. One possible use is to flip the header around and use it to make a more secure connection to the ground pin mentioned previously.<br />
<br />
==== Driving Coils from the Arduino Software ====<br />
<br />
The ''Arduino'' '''digitalWrite''' command is quite slow, due to some error checking that is done in the background. This may introduce lag into the solenoid firing. A discussion of the problem, and how it can be remedied, can be found [http://www.instructables.com/id/Arduino-is-Slow-and-how-to-fix-it/ here].<br />
<br />
==== Connecting a Coil Wing to MPF ====<br />
See the [http://docs.missionpinball.org/en/latest/hardware/opp/index.html MPF Documentation about OPP] for details.<br />
<br />
== Troubleshooting ==<br />
<br />
If after assembling the boards and testing the connections they do not work, see below for some suggestions on next steps.<br />
<br />
==== Python Errors ====<br />
<br />
<code>IndexError: string index out of range</code> <br />
<br />
This error means that the serial communication failed and no results were returned.<br />
<br />
* Has the firmware been installed?<br />
* Has the ''Processor'' been correctly configured for the wings that are installed?<br />
* Is the yellow power LED on when plugged into USB?<br />
* Are you using the correct serial port? Note that on Raspberry Pi PCs that the default driver for the Cypress processors needs to be disabled in <code>/etc/modprobe.d</code>. See the [[#Firmware|Firmware]] section for details.<br />
<br />
<br />
If the answers to the above questions are ''Yes'', then the issue may be hardware related.<br />
<br />
<code>ImportError: No module named serial</code><br />
<br />
This error is generated when you do not have the '''pyserial''' module installed on your host PC. It can be installed via <code>pip install pyserial</code>.<br />
<br />
Download page for pyserial for Windows and other OSes: [https://pypi.python.org/pypi/pyserial https://pypi.python.org/pypi/pyserial]<br />
<br />
==== Hardware Checklist ====<br />
<br />
More often than not, due to having to self-assemble the boards, assembly errors can cause issues. Here is a checklist of possible reasons why a ''Processor'' may not respond to commands.<br />
<br />
* Check 5V at multiple points: Interface wing, USB-to-Serial interface, bottom of Cypress board<br />
* Check ground connections are correct and solid with no breaks in the solder<br />
* Use a multimeter to confirm RX/TX lines are cut<br />
* When testing a single board, confirm both RX and TX lines are correctly jumpered on USB-to-Serial interface<br />
* When testing multiple boards, confirm all cables are correctly oriented<br />
* When testing multiple boards, confirm last board is correctly terminated with a jumper on pins 3-4 of OUT connector <br />
<br />
==== Contact OPP Support ====<br />
<br />
If a reason for the failure cannot be found, the maintainer of the Open Pinball Project offers support via email at:<br />
<br />
[[Image:opp_email.png]]<br />
<br />
The maintainer is extremely responsive to questions and can often help find the issue with your setup. However, remember that OPP is run by volunteers, so they may not respond immediately to requests for help.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Controlling_Coils&diff=52262Controlling Coils2018-05-03T21:33:05Z<p>Jab: </p>
<hr />
<div>== Hardware == <br />
<br />
The usual way to control coils is to connect power to one side of the coil and to connect the other side to a low-side transistor circuit, such as an n-channel MOSFET. When the transistor is activated, the source voltage has a path to ground through the coil and through the transistor, thereby activating the coil.<br />
<br />
Coils are typically controlled with a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] board. It's best to connect the power side of the coil to the fused power output connector on the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]. This will cause only the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]'s fuse to blow if there's ever a serious problem with the coil circuit, rather than taking out various other things on the machine. The other side of the coil is then connected to one of the eight transistor circuits the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] provides in each bank.<br />
<br />
As shown in the diagram below, banks A and B of the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] are completely independent. The voltages used to feed each bank can be the same, but they don't have to be. This diagram is showing how to use bank A to control high power coils and bank B to control low power coils or flashlamps.<br />
<br />
[[Image:Power-Driver-16-example-use.jpg|500px]]<br />
<br />
=== Controlling coils ===<br />
<br />
Coils are used for a variety of features in most pinball machines. Common features with coils are flippers, slingshots, pop bumpers, drop targets, diverters, etc. Most coils are simply a long wire wrapped around a hollow core. When current flows through through the wire, a magnetic field is created in the core. This magnetic field pulls in metal objects. Typically, a steel rod (plunger) is connected to the playfield feature. When the coil is activated (current applied), the steel rod is pulled into the core due to the magnet field. The movement of the rod translates to movement of the feature. For instance, a pop bumper typically has a metal ring attached to the plunger that gets pulled down toward the playfield when the coil activates. This downwards motion pushes the ball away from the pop bumper.<br />
<br />
As shown in the picture below, a coil generally has two lugs, sometimes with a diode wired between them.<br />
<br />
[[Image:P-Coil.jpg|300]]<br />
<br />
To connect a coil to a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] board, simply wire power out from the desired bank (J3 or J4) to one lug, and one of the bank's 8 transistor circuits (J7 or J11) to the other lug. <br />
<br />
'''Important''': If the coil has diode, you MUST wire power out to the bar end of the diode and the transistor circuit to the non-bar end of the diode. Otherwise, bad things ensue (blown diodes, blown transistors, blown fuses, etc). The [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] boards have their own diodes on each circuit; so diodes on the coils are unnecessary.<br />
<br />
=== Controlling Flippers ===<br />
<br />
[[Controlling Flippers|Click here for a more detailed description of flipper control.]]<br />
<br />
== Software ==<br />
<br />
=== P-ROC ===<br />
<br />
The P-ROC can be configured to automatically control your chain of driver boards, allowing you to issue higher level commands (pulse, schedule, patter, etc). If you're using libpinproc (C) or pyprocgame (Python), you'll first need to configure the P-ROC to work with your chain of driver boards. Instructions for doing this are [[Configuring Driver Boards|found here]].<br />
<br />
<br />
==== libpinproc ====<br />
<br />
To activate the coils in a C program using libpinproc, you simply need to call the desired PRDriver... libpinproc function, passing in the handle to your P-ROC, the coil number, and the desired activation params. For instance, to pulse coil 32 for 40 milliseconds:<br />
<br />
PRDriverPulse(PRHandle, 32, 40)<br />
<br />
Other available driver commands include:<br />
<br />
PRDriverSchedule() - Issue a defined pattern that repeats every second<br />
PRDriverPatter() - Issue a repeating pitter-patter style pattern where the coil repeatedly turns on for X ms and off for Y ms.<br />
PRDriverPulsedPatter() - Same as above except the pattern ends after Z ms.<br />
PRDriverDisable() - Turn off the coil<br />
<br />
Refer to the [https://github.com/preble/libpinproc libpinproc code] for implementation details.<br />
<br />
'''Warning - It's best to use only PRDriverPulse() and PRDriverDisable() commands for high power coils. This will help to eliminate errors that could result in coils staying on too long and burning up or blowing fuses.'''<br />
<br />
==== pyprocgame ====<br />
<br />
Your machine's YAML file will need to contain coil definitions so that pyprocgame will know know which coils exist on your machine. Here's an example YAML with only the relevant coil items:<br />
<br />
PRGame:<br />
machineType: custom<br />
<br />
PRCoils:<br />
coil0:<br />
number: PD-16 circuit number for coil0 (0 for board 0, bank A, output 0)<br />
coil1:<br />
number: PD-16 circuit number for coil1 (1 for board 0, bank A, output 1)<br />
coil2:<br />
number: PD-16 circuit number for coil2 (8 for board 0, bank B, output 0)<br />
coil3:<br />
number: PD-16 circuit number for coil3 (16 for board 1, bank A, output 0)<br />
<br />
Once your YAML file is loaded into pyprocgame, you can activate your coils by calling:<br />
<br />
game.coils.coil0.pulse(40) - Drives coil0 for 40ms<br />
<br />
Other available driver methods include:<br />
<br />
schedule()<br />
patter()<br />
pulsedpatter()<br />
disable()<br />
enable()<br />
<br />
Refer to the [http://pyprocgame.pindev.org/ref/game.html#driver pyprocgame] docs more detailed information.<br />
<br />
'''Warning - It's best to use only pulse() and disable() commands for high power coils. This will help to eliminate errors that could result in coils staying on too long and burning up or blowing fuses.'''<br />
<br />
==== Mission Pinball Framework (MPF) ====<br />
See the [http://docs.missionpinball.org/en/latest/hardware/multimorphic/drivers.html MPF Documentation about P-Roc Coils] for details. <br />
<br />
==== Direct Control ====<br />
<br />
If you'd rather use software to write to the driver board directly, which is possible though eliminates the possibility of using the pulse, schedule, patter, etc functions the P-ROC provides, you can issue direct register writes to the P-ROC that, in turn, get sent to the appropriate driver board. Refer to the [http://www.pinballcontrollers.com/index.php/products/p-roc/documentation P-ROC FPGA documentation] for more details (register addresses and data format)<br />
<br />
=== Other controller (non - P-ROC) ===<br />
<br />
If you are using a microcontroller such as an Arduino or Parallax Propeller to control your flippers through a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16], you'll need to do everything in software. Refer to the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] documentation for a description of the PDB Protocol used for sending commands to the driver board.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Fast&diff=52261Fast2018-05-03T21:28:54Z<p>Jab: </p>
<hr />
<div>= Architecture =<br />
Fast Pinball offers a [http://fastpinball.com/platform/hardware pinball control systems] which consists of a controller and multiple node boards. There is currently only one controller available. It is called the [http://fastpinball.com/platform/hardware/controllers/fast-nano-controller Nano] and supports a chain of node boards and 128 serial RGB LEDs.<br />
<br />
The following node boards are available:<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-3208 Fast IO 3208] - 32 inputs and 8 drivers<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-1616 Fast IO 1616] - 16 inputs and 16 drivers<br />
* [http://fastpinball.com/platform/hardware/io/fast-io-0804 Fast IO 0804] - 8 inputs and 4 drivers<br />
<br />
Most machines use a 3208 for the lower playfield. The 0804 is often used as cabinet node. Upper playfield configurations differ.<br />
<br />
Node boards are connected in a Ring using RJ45 cables. Nano connects to the first board (ID 0). First board to the second and so on. Last board connects back to the Nano.<br />
<br />
= Switches =<br />
Switches are organized in banks of 8. They contain pull up the voltage to 12V using an internal pull up. If you connect an switch input to ground the switch will be considered closed. You can connect normal pinball switches and optos directly to inputs.<br />
<br />
= Drivers =<br />
Boards contain drivers in banks of 8 (except the 0804 which contains a bank of only 4 drivers). All drivers pull to ground. Connect your mechs to high voltage (HV) and connect the other side to a driver. When the driver is activated the current will flow.<br />
<br />
= Flipper rules =<br />
Fast supports only node local rules which means that switch and driver have to be on the same board. <br />
For instance if the switch of a popbumper is connected to switch 2 on node board 1 then the coil also has to be connected to an output on node board 1. The first 8 switches on the first board (ID 0) are special since those are local to every node board. E.g. you can connect your flipper buttons to inputs 0 and 1 on the first node board (as cabinet node board) and connect the drivers to node 2 below the playfield.<br />
<br />
= DMDs =<br />
Fast offers a standalone RGB DMD display which interfaces via USB.<br />
<br />
= Special hardware =<br />
All Fast node board support one daughter board.<br />
Currently there is a servo daughter board for six servos.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Fast&diff=52260Fast2018-05-03T21:27:58Z<p>Jab: Created page with "= Architecture = Fast Pinball offers a [http://fastpinball.com/platform/hardware pinball control systems] which consists of a controller and multiple node boards. There is cur..."</p>
<hr />
<div>= Architecture =<br />
Fast Pinball offers a [http://fastpinball.com/platform/hardware pinball control systems] which consists of a controller and multiple node boards. There is currently only one controller available. It is called the [http://fastpinball.com/platform/hardware/controllers/fast-nano-controller Nano] and supports a chain of node boards and 128 serial RGB LEDs.<br />
<br />
The following node boards are available:<br />
[http://fastpinball.com/platform/hardware/io/fast-io-3208 Fast IO 3208] - 32 inputs and 8 drivers<br />
[http://fastpinball.com/platform/hardware/io/fast-io-1616 Fast IO 1616] - 16 inputs and 16 drivers<br />
[http://fastpinball.com/platform/hardware/io/fast-io-0804 Fast IO 0804] - 8 inputs and 4 drivers<br />
<br />
Most machines use a 3208 for the lower playfield. The 0804 is often used as cabinet node. Upper playfield configurations differ.<br />
<br />
Node boards are connected in a Ring using RJ45 cables. Nano connects to the first board (ID 0). First board to the second and so on. Last board connects back to the Nano.<br />
<br />
= Switches =<br />
Switches are organized in banks of 8. They contain pull up the voltage to 12V using an internal pull up. If you connect an switch input to ground the switch will be considered closed. You can connect normal pinball switches and optos directly to inputs.<br />
<br />
= Drivers =<br />
Boards contain drivers in banks of 8 (except the 0804 which contains a bank of only 4 drivers). All drivers pull to ground. Connect your mechs to high voltage (HV) and connect the other side to a driver. When the driver is activated the current will flow.<br />
<br />
= Flipper rules =<br />
Fast supports only node local rules which means that switch and driver have to be on the same board. <br />
For instance if the switch of a popbumper is connected to switch 2 on node board 1 then the coil also has to be connected to an output on node board 1. The first 8 switches on the first board (ID 0) are special since those are local to every node board. E.g. you can connect your flipper buttons to inputs 0 and 1 on the first node board (as cabinet node board) and connect the drivers to node 2 below the playfield.<br />
<br />
= DMDs =<br />
Fast offers a standalone RGB DMD display which interfaces via USB.<br />
<br />
= Special hardware =<br />
All Fast node board support one daughter board.<br />
Currently there is a servo daughter board for six servos.</div>Jabhttps://pinballmakers.com/wiki/index.php?title=P-ROC_software_main&diff=52259P-ROC software main2018-05-03T21:09:56Z<p>Jab: </p>
<hr />
<div>== [[P-ROC Software Architecture]] ==<br />
<br />
<br />
==Installation/Build Instructions==<br />
<br />
Build instructions are available for (this is needed for skeletongame/pyprocgame):<br />
<br />
* [[Windows build instructions|Windows (MinGW)]]<br />
* [[Windows build instructions VS|Windows (Visual Studio)]]<br />
* [[Linux build instructions|Linux]]<br />
* [[Mac build instructions|Mac]]<br />
<br />
If you are using the Mission Pinball Framework (MPF) follow [http://docs.missionpinball.org/en/latest/hardware/multimorphic/index.html this tutorial] and the [http://docs.missionpinball.org/en/latest/install/index.html installation instructions] instead.<br />
<br />
==[[Sample Game Files]]==<br />
[[Sample Game Files]]<br />
<br />
== Game Development Resources ==<br />
<br />
* [[Fonts]] (.dmd format)</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Programming&diff=52225Programming2017-09-28T23:12:39Z<p>Jab: /* Pinball Frameworks */</p>
<hr />
<div>After the initial [[Construction#Whitewood|whitewood]] has been built, it is time to bring it to life by programming the control system and adding game rules.<br />
<br />
== Languages ==<br />
<br />
The programming language being used is going to be dictated primarily by the hardware control system chosen. Off the shelf systems such as '''[[Construction#Off-the-Shelf_Boards|P-ROC or Fast]]''' have a close relationship to '''[http://github.com/preble/pyprocgame PyProcGame]''', which is dedicated exclusively to the P-ROC, or the '''[https://missionpinball.com/framework/ Mission Pinball Framework]''' which supports both P-ROC and FAST and is a more higher level programming framework.<br />
<br />
For more lower-level control, there is the [http://github.com/preble/libpinproc libpinproc] library for P-ROC boards, which allow binding into other languages and building of custom frameworks using things like [http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer SDL] or [http://www.sfml-dev.org/ SFML] which provides access to ''OpenGL'' and other graphics APIs.<br />
<br />
If using custom hardware, it is up to the designer to decide on how to interface with the controller.<br />
<br />
=== Pinball Frameworks ===<br />
<br />
To make programming pinball machines easier, a number of frameworks are available to use that provide a baseline of functionality.<br />
<br />
* [https://missionpinball.org/ Mission Pinball]: Currently supports P-ROC, FAST and [[OPP|Open Pinball Project]] controllers, written in Python. Uses YAML config files to define functions. [http://docs.missionpinball.org/ Mission Pinball Documentation]<br />
* [http://pyprocgame.pindev.org/ PyProcGame]: Developed specifically for the P-ROC controllers, written in Python<br />
* [http://skeletongame.com/ SkeletonGame]: Based on PyProcGame<br />
* [https://github.com/preble/libpinproc libPinPROC]: Lower level C library for P-ROC<br />
* [http://mypinballs.co.uk/electronics/store.jsp myPinballs]: Framework written in C for developing custom games in conjunction with the myPinballs Custom Controller Board Set for early 80s Bally/Stern games. <br />
<br />
<br />
The following is a breakdown of the hardware and functionality support for the top three frameworks.<br />
<br />
{| class="wikitable" style="text-align: center;"<br />
!<br />
! Mission Pinball Framework<br />
! PyProcGame<br />
! SkeletonGame<br />
|-<br />
!Hardware<br />
| <br />
|<br />
|<br />
|-<br />
| P-ROC<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| FAST <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| OPP <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Stern SPIKE <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Gottlieb System1/80<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Displays<br />
|<br />
|<br />
|<br />
|-<br />
| LCD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| DMD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Alphanumeric<br />
| style="color: white; background-color: green;"| ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Lighting<br />
|<br />
|<br />
|<br />
|-<br />
| Incandescent<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Serial LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
! Devices<br />
|<br />
|<br />
|<br />
|-<br />
| Coils<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Motors / Servos<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
! Standard Functions<br />
|<br />
|<br />
|<br />
|-<br />
| Config File Setup<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Custom Code<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Service Menu<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
|}<br />
<br />
== Rules ==<br />
<br />
As pinball hardware advanced in complexity from simple relays to transistors, so did game rules. ''Electromechanical'' (EM) pinball machines often struggled to register multiple switch hits at the same time, while early ''Solid State'' (SS) games allowed fast response times and multiple concurrent switch hits to be registered. Faster CPUs with more memory allow for the deeper rule sets of modern pinball.<br />
<br />
Rules can be as simple as ''Complete the rollovers for bonus multiplier'' to stacking several mode-scoring multiballs together.<br />
<br />
=== Maintaining State ===<br />
<br />
Deeper rule tracking requires maintaining '''State''', which is a map (in memory) of the current switch conditions, such as:<br />
<br />
* What was the state of all the switches N seconds ago? <br />
* Has anything changed in N seconds?<br />
* How many times has a switch been hit total?<br />
<br />
<br />
These are all ''States'' and the control program keeping track of these allows for modes and other advanced rules.<br />
<br />
Think of an orbit shot: two switches, one of the left side orbit entry, one of the right side orbit entry. An orbit is complete if both switches are hit in order. It takes time for the ball to travel from one side to the other - there may be 5 seconds or more if the ball is slow, struggles to get to the apex, or dribbles down the other side. A failed orbit may count two hits to only one of the switches. It may count only one hit if the ball just makes it and rolls back down. The orbit shot is a good example of needing to know the previous switch state, the question then becomes, how many previous states to track? <br />
<br />
''Example'': If an orbit is a multiball jackpot shot, how to handle when a second ball enters the left orbit before the first ball has triggered the right orbit switch? This means an orbit that can be fed from either direction is probably not a good way to score a jackpot. This is why a ramp shot is very easy to track a jackpot on - ramps have an apex and once your past the apex, any exit switch hit from the ramp is easily countable. <br />
<br />
Another example of an advanced rule would be tracking the order of something - having five drop targets that give an extra bonus if hit in order of one to five, or five to one. This is a variable outside of standard switch state and it has to be managed outside of just target hits, as well as be reset on a ball drain, reset if a mode changes, or reset if the drop targets are reset.<br />
<br />
Code complexity is increased by remembering the state of that variable and which targets have been hit or not between changing players.<br />
<br />
The deeper rules become, the more variables, flags and timers that are needed to be tracked and managed, and the more difficult the code becomes to debug and maintain.<br />
<br />
Some other examples of maintaining state:<br />
<br />
* If a target enables a kickback, will extra kick backs be added if it is already lit?<br />
* Knowing how many balls are in the ball trough before lighting the add-a-ball insert.<br />
<br />
=== Game Logic Flow ===<br />
<br />
For an example of a typical layout of general game rules and how the logic should flow, see the [[Rule Flow]] subpage.<br />
<br />
=== Priority ===<br />
<br />
Modes, display events and sounds all need to be '''prioritized''' relative to each other - for example, background displays or sounds are a lower priority than a switch hit or score display. <br />
<br />
For example, if a high priority sound is playing, and the ball hits a switch that triggers a low priority sound effect, the control program can skip playing the lower priority sound, or play it at a lower volume. Or, if there is a display event for a pop bumper hit, it will be higher priority than the score display.<br />
<br />
== Light Shows ==<br />
<br />
With modern CPU-controlled lamps, it is possible to use general illumination, flashers and playfield insert lamps to produce '''Light Shows''' during Attract mode to bring attention to the game from a passer-by, or while the game is active to convey information to the player.<br />
<br />
For example, lighting lamps from the bottom of the playfield up to the top, then turn them off from the bottom up would be a distinct lamp show used during Attract mode. Below shows part of the attract mode for ''High Speed'' which uses multiple techniques.<br />
<br />
[[Image:high-speed-attract-mode.gif]]<br />
<br />
''Mission Pinball Framework'' supports the concept of [https://missionpinball.com/docs/lighting/light-scripts/ Light scripts], which allow a maker to script what lamps are lit, for how long, and at a specific brightness to produce various effects.<br />
<br />
=== Light Groups ===<br />
<br />
Lights can be put into ''groups'' of similar lamps that allow for specific light effects. For example ''High Speed'' has the circular rev lamps, which lend themselves to a circular lamp effect, or the lamps in a row above them are well suited to a side-to-side effect.<br />
<br />
=== Backbox ===<br />
<br />
Most modern games have abandoned controlled lamps in the backbox to save on costs, but a garage maker has no such restrictions on creativity and can add various light effects to the backglass. Separating sections off to light separately is a common technique.<br />
<br />
[[Image:backbox-light-show.gif]]<br />
<br />
== Settings / Preferences ==<br />
<br />
=== Audits ===<br />
<br />
Auditing for a pinball machine involves keeping a tally of various activities, such as:<br />
<br />
* Total plays<br />
* Total balls played<br />
* Coins dropped<br />
* Replays awarded<br />
<br />
<br />
Creating audit tracking is easy, programming-wise. When a game is over, you would simply increment the "total games played" variable up by one. <br />
<br />
=== Settings ===<br />
<br />
These are values that modify the game rules. Most modern games have dozens of settings that dramatically alter game play. Some examples include:<br />
<br />
* Free Play<br />
* Balls Per Game<br />
* Replay enabled<br />
* Replay score percentage<br />
* Extra balls enabled<br />
* Ball Save enabled<br />
<br />
<br />
=== Diagnostics ===<br />
<br />
Another benefit of the switch from EM to Solid State electronics was the ability to include '''Diagnostics''' as a standard part of new games. The operator can run quick diagnostics on a machine without having to lift the playfield. Some example include:<br />
<br />
* '''Switch Test''': With the playfield glass removed, switches can be individually tested, with the number being shown on numerical scoring games, or the matrix coordinates being shown on DMD pins.<br />
* '''Sound Test''': With modern computer-based pinball machines, this test might be obsolete.<br />
* '''Coil Test''': Coils can be individually fired for checking faults, or all coils fired in order to test all coils.<br />
* '''Light Test''': Insert lights can be checked for burned out bulbs by flashing them individually.<br />
* '''Unique Mechanism Test''': This would apply to parts unique to the machine. An example would be the rotating box on ''Bally Theatre of Magic''.<br />
<br />
== Scoring ==<br />
<br />
For scoring, a separate scoring subroutine should be used and called as needed. This routine can do checks for earning game-wide rewards (points, replay) each time a player's score is incremented. Having it separate also allows for incorporating a ''double score'' mode for adding twice the amount of points without having to incorporate the mode check in each target hit routine.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
def add_score(points):<br />
game.curplayer.score = game.curplayer.score + points<br />
if curplayer.score => game.settings.replayscore:<br />
award_replay()<br />
</pre><br />
<br />
=== Bonus Lanes ===<br />
<br />
Bonus lanes are typically located at the top of the playfield, consisting of three or more lanes a ball can fall through at random. A ball falling through one of the lanes will light the lane. A bonus will be awarded, typically with a bonus multiplier (but can vary) if all the lanes are lit. <br />
<br />
Beginning with ''Williams Firepower'', hitting the flipper buttons would cycle the lit lanes left or right, allowing the player to move the unlit lane under the falling ball, achieving the bonus. Bonus lanes are frequently incorporated into the skill shot.<br />
<br />
Layout:<br />
<br />
* One switch per lane. <br />
* Each lane will have one light associated with it. Some games have two lights per lane, creating two sets of bonus lanes (Example: ''Williams Barracora''').<br />
<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
cur_bonus = 1 <br />
lane1 = off <br />
lane2 = off<br />
lane3 = off<br />
tmplane = off<br />
<br />
def switch1_hit<br />
lane1 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane1 = on<br />
<br />
def switch2_hit<br />
lane2 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane2 = on<br />
<br />
def switch3_hit<br />
lane3 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane3 = on<br />
<br />
// and the code for cycling the bonus lanes, tied to flipper button<br />
<br />
// code for checking all bonus lanes<br />
def check_all_lanes()<br />
with curplayer<br />
if (lane1 = on) + (lane2 = on) + (lane3 = on)<br />
increase_bonus()<br />
play_sound(yay_bonus!)<br />
display_msg("BONUS INCREASED")<br />
// shut off states & reset!<br />
lights.lane1 = off<br />
lights.lane2 = off<br />
lights.lane3 = off<br />
<br />
// the code for increasing the bonus multiplier <br />
// bonus held not implemented<br />
<br />
def increase_bonus()<br />
curplayer.cur_bonus = curplayer.cur_bonus + 1<br />
// give any special award if it is at a high #<br />
</pre><br />
<br />
== Game Modes ==<br />
<br />
These are modes that are specific to the game in question and relate to the theme or specific special devices included in the design. They can also fall outside regular gameplay - for example, ''Bally Safecracker'' has a special ''Assault the Vault'' mode triggered by using a unique token in the coin slot. Or ''Williams Black Knight'' and ''Time Fantasy'', which have a special post-game timed mode governed by time earned in regular gameplay, where you have unlimited balls to score extra points. <br />
<br />
=== General Modes ===<br />
<br />
These are modes that are general to most games, rather than rules specific to the machine's theme.<br />
<br />
==== Game Start ====<br />
<br />
==== Game End ====<br />
<br />
After the game ends, cleanup of the playfield device and some variables internal to the software should be done. Examples in no particular order include:<br />
<br />
* Release any locked balls from kickers<br />
* Release any locked balls from vertical upkickers<br />
* Disable flippers<br />
* Return any mechanical devices to Game Start state<br />
* Check for any high scores achieved by any players and record initials<br />
* Run Replay Match<br />
* Set number of current players to zero<br />
* Null/delete any player objects<br />
* Delete the game session object<br />
* Audits - increase # of games played, etc.<br />
<br />
==== Replay Match ====<br />
<br />
==== Ball Seek ====<br />
<br />
In the event a ball gets stuck and the player is unable to play, many machines will go into a '''Ball Seek''' mode. All mechanisms that interact with the ball will individually fire after a specified "idle" delay in an attempt to free the stuck ball. The ''Ball Seek'' mode will often run continuously until the missing ball is found, or only repeat a few times at which point the ball is marked as ''lost'' and game play continues, with the software compensating for the missing ball as best as possible.<br />
<br />
A timer is updated to check for any '''idle time''' of the ball - any switch hits (indicating ball movement) resets this timer. If no switch activity occurs for a specified period of time (as set by an operator setting), the '''Ball Seek''' subroutine would be run.<br />
<br />
Put the timer reset calls through all the switch detection events (except for shooter lane, tilt plumb, buttons) as those switch hits indicate a healthy running ball session.<br />
<br />
A ball in the shooter lane should disable the timer, with it starting after confirming a ball has been launched and is in play. For convenience sake, invoke the ball seek timer after a player has passed or failed the skill shot. So, just after shutting down the skill shot (if implemented), start the ball save timer.<br />
<br />
Shut down the ball save timer once the ball session is over. <br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// invoke the ball seeker routine<br />
def bs_timer_start()<br />
// ball saver invoked<br />
bs_timer_countdown = 60<br />
<br />
// reset the timer<br />
def bs_timer_reset()<br />
bs_timer_countdown = 60<br />
<br />
// shut down the timer entirely<br />
def bs_timer_shutdown()<br />
bs_timer_countdown = -1<br />
<br />
// this runs when the timer has expired<br />
def ball_saver()<br />
if ( bs_timer_countdown = 0 ) <br />
// fire the coils<br />
coils.popbumper1.fire()<br />
// fire drop target reset<br />
coils.dtbank1.fire()<br />
// and so forth<br />
// reset timer and hopefully we won't have to run it again<br />
bs_timer_reset()<br />
<br />
// example of the 1 of many target hits<br />
// that show the timer reset routine<br />
def leaftarget1_hit()<br />
score.addpoints(50)<br />
sound.play("boop")<br />
bs_timer_reset()<br />
</pre><br />
<br />
==== Ball Save ====<br />
<br />
'''Ball save''' is when a ball in play is drained out shortly into the ball session. This routine can be triggered via the outlanes or center drain.<br />
<br />
Typically ''Ball Save'' is either time-based or score-based. The allowed time for ball save to be active can be set via '''Preferences'''.<br />
<br />
==== Extra Ball ====<br />
<br />
==== Skill Shot ====<br />
<br />
'''Skill Shots''' are available when the player first plunges the ball. Plunging the ball at the right strength, or at the right time, or hitting a specific switch, will earn the player a reward - generally a bonus multiplier or a large points bonus.<br />
<br />
Used in conjunction with a physical plunger (as opposed to an autoplunger), plunging the ball at just the right strength to hit a specific switch will award the ''Skill Shot'' value.<br />
<br />
Some shots are ''Strength-based'', where a group of targets or switches can be hit by the ball from the plunger, and the indicated target or switch, when hit, will award the value. Of these types, variations include the '''Side''' style where the ball is aimed at targets in a vertical alignment (as in ''Williams No Good Gofers''), or '''Over''' where the ball is plunged over the switches, as shown in this example from ''Williams Pinbot'':<br />
<br />
[[Image:pinbot-skill.jpg|400px]]<br />
<br />
For games with autoplungers, there are ''Time-based'' examples where the player must time the activation of the plunger to correspond with the ball hitting a lit target - ''Williams Terminator 2'' is an example of this type. Many autoplunger games use a randomly-chosen ''Bonus Lane'', where the skill shot is achieved if the ball goes through the indicated lane at the end of a plunge. <br />
<br />
When coding, the logic is:<br />
<br />
* Initialize the skill shot mode at the begin of a ball session<br />
* End the skill shot after the player has passed or failed<br />
<br />
==== Tilt ====<br />
<br />
Although not thought of as a ''mode'', it fits the same model - it is triggered from one or multiple switch events, in this case, the switch being the tilt bob. When the tilt is triggered enough times (and after warnings issued), the game will end the current ball. <br />
<br />
A ''Tilt'' should trigger the following:<br />
<br />
* Disable Flippers<br />
* Shut off GI and any insert lights<br />
* Shut off music<br />
* Disable pop bumpers<br />
* Disable slingshots<br />
* Do not award end-of-ball bonus points<br />
<br />
Once the ball is returned the trough, regular play resumes.<br />
<br />
An additonal mode is the '''Slam Tilt''', triggered by a switch on the coin door. The main difference is that the whole game for all players will be immediately ended, as to punish the player for being rough with the machine.<br />
<br />
==== Status Report ====<br />
<br />
Generally activated by holding down both flippers.<br />
<br />
[[Status Report]]<br />
<br />
=== Device Modes ===<br />
<br />
These are general modes that trigger specific mechanical devices.<br />
<br />
==== Kickback ====<br />
<br />
See the [[Kickback]] subpage for hardware details.<br />
<br />
For the kickback, some checks will need to be done to ensure that the ball is out of the outlane area. One solution is to leave it active for a specified period of time to give an additional kickback to ensure the ball is out.<br />
<br />
Other triggers may include:<br />
<br />
* A sound or call-out indicating to the player that kickback is enabled<br />
* A sound or call-out when kickback is invoked<br />
<br />
<br />
The action to activate the kickback is to pulse the solenoid. What is critical is getting the timing correct where it does not fire too soon, or too late, where the ball will be missed. Some timing adjustments will need to be done to find the sweet spot where it will handle the most amount of ball velocity variations.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
kickback_enabled = (on/off) <br />
<br />
// scope: ball session<br />
<br />
def enable_kickback()<br />
ballsess.kickback_enabled = on<br />
lights.kb = flashy<br />
play.sound("kickback is on!")<br />
<br />
// switch hit event for the left outlane<br />
// determines if you drain or kick<br />
<br />
def leftoutlane_sw()<br />
if ballsess.kickback_enabled = on<br />
( kickback_fire() )<br />
else<br />
score.addpoints(50)<br />
sound.play("aww shucks")<br />
<br />
// fire the kickback<br />
<br />
def fire_kickback()<br />
sound.play("misspiggy hiyah!")<br />
coils.kickback.pulse()<br />
<br />
// insert any additional "keep hot" code here<br />
// okay, shut off the kickback<br />
disable_kickback()<br />
<br />
// shut off kb<br />
// also shut this off if you tilt<br />
<br />
def disable_kickback()<br />
ballsess.kickback_enabled = off<br />
lights.kb = off<br />
</pre><br />
<br />
==== Ball Trough ====<br />
<br />
See the [[Ball Trough]] subpage for hardware details.<br />
<br />
Pseudocode example:<br />
<pre><br />
<br />
// callback function<br />
// returns true if the trough is full<br />
function is_trough_full()<br />
if (trsw1 = true) + (trsw2=true) + (trsw3=true)<br />
return true<br />
else<br />
return false<br />
</pre><br />
<br />
==== Drop Targets ====<br />
<br />
See the [[Drop Targets]] subpage for hardware details.<br />
<br />
For a drop target bank, a check is needed after every drop target hit. As an example of using ''state'' to manage the game, a player could be awarded points for hitting the drop targets in order (Example: ''Bally Centaur''), or award points for completing multiple sets of drop target banks. <br />
<br />
Pseudocode:<br />
<br />
<pre><br />
// variable scope(current ball session)<br />
dbank1 = off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
def dbank1_hit()<br />
score.addpoints(50)<br />
dbank1 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank2 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank3 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
// check to see if all the drop targets have been hit<br />
<br />
def check_dropbank1()<br />
if (dbank1= on) & (dbank2=on) & (dbank3=on)<br />
// reward for completing drop target bank<br />
play_sound(chaching)<br />
score.addpoints(200)<br />
<br />
// reset the variables<br />
dbank1= off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
// reset 'em<br />
coils.dbank1.pulse()<br />
<br />
// separate routine for resetting drop target bank ,<br />
// add this to the "ball begin" routine<br />
<br />
def reset_drop_bank()<br />
coils.dbank1.pulse()<br />
</pre><br />
<br />
==== Slingshots ====<br />
<br />
See the [[Slingshots]] subpage for hardware details.<br />
<br />
Most off-the-shelf controllers allow a user to create '''Triggers''', where if a specific switch is hit, it causes a specific coil to fire. For slingshots, this is all that is needed for them to operate as expected, plus recording any scoring involved.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Kicker Hole ====<br />
<br />
See the [[Kicker Hole]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Divertors ====<br />
<br />
See the [[Divertors]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Vertical Up-Kickers ====<br />
<br />
See the [[VUK]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
== Sound ==<br />
<br />
Sound is a critical component of any pinball machine. EM games used bells and chimes to inform the player while modern games use digitized voice callouts and stereo music.<br />
<br />
Some things to consider when deciding on how to incorporate sound in a game include:<br />
<br />
* Avoid playing sounds continuously over the top of one another. For example, having an explosion sound when a pop bumper is triggered - if the ball is getting a lot of pop bumper action and it triggers three pops in very fast succession, restarting the sound event on each trigger would sound like white noise. Thus, choose not to play the same sound effect unless N time has passed (say 3 seconds), or never play the same sound affect at the same time.<br />
* Too many sound effects playing over each over mutes the effect it should have on the player and can be confusing.<br />
* Timing of sound events should be kept short, as the longer the sound, the more likely it will overlap with another switch event trigger, leading to too many overlapping sound events or the white noise problem mentioned earlier.<br />
* Normalize the volume of all the sound effects to the same level to maintain a common volume level on the machine itself. <br />
<br />
[[sound assignments]]<br />
<br />
[[Music loops]]<br />
<br />
[[Basic sounds]]<br />
<br />
[[voice callouts]]</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Programming&diff=52224Programming2017-09-28T23:10:56Z<p>Jab: /* Pinball Frameworks */</p>
<hr />
<div>After the initial [[Construction#Whitewood|whitewood]] has been built, it is time to bring it to life by programming the control system and adding game rules.<br />
<br />
== Languages ==<br />
<br />
The programming language being used is going to be dictated primarily by the hardware control system chosen. Off the shelf systems such as '''[[Construction#Off-the-Shelf_Boards|P-ROC or Fast]]''' have a close relationship to '''[http://github.com/preble/pyprocgame PyProcGame]''', which is dedicated exclusively to the P-ROC, or the '''[https://missionpinball.com/framework/ Mission Pinball Framework]''' which supports both P-ROC and FAST and is a more higher level programming framework.<br />
<br />
For more lower-level control, there is the [http://github.com/preble/libpinproc libpinproc] library for P-ROC boards, which allow binding into other languages and building of custom frameworks using things like [http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer SDL] or [http://www.sfml-dev.org/ SFML] which provides access to ''OpenGL'' and other graphics APIs.<br />
<br />
If using custom hardware, it is up to the designer to decide on how to interface with the controller.<br />
<br />
=== Pinball Frameworks ===<br />
<br />
To make programming pinball machines easier, a number of frameworks are available to use that provide a baseline of functionality.<br />
<br />
* [https://missionpinball.com/framework/ Mission Pinball]: Currently supports P-ROC, FAST and [[OPP|Open Pinball Project]] controllers, written in Python. Uses YAML config files to define functions<br />
* [http://pyprocgame.pindev.org/ PyProcGame]: Developed specifically for the P-ROC controllers, written in Python<br />
* [http://skeletongame.com/ SkeletonGame]: Based on PyProcGame<br />
* [https://github.com/preble/libpinproc libPinPROC]: Lower level C library for P-ROC<br />
* [http://mypinballs.co.uk/electronics/store.jsp myPinballs]: Framework written in C for developing custom games in conjunction with the myPinballs Custom Controller Board Set for early 80s Bally/Stern games. <br />
<br />
<br />
The following is a breakdown of the hardware and functionality support for the top three frameworks.<br />
<br />
{| class="wikitable" style="text-align: center;"<br />
!<br />
! Mission Pinball Framework<br />
! PyProcGame<br />
! SkeletonGame<br />
|-<br />
!Hardware<br />
| <br />
|<br />
|<br />
|-<br />
| P-ROC<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| FAST <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| OPP <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Stern SPIKE <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Gottlieb System1/80<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Displays<br />
|<br />
|<br />
|<br />
|-<br />
| LCD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| DMD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Alphanumeric<br />
| style="color: white; background-color: green;"| ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Lighting<br />
|<br />
|<br />
|<br />
|-<br />
| Incandescent<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Serial LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
! Devices<br />
|<br />
|<br />
|<br />
|-<br />
| Coils<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Motors / Servos<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
! Standard Functions<br />
|<br />
|<br />
|<br />
|-<br />
| Config File Setup<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Custom Code<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Service Menu<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
|}<br />
<br />
== Rules ==<br />
<br />
As pinball hardware advanced in complexity from simple relays to transistors, so did game rules. ''Electromechanical'' (EM) pinball machines often struggled to register multiple switch hits at the same time, while early ''Solid State'' (SS) games allowed fast response times and multiple concurrent switch hits to be registered. Faster CPUs with more memory allow for the deeper rule sets of modern pinball.<br />
<br />
Rules can be as simple as ''Complete the rollovers for bonus multiplier'' to stacking several mode-scoring multiballs together.<br />
<br />
=== Maintaining State ===<br />
<br />
Deeper rule tracking requires maintaining '''State''', which is a map (in memory) of the current switch conditions, such as:<br />
<br />
* What was the state of all the switches N seconds ago? <br />
* Has anything changed in N seconds?<br />
* How many times has a switch been hit total?<br />
<br />
<br />
These are all ''States'' and the control program keeping track of these allows for modes and other advanced rules.<br />
<br />
Think of an orbit shot: two switches, one of the left side orbit entry, one of the right side orbit entry. An orbit is complete if both switches are hit in order. It takes time for the ball to travel from one side to the other - there may be 5 seconds or more if the ball is slow, struggles to get to the apex, or dribbles down the other side. A failed orbit may count two hits to only one of the switches. It may count only one hit if the ball just makes it and rolls back down. The orbit shot is a good example of needing to know the previous switch state, the question then becomes, how many previous states to track? <br />
<br />
''Example'': If an orbit is a multiball jackpot shot, how to handle when a second ball enters the left orbit before the first ball has triggered the right orbit switch? This means an orbit that can be fed from either direction is probably not a good way to score a jackpot. This is why a ramp shot is very easy to track a jackpot on - ramps have an apex and once your past the apex, any exit switch hit from the ramp is easily countable. <br />
<br />
Another example of an advanced rule would be tracking the order of something - having five drop targets that give an extra bonus if hit in order of one to five, or five to one. This is a variable outside of standard switch state and it has to be managed outside of just target hits, as well as be reset on a ball drain, reset if a mode changes, or reset if the drop targets are reset.<br />
<br />
Code complexity is increased by remembering the state of that variable and which targets have been hit or not between changing players.<br />
<br />
The deeper rules become, the more variables, flags and timers that are needed to be tracked and managed, and the more difficult the code becomes to debug and maintain.<br />
<br />
Some other examples of maintaining state:<br />
<br />
* If a target enables a kickback, will extra kick backs be added if it is already lit?<br />
* Knowing how many balls are in the ball trough before lighting the add-a-ball insert.<br />
<br />
=== Game Logic Flow ===<br />
<br />
For an example of a typical layout of general game rules and how the logic should flow, see the [[Rule Flow]] subpage.<br />
<br />
=== Priority ===<br />
<br />
Modes, display events and sounds all need to be '''prioritized''' relative to each other - for example, background displays or sounds are a lower priority than a switch hit or score display. <br />
<br />
For example, if a high priority sound is playing, and the ball hits a switch that triggers a low priority sound effect, the control program can skip playing the lower priority sound, or play it at a lower volume. Or, if there is a display event for a pop bumper hit, it will be higher priority than the score display.<br />
<br />
== Light Shows ==<br />
<br />
With modern CPU-controlled lamps, it is possible to use general illumination, flashers and playfield insert lamps to produce '''Light Shows''' during Attract mode to bring attention to the game from a passer-by, or while the game is active to convey information to the player.<br />
<br />
For example, lighting lamps from the bottom of the playfield up to the top, then turn them off from the bottom up would be a distinct lamp show used during Attract mode. Below shows part of the attract mode for ''High Speed'' which uses multiple techniques.<br />
<br />
[[Image:high-speed-attract-mode.gif]]<br />
<br />
''Mission Pinball Framework'' supports the concept of [https://missionpinball.com/docs/lighting/light-scripts/ Light scripts], which allow a maker to script what lamps are lit, for how long, and at a specific brightness to produce various effects.<br />
<br />
=== Light Groups ===<br />
<br />
Lights can be put into ''groups'' of similar lamps that allow for specific light effects. For example ''High Speed'' has the circular rev lamps, which lend themselves to a circular lamp effect, or the lamps in a row above them are well suited to a side-to-side effect.<br />
<br />
=== Backbox ===<br />
<br />
Most modern games have abandoned controlled lamps in the backbox to save on costs, but a garage maker has no such restrictions on creativity and can add various light effects to the backglass. Separating sections off to light separately is a common technique.<br />
<br />
[[Image:backbox-light-show.gif]]<br />
<br />
== Settings / Preferences ==<br />
<br />
=== Audits ===<br />
<br />
Auditing for a pinball machine involves keeping a tally of various activities, such as:<br />
<br />
* Total plays<br />
* Total balls played<br />
* Coins dropped<br />
* Replays awarded<br />
<br />
<br />
Creating audit tracking is easy, programming-wise. When a game is over, you would simply increment the "total games played" variable up by one. <br />
<br />
=== Settings ===<br />
<br />
These are values that modify the game rules. Most modern games have dozens of settings that dramatically alter game play. Some examples include:<br />
<br />
* Free Play<br />
* Balls Per Game<br />
* Replay enabled<br />
* Replay score percentage<br />
* Extra balls enabled<br />
* Ball Save enabled<br />
<br />
<br />
=== Diagnostics ===<br />
<br />
Another benefit of the switch from EM to Solid State electronics was the ability to include '''Diagnostics''' as a standard part of new games. The operator can run quick diagnostics on a machine without having to lift the playfield. Some example include:<br />
<br />
* '''Switch Test''': With the playfield glass removed, switches can be individually tested, with the number being shown on numerical scoring games, or the matrix coordinates being shown on DMD pins.<br />
* '''Sound Test''': With modern computer-based pinball machines, this test might be obsolete.<br />
* '''Coil Test''': Coils can be individually fired for checking faults, or all coils fired in order to test all coils.<br />
* '''Light Test''': Insert lights can be checked for burned out bulbs by flashing them individually.<br />
* '''Unique Mechanism Test''': This would apply to parts unique to the machine. An example would be the rotating box on ''Bally Theatre of Magic''.<br />
<br />
== Scoring ==<br />
<br />
For scoring, a separate scoring subroutine should be used and called as needed. This routine can do checks for earning game-wide rewards (points, replay) each time a player's score is incremented. Having it separate also allows for incorporating a ''double score'' mode for adding twice the amount of points without having to incorporate the mode check in each target hit routine.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
def add_score(points):<br />
game.curplayer.score = game.curplayer.score + points<br />
if curplayer.score => game.settings.replayscore:<br />
award_replay()<br />
</pre><br />
<br />
=== Bonus Lanes ===<br />
<br />
Bonus lanes are typically located at the top of the playfield, consisting of three or more lanes a ball can fall through at random. A ball falling through one of the lanes will light the lane. A bonus will be awarded, typically with a bonus multiplier (but can vary) if all the lanes are lit. <br />
<br />
Beginning with ''Williams Firepower'', hitting the flipper buttons would cycle the lit lanes left or right, allowing the player to move the unlit lane under the falling ball, achieving the bonus. Bonus lanes are frequently incorporated into the skill shot.<br />
<br />
Layout:<br />
<br />
* One switch per lane. <br />
* Each lane will have one light associated with it. Some games have two lights per lane, creating two sets of bonus lanes (Example: ''Williams Barracora''').<br />
<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
cur_bonus = 1 <br />
lane1 = off <br />
lane2 = off<br />
lane3 = off<br />
tmplane = off<br />
<br />
def switch1_hit<br />
lane1 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane1 = on<br />
<br />
def switch2_hit<br />
lane2 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane2 = on<br />
<br />
def switch3_hit<br />
lane3 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane3 = on<br />
<br />
// and the code for cycling the bonus lanes, tied to flipper button<br />
<br />
// code for checking all bonus lanes<br />
def check_all_lanes()<br />
with curplayer<br />
if (lane1 = on) + (lane2 = on) + (lane3 = on)<br />
increase_bonus()<br />
play_sound(yay_bonus!)<br />
display_msg("BONUS INCREASED")<br />
// shut off states & reset!<br />
lights.lane1 = off<br />
lights.lane2 = off<br />
lights.lane3 = off<br />
<br />
// the code for increasing the bonus multiplier <br />
// bonus held not implemented<br />
<br />
def increase_bonus()<br />
curplayer.cur_bonus = curplayer.cur_bonus + 1<br />
// give any special award if it is at a high #<br />
</pre><br />
<br />
== Game Modes ==<br />
<br />
These are modes that are specific to the game in question and relate to the theme or specific special devices included in the design. They can also fall outside regular gameplay - for example, ''Bally Safecracker'' has a special ''Assault the Vault'' mode triggered by using a unique token in the coin slot. Or ''Williams Black Knight'' and ''Time Fantasy'', which have a special post-game timed mode governed by time earned in regular gameplay, where you have unlimited balls to score extra points. <br />
<br />
=== General Modes ===<br />
<br />
These are modes that are general to most games, rather than rules specific to the machine's theme.<br />
<br />
==== Game Start ====<br />
<br />
==== Game End ====<br />
<br />
After the game ends, cleanup of the playfield device and some variables internal to the software should be done. Examples in no particular order include:<br />
<br />
* Release any locked balls from kickers<br />
* Release any locked balls from vertical upkickers<br />
* Disable flippers<br />
* Return any mechanical devices to Game Start state<br />
* Check for any high scores achieved by any players and record initials<br />
* Run Replay Match<br />
* Set number of current players to zero<br />
* Null/delete any player objects<br />
* Delete the game session object<br />
* Audits - increase # of games played, etc.<br />
<br />
==== Replay Match ====<br />
<br />
==== Ball Seek ====<br />
<br />
In the event a ball gets stuck and the player is unable to play, many machines will go into a '''Ball Seek''' mode. All mechanisms that interact with the ball will individually fire after a specified "idle" delay in an attempt to free the stuck ball. The ''Ball Seek'' mode will often run continuously until the missing ball is found, or only repeat a few times at which point the ball is marked as ''lost'' and game play continues, with the software compensating for the missing ball as best as possible.<br />
<br />
A timer is updated to check for any '''idle time''' of the ball - any switch hits (indicating ball movement) resets this timer. If no switch activity occurs for a specified period of time (as set by an operator setting), the '''Ball Seek''' subroutine would be run.<br />
<br />
Put the timer reset calls through all the switch detection events (except for shooter lane, tilt plumb, buttons) as those switch hits indicate a healthy running ball session.<br />
<br />
A ball in the shooter lane should disable the timer, with it starting after confirming a ball has been launched and is in play. For convenience sake, invoke the ball seek timer after a player has passed or failed the skill shot. So, just after shutting down the skill shot (if implemented), start the ball save timer.<br />
<br />
Shut down the ball save timer once the ball session is over. <br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// invoke the ball seeker routine<br />
def bs_timer_start()<br />
// ball saver invoked<br />
bs_timer_countdown = 60<br />
<br />
// reset the timer<br />
def bs_timer_reset()<br />
bs_timer_countdown = 60<br />
<br />
// shut down the timer entirely<br />
def bs_timer_shutdown()<br />
bs_timer_countdown = -1<br />
<br />
// this runs when the timer has expired<br />
def ball_saver()<br />
if ( bs_timer_countdown = 0 ) <br />
// fire the coils<br />
coils.popbumper1.fire()<br />
// fire drop target reset<br />
coils.dtbank1.fire()<br />
// and so forth<br />
// reset timer and hopefully we won't have to run it again<br />
bs_timer_reset()<br />
<br />
// example of the 1 of many target hits<br />
// that show the timer reset routine<br />
def leaftarget1_hit()<br />
score.addpoints(50)<br />
sound.play("boop")<br />
bs_timer_reset()<br />
</pre><br />
<br />
==== Ball Save ====<br />
<br />
'''Ball save''' is when a ball in play is drained out shortly into the ball session. This routine can be triggered via the outlanes or center drain.<br />
<br />
Typically ''Ball Save'' is either time-based or score-based. The allowed time for ball save to be active can be set via '''Preferences'''.<br />
<br />
==== Extra Ball ====<br />
<br />
==== Skill Shot ====<br />
<br />
'''Skill Shots''' are available when the player first plunges the ball. Plunging the ball at the right strength, or at the right time, or hitting a specific switch, will earn the player a reward - generally a bonus multiplier or a large points bonus.<br />
<br />
Used in conjunction with a physical plunger (as opposed to an autoplunger), plunging the ball at just the right strength to hit a specific switch will award the ''Skill Shot'' value.<br />
<br />
Some shots are ''Strength-based'', where a group of targets or switches can be hit by the ball from the plunger, and the indicated target or switch, when hit, will award the value. Of these types, variations include the '''Side''' style where the ball is aimed at targets in a vertical alignment (as in ''Williams No Good Gofers''), or '''Over''' where the ball is plunged over the switches, as shown in this example from ''Williams Pinbot'':<br />
<br />
[[Image:pinbot-skill.jpg|400px]]<br />
<br />
For games with autoplungers, there are ''Time-based'' examples where the player must time the activation of the plunger to correspond with the ball hitting a lit target - ''Williams Terminator 2'' is an example of this type. Many autoplunger games use a randomly-chosen ''Bonus Lane'', where the skill shot is achieved if the ball goes through the indicated lane at the end of a plunge. <br />
<br />
When coding, the logic is:<br />
<br />
* Initialize the skill shot mode at the begin of a ball session<br />
* End the skill shot after the player has passed or failed<br />
<br />
==== Tilt ====<br />
<br />
Although not thought of as a ''mode'', it fits the same model - it is triggered from one or multiple switch events, in this case, the switch being the tilt bob. When the tilt is triggered enough times (and after warnings issued), the game will end the current ball. <br />
<br />
A ''Tilt'' should trigger the following:<br />
<br />
* Disable Flippers<br />
* Shut off GI and any insert lights<br />
* Shut off music<br />
* Disable pop bumpers<br />
* Disable slingshots<br />
* Do not award end-of-ball bonus points<br />
<br />
Once the ball is returned the trough, regular play resumes.<br />
<br />
An additonal mode is the '''Slam Tilt''', triggered by a switch on the coin door. The main difference is that the whole game for all players will be immediately ended, as to punish the player for being rough with the machine.<br />
<br />
==== Status Report ====<br />
<br />
Generally activated by holding down both flippers.<br />
<br />
[[Status Report]]<br />
<br />
=== Device Modes ===<br />
<br />
These are general modes that trigger specific mechanical devices.<br />
<br />
==== Kickback ====<br />
<br />
See the [[Kickback]] subpage for hardware details.<br />
<br />
For the kickback, some checks will need to be done to ensure that the ball is out of the outlane area. One solution is to leave it active for a specified period of time to give an additional kickback to ensure the ball is out.<br />
<br />
Other triggers may include:<br />
<br />
* A sound or call-out indicating to the player that kickback is enabled<br />
* A sound or call-out when kickback is invoked<br />
<br />
<br />
The action to activate the kickback is to pulse the solenoid. What is critical is getting the timing correct where it does not fire too soon, or too late, where the ball will be missed. Some timing adjustments will need to be done to find the sweet spot where it will handle the most amount of ball velocity variations.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
kickback_enabled = (on/off) <br />
<br />
// scope: ball session<br />
<br />
def enable_kickback()<br />
ballsess.kickback_enabled = on<br />
lights.kb = flashy<br />
play.sound("kickback is on!")<br />
<br />
// switch hit event for the left outlane<br />
// determines if you drain or kick<br />
<br />
def leftoutlane_sw()<br />
if ballsess.kickback_enabled = on<br />
( kickback_fire() )<br />
else<br />
score.addpoints(50)<br />
sound.play("aww shucks")<br />
<br />
// fire the kickback<br />
<br />
def fire_kickback()<br />
sound.play("misspiggy hiyah!")<br />
coils.kickback.pulse()<br />
<br />
// insert any additional "keep hot" code here<br />
// okay, shut off the kickback<br />
disable_kickback()<br />
<br />
// shut off kb<br />
// also shut this off if you tilt<br />
<br />
def disable_kickback()<br />
ballsess.kickback_enabled = off<br />
lights.kb = off<br />
</pre><br />
<br />
==== Ball Trough ====<br />
<br />
See the [[Ball Trough]] subpage for hardware details.<br />
<br />
Pseudocode example:<br />
<pre><br />
<br />
// callback function<br />
// returns true if the trough is full<br />
function is_trough_full()<br />
if (trsw1 = true) + (trsw2=true) + (trsw3=true)<br />
return true<br />
else<br />
return false<br />
</pre><br />
<br />
==== Drop Targets ====<br />
<br />
See the [[Drop Targets]] subpage for hardware details.<br />
<br />
For a drop target bank, a check is needed after every drop target hit. As an example of using ''state'' to manage the game, a player could be awarded points for hitting the drop targets in order (Example: ''Bally Centaur''), or award points for completing multiple sets of drop target banks. <br />
<br />
Pseudocode:<br />
<br />
<pre><br />
// variable scope(current ball session)<br />
dbank1 = off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
def dbank1_hit()<br />
score.addpoints(50)<br />
dbank1 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank2 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank3 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
// check to see if all the drop targets have been hit<br />
<br />
def check_dropbank1()<br />
if (dbank1= on) & (dbank2=on) & (dbank3=on)<br />
// reward for completing drop target bank<br />
play_sound(chaching)<br />
score.addpoints(200)<br />
<br />
// reset the variables<br />
dbank1= off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
// reset 'em<br />
coils.dbank1.pulse()<br />
<br />
// separate routine for resetting drop target bank ,<br />
// add this to the "ball begin" routine<br />
<br />
def reset_drop_bank()<br />
coils.dbank1.pulse()<br />
</pre><br />
<br />
==== Slingshots ====<br />
<br />
See the [[Slingshots]] subpage for hardware details.<br />
<br />
Most off-the-shelf controllers allow a user to create '''Triggers''', where if a specific switch is hit, it causes a specific coil to fire. For slingshots, this is all that is needed for them to operate as expected, plus recording any scoring involved.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Kicker Hole ====<br />
<br />
See the [[Kicker Hole]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Divertors ====<br />
<br />
See the [[Divertors]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Vertical Up-Kickers ====<br />
<br />
See the [[VUK]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
== Sound ==<br />
<br />
Sound is a critical component of any pinball machine. EM games used bells and chimes to inform the player while modern games use digitized voice callouts and stereo music.<br />
<br />
Some things to consider when deciding on how to incorporate sound in a game include:<br />
<br />
* Avoid playing sounds continuously over the top of one another. For example, having an explosion sound when a pop bumper is triggered - if the ball is getting a lot of pop bumper action and it triggers three pops in very fast succession, restarting the sound event on each trigger would sound like white noise. Thus, choose not to play the same sound effect unless N time has passed (say 3 seconds), or never play the same sound affect at the same time.<br />
* Too many sound effects playing over each over mutes the effect it should have on the player and can be confusing.<br />
* Timing of sound events should be kept short, as the longer the sound, the more likely it will overlap with another switch event trigger, leading to too many overlapping sound events or the white noise problem mentioned earlier.<br />
* Normalize the volume of all the sound effects to the same level to maintain a common volume level on the machine itself. <br />
<br />
[[sound assignments]]<br />
<br />
[[Music loops]]<br />
<br />
[[Basic sounds]]<br />
<br />
[[voice callouts]]</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Programming&diff=52223Programming2017-09-28T23:08:39Z<p>Jab: /* Pinball Frameworks */</p>
<hr />
<div>After the initial [[Construction#Whitewood|whitewood]] has been built, it is time to bring it to life by programming the control system and adding game rules.<br />
<br />
== Languages ==<br />
<br />
The programming language being used is going to be dictated primarily by the hardware control system chosen. Off the shelf systems such as '''[[Construction#Off-the-Shelf_Boards|P-ROC or Fast]]''' have a close relationship to '''[http://github.com/preble/pyprocgame PyProcGame]''', which is dedicated exclusively to the P-ROC, or the '''[https://missionpinball.com/framework/ Mission Pinball Framework]''' which supports both P-ROC and FAST and is a more higher level programming framework.<br />
<br />
For more lower-level control, there is the [http://github.com/preble/libpinproc libpinproc] library for P-ROC boards, which allow binding into other languages and building of custom frameworks using things like [http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer SDL] or [http://www.sfml-dev.org/ SFML] which provides access to ''OpenGL'' and other graphics APIs.<br />
<br />
If using custom hardware, it is up to the designer to decide on how to interface with the controller.<br />
<br />
=== Pinball Frameworks ===<br />
<br />
To make programming pinball machines easier, a number of frameworks are available to use that provide a baseline of functionality.<br />
<br />
* [https://missionpinball.com/framework/ Mission Pinball]: Currently supports P-ROC, FAST and [[OPP|Open Pinball Project]] controllers, written in Python. Uses YAML config files to define functions<br />
* [http://pyprocgame.pindev.org/ PyProcGame]: Developed specifically for the P-ROC controllers, written in Python<br />
* [http://skeletongame.com/ SkeletonGame]: Based on PyProcGame<br />
* [https://github.com/preble/libpinproc libPinPROC]: Lower level C library for P-ROC<br />
* [http://mypinballs.co.uk/electronics/store.jsp myPinballs]: Framework written in C for developing custom games in conjunction with the myPinballs Custom Controller Board Set for early 80s Bally/Stern games. <br />
<br />
<br />
The following is a breakdown of the hardware and functionality support for the top three frameworks.<br />
<br />
{| class="wikitable" style="text-align: center;"<br />
!<br />
! Mission Pinball Framework<br />
! PyProcGame<br />
! SkeletonGame<br />
|-<br />
!Hardware<br />
| <br />
|<br />
|<br />
|-<br />
| P-ROC<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| FAST <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| OPP <br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Displays<br />
|<br />
|<br />
|<br />
|-<br />
| LCD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| DMD<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Alphanumeric<br />
| style="color: white; background-color: green;"| ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
!Lighting<br />
|<br />
|<br />
|<br />
|-<br />
| Incandescent<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Serial LED<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
! Devices<br />
|<br />
|<br />
|<br />
|-<br />
| Coils<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Motors / Servos<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
! Standard Functions<br />
|<br />
|<br />
|<br />
|-<br />
| Config File Setup<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: red;"| ✗<br />
| style="color: white; background-color: red;"| ✗<br />
|-<br />
| Custom Code<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
| Service Menu<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
| style="color: white; background-color: green;" | ✓<br />
|-<br />
|}<br />
<br />
== Rules ==<br />
<br />
As pinball hardware advanced in complexity from simple relays to transistors, so did game rules. ''Electromechanical'' (EM) pinball machines often struggled to register multiple switch hits at the same time, while early ''Solid State'' (SS) games allowed fast response times and multiple concurrent switch hits to be registered. Faster CPUs with more memory allow for the deeper rule sets of modern pinball.<br />
<br />
Rules can be as simple as ''Complete the rollovers for bonus multiplier'' to stacking several mode-scoring multiballs together.<br />
<br />
=== Maintaining State ===<br />
<br />
Deeper rule tracking requires maintaining '''State''', which is a map (in memory) of the current switch conditions, such as:<br />
<br />
* What was the state of all the switches N seconds ago? <br />
* Has anything changed in N seconds?<br />
* How many times has a switch been hit total?<br />
<br />
<br />
These are all ''States'' and the control program keeping track of these allows for modes and other advanced rules.<br />
<br />
Think of an orbit shot: two switches, one of the left side orbit entry, one of the right side orbit entry. An orbit is complete if both switches are hit in order. It takes time for the ball to travel from one side to the other - there may be 5 seconds or more if the ball is slow, struggles to get to the apex, or dribbles down the other side. A failed orbit may count two hits to only one of the switches. It may count only one hit if the ball just makes it and rolls back down. The orbit shot is a good example of needing to know the previous switch state, the question then becomes, how many previous states to track? <br />
<br />
''Example'': If an orbit is a multiball jackpot shot, how to handle when a second ball enters the left orbit before the first ball has triggered the right orbit switch? This means an orbit that can be fed from either direction is probably not a good way to score a jackpot. This is why a ramp shot is very easy to track a jackpot on - ramps have an apex and once your past the apex, any exit switch hit from the ramp is easily countable. <br />
<br />
Another example of an advanced rule would be tracking the order of something - having five drop targets that give an extra bonus if hit in order of one to five, or five to one. This is a variable outside of standard switch state and it has to be managed outside of just target hits, as well as be reset on a ball drain, reset if a mode changes, or reset if the drop targets are reset.<br />
<br />
Code complexity is increased by remembering the state of that variable and which targets have been hit or not between changing players.<br />
<br />
The deeper rules become, the more variables, flags and timers that are needed to be tracked and managed, and the more difficult the code becomes to debug and maintain.<br />
<br />
Some other examples of maintaining state:<br />
<br />
* If a target enables a kickback, will extra kick backs be added if it is already lit?<br />
* Knowing how many balls are in the ball trough before lighting the add-a-ball insert.<br />
<br />
=== Game Logic Flow ===<br />
<br />
For an example of a typical layout of general game rules and how the logic should flow, see the [[Rule Flow]] subpage.<br />
<br />
=== Priority ===<br />
<br />
Modes, display events and sounds all need to be '''prioritized''' relative to each other - for example, background displays or sounds are a lower priority than a switch hit or score display. <br />
<br />
For example, if a high priority sound is playing, and the ball hits a switch that triggers a low priority sound effect, the control program can skip playing the lower priority sound, or play it at a lower volume. Or, if there is a display event for a pop bumper hit, it will be higher priority than the score display.<br />
<br />
== Light Shows ==<br />
<br />
With modern CPU-controlled lamps, it is possible to use general illumination, flashers and playfield insert lamps to produce '''Light Shows''' during Attract mode to bring attention to the game from a passer-by, or while the game is active to convey information to the player.<br />
<br />
For example, lighting lamps from the bottom of the playfield up to the top, then turn them off from the bottom up would be a distinct lamp show used during Attract mode. Below shows part of the attract mode for ''High Speed'' which uses multiple techniques.<br />
<br />
[[Image:high-speed-attract-mode.gif]]<br />
<br />
''Mission Pinball Framework'' supports the concept of [https://missionpinball.com/docs/lighting/light-scripts/ Light scripts], which allow a maker to script what lamps are lit, for how long, and at a specific brightness to produce various effects.<br />
<br />
=== Light Groups ===<br />
<br />
Lights can be put into ''groups'' of similar lamps that allow for specific light effects. For example ''High Speed'' has the circular rev lamps, which lend themselves to a circular lamp effect, or the lamps in a row above them are well suited to a side-to-side effect.<br />
<br />
=== Backbox ===<br />
<br />
Most modern games have abandoned controlled lamps in the backbox to save on costs, but a garage maker has no such restrictions on creativity and can add various light effects to the backglass. Separating sections off to light separately is a common technique.<br />
<br />
[[Image:backbox-light-show.gif]]<br />
<br />
== Settings / Preferences ==<br />
<br />
=== Audits ===<br />
<br />
Auditing for a pinball machine involves keeping a tally of various activities, such as:<br />
<br />
* Total plays<br />
* Total balls played<br />
* Coins dropped<br />
* Replays awarded<br />
<br />
<br />
Creating audit tracking is easy, programming-wise. When a game is over, you would simply increment the "total games played" variable up by one. <br />
<br />
=== Settings ===<br />
<br />
These are values that modify the game rules. Most modern games have dozens of settings that dramatically alter game play. Some examples include:<br />
<br />
* Free Play<br />
* Balls Per Game<br />
* Replay enabled<br />
* Replay score percentage<br />
* Extra balls enabled<br />
* Ball Save enabled<br />
<br />
<br />
=== Diagnostics ===<br />
<br />
Another benefit of the switch from EM to Solid State electronics was the ability to include '''Diagnostics''' as a standard part of new games. The operator can run quick diagnostics on a machine without having to lift the playfield. Some example include:<br />
<br />
* '''Switch Test''': With the playfield glass removed, switches can be individually tested, with the number being shown on numerical scoring games, or the matrix coordinates being shown on DMD pins.<br />
* '''Sound Test''': With modern computer-based pinball machines, this test might be obsolete.<br />
* '''Coil Test''': Coils can be individually fired for checking faults, or all coils fired in order to test all coils.<br />
* '''Light Test''': Insert lights can be checked for burned out bulbs by flashing them individually.<br />
* '''Unique Mechanism Test''': This would apply to parts unique to the machine. An example would be the rotating box on ''Bally Theatre of Magic''.<br />
<br />
== Scoring ==<br />
<br />
For scoring, a separate scoring subroutine should be used and called as needed. This routine can do checks for earning game-wide rewards (points, replay) each time a player's score is incremented. Having it separate also allows for incorporating a ''double score'' mode for adding twice the amount of points without having to incorporate the mode check in each target hit routine.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
def add_score(points):<br />
game.curplayer.score = game.curplayer.score + points<br />
if curplayer.score => game.settings.replayscore:<br />
award_replay()<br />
</pre><br />
<br />
=== Bonus Lanes ===<br />
<br />
Bonus lanes are typically located at the top of the playfield, consisting of three or more lanes a ball can fall through at random. A ball falling through one of the lanes will light the lane. A bonus will be awarded, typically with a bonus multiplier (but can vary) if all the lanes are lit. <br />
<br />
Beginning with ''Williams Firepower'', hitting the flipper buttons would cycle the lit lanes left or right, allowing the player to move the unlit lane under the falling ball, achieving the bonus. Bonus lanes are frequently incorporated into the skill shot.<br />
<br />
Layout:<br />
<br />
* One switch per lane. <br />
* Each lane will have one light associated with it. Some games have two lights per lane, creating two sets of bonus lanes (Example: ''Williams Barracora''').<br />
<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
cur_bonus = 1 <br />
lane1 = off <br />
lane2 = off<br />
lane3 = off<br />
tmplane = off<br />
<br />
def switch1_hit<br />
lane1 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane1 = on<br />
<br />
def switch2_hit<br />
lane2 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane2 = on<br />
<br />
def switch3_hit<br />
lane3 = on<br />
play_sound(boink)<br />
curplayer.add_score(10)<br />
lights.lane3 = on<br />
<br />
// and the code for cycling the bonus lanes, tied to flipper button<br />
<br />
// code for checking all bonus lanes<br />
def check_all_lanes()<br />
with curplayer<br />
if (lane1 = on) + (lane2 = on) + (lane3 = on)<br />
increase_bonus()<br />
play_sound(yay_bonus!)<br />
display_msg("BONUS INCREASED")<br />
// shut off states & reset!<br />
lights.lane1 = off<br />
lights.lane2 = off<br />
lights.lane3 = off<br />
<br />
// the code for increasing the bonus multiplier <br />
// bonus held not implemented<br />
<br />
def increase_bonus()<br />
curplayer.cur_bonus = curplayer.cur_bonus + 1<br />
// give any special award if it is at a high #<br />
</pre><br />
<br />
== Game Modes ==<br />
<br />
These are modes that are specific to the game in question and relate to the theme or specific special devices included in the design. They can also fall outside regular gameplay - for example, ''Bally Safecracker'' has a special ''Assault the Vault'' mode triggered by using a unique token in the coin slot. Or ''Williams Black Knight'' and ''Time Fantasy'', which have a special post-game timed mode governed by time earned in regular gameplay, where you have unlimited balls to score extra points. <br />
<br />
=== General Modes ===<br />
<br />
These are modes that are general to most games, rather than rules specific to the machine's theme.<br />
<br />
==== Game Start ====<br />
<br />
==== Game End ====<br />
<br />
After the game ends, cleanup of the playfield device and some variables internal to the software should be done. Examples in no particular order include:<br />
<br />
* Release any locked balls from kickers<br />
* Release any locked balls from vertical upkickers<br />
* Disable flippers<br />
* Return any mechanical devices to Game Start state<br />
* Check for any high scores achieved by any players and record initials<br />
* Run Replay Match<br />
* Set number of current players to zero<br />
* Null/delete any player objects<br />
* Delete the game session object<br />
* Audits - increase # of games played, etc.<br />
<br />
==== Replay Match ====<br />
<br />
==== Ball Seek ====<br />
<br />
In the event a ball gets stuck and the player is unable to play, many machines will go into a '''Ball Seek''' mode. All mechanisms that interact with the ball will individually fire after a specified "idle" delay in an attempt to free the stuck ball. The ''Ball Seek'' mode will often run continuously until the missing ball is found, or only repeat a few times at which point the ball is marked as ''lost'' and game play continues, with the software compensating for the missing ball as best as possible.<br />
<br />
A timer is updated to check for any '''idle time''' of the ball - any switch hits (indicating ball movement) resets this timer. If no switch activity occurs for a specified period of time (as set by an operator setting), the '''Ball Seek''' subroutine would be run.<br />
<br />
Put the timer reset calls through all the switch detection events (except for shooter lane, tilt plumb, buttons) as those switch hits indicate a healthy running ball session.<br />
<br />
A ball in the shooter lane should disable the timer, with it starting after confirming a ball has been launched and is in play. For convenience sake, invoke the ball seek timer after a player has passed or failed the skill shot. So, just after shutting down the skill shot (if implemented), start the ball save timer.<br />
<br />
Shut down the ball save timer once the ball session is over. <br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// invoke the ball seeker routine<br />
def bs_timer_start()<br />
// ball saver invoked<br />
bs_timer_countdown = 60<br />
<br />
// reset the timer<br />
def bs_timer_reset()<br />
bs_timer_countdown = 60<br />
<br />
// shut down the timer entirely<br />
def bs_timer_shutdown()<br />
bs_timer_countdown = -1<br />
<br />
// this runs when the timer has expired<br />
def ball_saver()<br />
if ( bs_timer_countdown = 0 ) <br />
// fire the coils<br />
coils.popbumper1.fire()<br />
// fire drop target reset<br />
coils.dtbank1.fire()<br />
// and so forth<br />
// reset timer and hopefully we won't have to run it again<br />
bs_timer_reset()<br />
<br />
// example of the 1 of many target hits<br />
// that show the timer reset routine<br />
def leaftarget1_hit()<br />
score.addpoints(50)<br />
sound.play("boop")<br />
bs_timer_reset()<br />
</pre><br />
<br />
==== Ball Save ====<br />
<br />
'''Ball save''' is when a ball in play is drained out shortly into the ball session. This routine can be triggered via the outlanes or center drain.<br />
<br />
Typically ''Ball Save'' is either time-based or score-based. The allowed time for ball save to be active can be set via '''Preferences'''.<br />
<br />
==== Extra Ball ====<br />
<br />
==== Skill Shot ====<br />
<br />
'''Skill Shots''' are available when the player first plunges the ball. Plunging the ball at the right strength, or at the right time, or hitting a specific switch, will earn the player a reward - generally a bonus multiplier or a large points bonus.<br />
<br />
Used in conjunction with a physical plunger (as opposed to an autoplunger), plunging the ball at just the right strength to hit a specific switch will award the ''Skill Shot'' value.<br />
<br />
Some shots are ''Strength-based'', where a group of targets or switches can be hit by the ball from the plunger, and the indicated target or switch, when hit, will award the value. Of these types, variations include the '''Side''' style where the ball is aimed at targets in a vertical alignment (as in ''Williams No Good Gofers''), or '''Over''' where the ball is plunged over the switches, as shown in this example from ''Williams Pinbot'':<br />
<br />
[[Image:pinbot-skill.jpg|400px]]<br />
<br />
For games with autoplungers, there are ''Time-based'' examples where the player must time the activation of the plunger to correspond with the ball hitting a lit target - ''Williams Terminator 2'' is an example of this type. Many autoplunger games use a randomly-chosen ''Bonus Lane'', where the skill shot is achieved if the ball goes through the indicated lane at the end of a plunge. <br />
<br />
When coding, the logic is:<br />
<br />
* Initialize the skill shot mode at the begin of a ball session<br />
* End the skill shot after the player has passed or failed<br />
<br />
==== Tilt ====<br />
<br />
Although not thought of as a ''mode'', it fits the same model - it is triggered from one or multiple switch events, in this case, the switch being the tilt bob. When the tilt is triggered enough times (and after warnings issued), the game will end the current ball. <br />
<br />
A ''Tilt'' should trigger the following:<br />
<br />
* Disable Flippers<br />
* Shut off GI and any insert lights<br />
* Shut off music<br />
* Disable pop bumpers<br />
* Disable slingshots<br />
* Do not award end-of-ball bonus points<br />
<br />
Once the ball is returned the trough, regular play resumes.<br />
<br />
An additonal mode is the '''Slam Tilt''', triggered by a switch on the coin door. The main difference is that the whole game for all players will be immediately ended, as to punish the player for being rough with the machine.<br />
<br />
==== Status Report ====<br />
<br />
Generally activated by holding down both flippers.<br />
<br />
[[Status Report]]<br />
<br />
=== Device Modes ===<br />
<br />
These are general modes that trigger specific mechanical devices.<br />
<br />
==== Kickback ====<br />
<br />
See the [[Kickback]] subpage for hardware details.<br />
<br />
For the kickback, some checks will need to be done to ensure that the ball is out of the outlane area. One solution is to leave it active for a specified period of time to give an additional kickback to ensure the ball is out.<br />
<br />
Other triggers may include:<br />
<br />
* A sound or call-out indicating to the player that kickback is enabled<br />
* A sound or call-out when kickback is invoked<br />
<br />
<br />
The action to activate the kickback is to pulse the solenoid. What is critical is getting the timing correct where it does not fire too soon, or too late, where the ball will be missed. Some timing adjustments will need to be done to find the sweet spot where it will handle the most amount of ball velocity variations.<br />
<br />
Pseudocode example:<br />
<br />
<pre><br />
// variables<br />
kickback_enabled = (on/off) <br />
<br />
// scope: ball session<br />
<br />
def enable_kickback()<br />
ballsess.kickback_enabled = on<br />
lights.kb = flashy<br />
play.sound("kickback is on!")<br />
<br />
// switch hit event for the left outlane<br />
// determines if you drain or kick<br />
<br />
def leftoutlane_sw()<br />
if ballsess.kickback_enabled = on<br />
( kickback_fire() )<br />
else<br />
score.addpoints(50)<br />
sound.play("aww shucks")<br />
<br />
// fire the kickback<br />
<br />
def fire_kickback()<br />
sound.play("misspiggy hiyah!")<br />
coils.kickback.pulse()<br />
<br />
// insert any additional "keep hot" code here<br />
// okay, shut off the kickback<br />
disable_kickback()<br />
<br />
// shut off kb<br />
// also shut this off if you tilt<br />
<br />
def disable_kickback()<br />
ballsess.kickback_enabled = off<br />
lights.kb = off<br />
</pre><br />
<br />
==== Ball Trough ====<br />
<br />
See the [[Ball Trough]] subpage for hardware details.<br />
<br />
Pseudocode example:<br />
<pre><br />
<br />
// callback function<br />
// returns true if the trough is full<br />
function is_trough_full()<br />
if (trsw1 = true) + (trsw2=true) + (trsw3=true)<br />
return true<br />
else<br />
return false<br />
</pre><br />
<br />
==== Drop Targets ====<br />
<br />
See the [[Drop Targets]] subpage for hardware details.<br />
<br />
For a drop target bank, a check is needed after every drop target hit. As an example of using ''state'' to manage the game, a player could be awarded points for hitting the drop targets in order (Example: ''Bally Centaur''), or award points for completing multiple sets of drop target banks. <br />
<br />
Pseudocode:<br />
<br />
<pre><br />
// variable scope(current ball session)<br />
dbank1 = off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
def dbank1_hit()<br />
score.addpoints(50)<br />
dbank1 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank2 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
def dbank2_hit()<br />
score.addpoints(50)<br />
dbank3 = on<br />
play_sound(boink)<br />
check_dropbank1()<br />
<br />
// check to see if all the drop targets have been hit<br />
<br />
def check_dropbank1()<br />
if (dbank1= on) & (dbank2=on) & (dbank3=on)<br />
// reward for completing drop target bank<br />
play_sound(chaching)<br />
score.addpoints(200)<br />
<br />
// reset the variables<br />
dbank1= off<br />
dbank2 = off<br />
dbank3 = off<br />
<br />
// reset 'em<br />
coils.dbank1.pulse()<br />
<br />
// separate routine for resetting drop target bank ,<br />
// add this to the "ball begin" routine<br />
<br />
def reset_drop_bank()<br />
coils.dbank1.pulse()<br />
</pre><br />
<br />
==== Slingshots ====<br />
<br />
See the [[Slingshots]] subpage for hardware details.<br />
<br />
Most off-the-shelf controllers allow a user to create '''Triggers''', where if a specific switch is hit, it causes a specific coil to fire. For slingshots, this is all that is needed for them to operate as expected, plus recording any scoring involved.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Kicker Hole ====<br />
<br />
See the [[Kicker Hole]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Divertors ====<br />
<br />
See the [[Divertors]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
==== Vertical Up-Kickers ====<br />
<br />
See the [[VUK]] subpage for hardware details.<br />
<br />
Pseudocode:<br />
<pre><br />
TBD<br />
</pre><br />
<br />
== Sound ==<br />
<br />
Sound is a critical component of any pinball machine. EM games used bells and chimes to inform the player while modern games use digitized voice callouts and stereo music.<br />
<br />
Some things to consider when deciding on how to incorporate sound in a game include:<br />
<br />
* Avoid playing sounds continuously over the top of one another. For example, having an explosion sound when a pop bumper is triggered - if the ball is getting a lot of pop bumper action and it triggers three pops in very fast succession, restarting the sound event on each trigger would sound like white noise. Thus, choose not to play the same sound effect unless N time has passed (say 3 seconds), or never play the same sound affect at the same time.<br />
* Too many sound effects playing over each over mutes the effect it should have on the player and can be confusing.<br />
* Timing of sound events should be kept short, as the longer the sound, the more likely it will overlap with another switch event trigger, leading to too many overlapping sound events or the white noise problem mentioned earlier.<br />
* Normalize the volume of all the sound effects to the same level to maintain a common volume level on the machine itself. <br />
<br />
[[sound assignments]]<br />
<br />
[[Music loops]]<br />
<br />
[[Basic sounds]]<br />
<br />
[[voice callouts]]</div>Jabhttps://pinballmakers.com/wiki/index.php?title=Controlling_Flippers&diff=1767Controlling Flippers2016-10-23T08:39:44Z<p>Jab: /* Software */ Add links to MPF documentation</p>
<hr />
<div>== Hardware == <br />
<br />
The usual way to control flipper coils is to connect power (typically a relatively high DC voltage like 70V) to one side of the coil and to connect the other side to a low-side transistor circuit, such as an n-channel MOSFET. When the transistor is activated, the source voltage has a path to ground through the coil and through the transistor, thereby activating the coil.<br />
<br />
Another way to hook up the flipper coils is to connect them to power through flipper buttons and use end-of-stroke switches to to govern how current flows through dual-wound coils. This is how 70V flipper circuits were implemented before the early 90's. If this is how you want to proceed, you don't need a P-ROC or a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] for your flipper circuits. You can refer to an early WPC (pre-fliptronics) machine manual for wiring diagrams showing this implementation.<br />
<br />
The rest of this page describes how flipper circuits have been implemented since the early 90's and how you could do the same with a P-ROC and [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16], using software controlled (or P-ROC controlled) transistors to activate the flippers when button presses are detected on the appropriate P-ROC switch inputs. Implemented flippers this way affords the designer a lot more control. Because the transistors are controlled programmatically, it is very easy to increase or decrease the flip strength by simply varying the pulse times. A creative designer could even implement modes in their game that intentionally make the flippers weaker or stronger. Other reasons to control flippers programmatically are to have the flexibility to deactivate them at times, enable only one at a time, reverse the button/flipper relationship, only allow them to be held on for specific lengths of time, etc, etc. One other important advantage is that the flipper buttons can be used while the flippers are deactivated (for video modes, entering high score initials, etc).<br />
<br />
Flipper coils, like most individual features on a pinball machine, can be controlled with a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] board. It's best to connect the power side of the coil to the fused power output connector on the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]. This will cause only the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]'s fuse to blow if there's ever a serious problem with the coil circuit, rather than taking out various other things on the machine. The other side of the coil is then connected to one of the eight transistor circuits the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] provides in each bank.<br />
<br />
<br />
=== Dual-wound Flipper Coils (WPC-style) ===<br />
<br />
Dual-wound coils are essentially two coils in one, for each flipper. One winding is called 'power', and the other is called 'hold'. That's why the coils have 3 terminals. One terminal is a common terminal that brings in power from the driver board. The other two terminals get connected to 2 of the 8 transistor circuits so they can be controlled by the P-ROC. Controlling two dual-wound flipper assemblies will therefore use 4 of the transistor circuits on one bank of a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]. <br />
<br />
The power winding is used to pulse the coil, which is when the flipper flips. That winding should measure about 4 ohms on a resistance meter.<br />
<br />
The hold winding is used to hold the coil up after flipping. It can keep the coil active indefinitely, and it only draws about 0.5A because it's about 127 Ohms.<br />
<br />
OK... now on to the actual wiring. Refer picture below. The center terminal is the power winding. It should be wired back to one of the transistor circuits. You can use a resistance meter to figure out the other two terminals. Put one probe on the center terminal and the other on one of the others. If it reads about 4 ohms, you've found the common terminal that you'll connect to the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]'s power output (J3 or J4 depending on the back you're using). If it reads 131 ohms or so, you've found the 'hold' winding terminal, which also goes to a transistor circuit.<br />
<br />
<br />
<center>[[Image: WPC_coil.jpg]]</center><br />
<br />
<br />
Note - Flipper assemblies with dual wound coils typically include and end-of-stroke (EOS) switch. Before flippers were controlled programmatically, the EOS switch was used to switch power from the power coil to the hold coil. With programmatically controlled flippers, the EOS switch is no longer necessary. Software controls each coil individually and can therefore shut off the power coil whenever necessary. Therefore, the EOS switch doesn't even need to be wired to the P-ROC.<br />
<br />
=== Single-wound Flipper Coils (Stern-style) ===<br />
<br />
Single-wound flipper coils are much simpler than dual-wound coils, at least electrically, because they have only two terminals. One terminal is connected directly to the power source (power output from a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]). The other terminal gets connected to one of the transistor circuits so it can be controlled by the P-ROC. Controlling two single-wound flipper assemblies will therefore use only 2 of the transistor circuits on one bank of a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]. <br />
<br />
The single-wound coil is a high power coil. It draws a lot of current so that the flipper will have enough power to flip the ball. If the coil remains active for longer than a short pulse, though, it will blow the fuse on the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]. Otherwise it would destroy either the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16]'s transistor or the coil itself, maybe even both. To keep this from happening, games with single-wound coils use software (or a P-ROC) to activate the coil for a long flip pulse (30 milliseconds or so) and immediately follow that with short pulses (maybe 2 milliseconds every 20 milliseconds) to keep the flipper active until the flipper button is released.<br />
<br />
'''Important''': If your coil has a diode on it, you must wire power to the bar end of the diode and the desired transistor circuit to the non-bar end.<br />
<br />
== Software ==<br />
<br />
===Mission Pinball Framework ===<br />
To configure your flippers in the Mission Pinball Framework (MPF) you should follow [http://docs.missionpinball.org/en/stable/tutorial/3_get_flipping.html tutorial step 3]. For single wound modern flippers have a look at the [http://docs.missionpinball.org/en/stable/devices/flipper_config_single_wound.html single wound flipper documentation]. If you are using a WPC machine more information about fliptronics can be found in the [http://docs.missionpinball.org/en/stable/machines/wpc.html WPC Howto]. Advanced topics, fine tuning and special configurations are covered in the [http://docs.missionpinball.org/en/stable/devices/flipper.html flipper device documentation]. <br />
<br />
=== P-ROC ===<br />
<br />
==== Switch Rules ====<br />
<br />
When using a P-ROC with the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] to control flippers, the best thing to do is configure P-ROC switch rules. Doing this will configure the P-ROC to automatically drive the flippers appropriately when the flipper buttons are pressed. This is better than trying to activate the flippers programmatically in response to button presses because it eliminates the latency of the switch event getting to software and the coil activation request getting back to the P-ROC.<br />
<br />
Whether you're using libpinproc (C) or pyprocgame (Python), your machine's YAML file will need to contain flipper definitions so the software will know which switches to link to link to which coils. Here's an example YAML with only the relevant flipper items:<br />
<br />
PRGame:<br />
machineType: custom<br />
<br />
PRFlippers:<br />
- flipperLwR<br />
- flipperLwL<br />
<br />
PRSwitches:<br />
flipperLwR:<br />
number: P-ROC input number for the Lower Right flipper button<br />
flipperLwL:<br />
number: P-ROC input number for the Lower Left flipper button<br />
<br />
PRCoils:<br />
flipperLwRMain:<br />
number: PD-16 circuit number for the LwR main flipper<br />
flipperLwRHold:<br />
number: PD-16 circuit number for the LwR hold flipper - if using dual-wound coils. If not, delete this Hold entry<br />
flipperLwLMain:<br />
number: PD-16 circuit number for the LwL main flipper<br />
flipperLwLHold:<br />
number: PD-16 circuit number for the LwL hold flipper - if using dual-wound coils. If not, delete this Hold entry<br />
<br />
===== Configuring the P-ROC =====<br />
<br />
You'll need to configure the P-ROC to work with your chain of driver boards. If you're using libpinproc (C) or pyprocgame (Python), instructions for doing this are [[Configuring Driver Boards|found here]].<br />
<br />
===== libpinproc =====<br />
<br />
For setting up the switch rules, see ConfigureWPCFlipperSwitchRule() (for dual-wound coils) and ConfigureSternFlipperSwitchRule() (for single-wound coils) in the [https://github.com/preble/libpinproc/blob/master/examples/pinproctest/switches.cpp libpinproc pinproctest example code].<br />
<br />
===== pyprocgame =====<br />
<br />
For setting up the switch rules, refer to the code that already does this for WPC and Stern flippers in pyprocgame. It's done in the enable_flippers() method of the GameController class in [https://github.com/preble/pyprocgame/blob/master/procgame/game/game.py game.py]. Use the WPC method for dual-wound coils and the Stern method for single-wound coils.<br />
<br />
==== Software Control ====<br />
<br />
If you're dead-set on activating the flippers in your software instead of using P-ROC switch rules, you can do this easily enough. <br />
<br />
===== Software control using P-ROC functions =====<br />
If you've configured the P-ROC to control your chain of driver boards, you can simply issue the appropriate pulse or patter commands when the appropriate switch events occur.<br />
<br />
====== Dual-wound (WPC-style) Flippers ======<br />
For software control of dual-wound WPC-style flippers, it's recommended to issue both a pulse command (30ms or so) to the power coil and an indefinite pulse (0ms) to the hold coil when the flipper button is pushed. Then deactivate both coils when the flipper button is released.<br />
<br />
====== Single-wound (Stern-style) Flippers ======<br />
For single-wound Stern-style flippers, it's recommend to issue a patter command when the flipper button is pushed. Use an on/off cycle time of about 2ms/18ms, respectively, and give it an original_on_time of 30 ms or so for the initial flip. Then deactivate the coil when the flipper button is released.<br />
<br />
===== Software control without using P-ROC functions =====<br />
<br />
If you'd rather use software to write to the driver board directly, which is possible though eliminates the possibility of using the pulse, schedule, patter, etc functions the P-ROC provides, you can issue direct register writes to the P-ROC that, in turn, get sent to the appropriate driver board. Refer to the [http://www.pinballcontrollers.com/index.php/products/p-roc/documentation P-ROC FPGA documentation] for more details.<br />
<br />
=== Other controller (non - P-ROC) ===<br />
<br />
If you're using a microcontroller such as an Arduino or Parallax Propeller to control your flippers through a [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16], you'll need to do everything in software. Refer to the [http://www.pinballcontrollers.com/index.php/products/driver-boards/power-driver-16 PD-16] documentation for a description of the PDB Protocol used for sending commands to the driver board.</div>Jab