This tech tip covers the Cosmic Cart Racing BallPaths and the module driver API.
There are 7 rings on the module: 3 rings on the left ramp and 4 rings on the right ramp.
lRampFrontRing
lRampEnterRing
lRampExitRing
rRampRightRing
rRampCenterRing
rRampLeftRing
rRampExitRing
The rings are decorative, except that lRampEnterRing, lRampExitRing, and rRampExitRing each contain a vertical opto switch.
Note that the left-ramp front ring is located at the start of the left ramp, but it is not considered the ramp entrance because it has no switch.
There are 4 magnets, all located in the mid backpanel: 3 magnets aligned with the right ramp rings in the back and 1 aligned with the VUK feeding lane.
RightRampRingLeft
RightRampRingCenter
RightRampRingRight
outerLoopMagnet
The right ramp magnets are actively cooled with computer fans. The outerLoopMagnet is not actively cooled.
Every magnet has 3 opto switches (Left, Center, Right). The Left and Right switches for the right ramp magnets are 3.5 cm away on either side. The Left and Right switches for the outerLoopMagnet are in the module top corners, far from the magnet.
There is an up post in the inner loop that can block the ball path and force the ball to drop in the inner loop hole.
Similarly, there is an up post in the outer loop that can block the ball path and force the ball to drop in the outer loop hole. That up post also serves as the VUK feeding the right ramp through the backpanel.
The module prototype included a third up post, but it was omitted from the production version.
There are 4 stand-up targets (target0 to target3) plus the captiveBall target at the end of the captive ball trough. There is no switch for the captive ball bash tube.
List of switches
Switch Name | Location |
captiveBall | back of captive ball trough |
innerLoopCenter | inner loop apex |
innerLoopLeft | inner loop left entrance |
innerLoopRight | inner loop right entrance |
leftRampEnter | left ramp entrance ring |
leftRampExit | left ramp exit ring |
outerLoopCenter | outer loop apex |
outerLoopLeft | top left corner |
outerLoopMagnet | Mid panel behind outer loop up post |
outerLoopRight | top right corner |
rampLoad | exit of backpanel VUK |
rampMagnetCenterHigh | left switch of right ramp center magnet |
rampMagnetCenterMiddle | center switch of right ramp center magnet |
rampMagnetCenterLow | right switch of right ramp center magnet |
rampMagnetLeftHigh | left switch of right ramp left magnet |
rampMagnetLeftMiddle | center switch of right ramp left magnet |
rampMagnetLeftLow | right switch of right ramp left magnet |
rampMagnetRightHigh | left switch of right ramp right magnet |
rampMagnetRightMiddle | center switch of right ramp right magnet |
rampMagnetRightLow | right switch of right ramp right magnet |
rightLoop | right loop slightly right of apex |
rightRampEnter | partially up the right ramp entrance |
rightRampExit | right ramp exit ring |
target0 | left post of left ramp entrance |
target1 | right post of left ramp entrance |
target2 | right post of scoop entrance |
target3 | target at left entrance of the right loop |
vukEntrance2 | inner loop hole |
vukEntrance3 | scoop entrance |
vukEntrance6 | outer loop hole |
vukExit3 | LeftVUK, scoop launcher |
vukExit6 | RightVUK, feeds outer loop up post |
The application should not handle these switches. The application should use BallPaths and the module driver API instead.
PlayfieldModuleSettings
The CCR module driver declares these PlayfieldModuleSettings:
Setting Name | Service Menu Location | Min | Max | Inc | Def |
VUK ramp pulse time | Settings/Mechs/Coils | 8 | 30 | 1 | 16 |
Left magnet throw strength | Settings/Mechs/Coils | 0 (Low) | 2 (High) | 1 | 2 |
Center magnet throw strength | Settings/Mechs/Coils | 0 (Low) | 2 (High) | 1 | 2 |
Right magnet throw strength | Settings/Mechs/Coils | 0 (Low) | 2 (High) | 1 | 2 |
Outer loop loader power | Settings/Mechs/Coils | 10 | 20 | 1 | 16 |
Disable LEDs with diags nav | Settings/Diagnostics | No | Yes | Yes | |
Award right loop w/ target | Settings/Mechs/Switches | No | Yes | No |
There is no need to establish BallPaths on CCR because all BallPaths are static. Dynamic BallPaths were invented later and never backported to this module. The magnets and up posts are controlled with an API instead. See the sections below for details.
This table lists all BallPaths with their Started and Completed events.
A * in the first column indicates the BallPath behaves in an unexpected way.
BallPath | StartedEvent | CompletedEvent | |
* | OuterLoopLeft | Evt_OuterLoopLeftStarted | Evt_OuterLoopLeftCompleted |
* | InnerLoopLeft | Evt_InnerLoopLeftStarted | Evt_InnerLoopLeftCompleted |
LeftRamp | Evt_LeftRampStarted | Evt_LeftRampCompleted | |
* | InnerLoopRight | Evt_InnerLoopRightStarted | Evt_InnerLoopRightCompleted |
RightLoop | Evt_RightLoopStarted | Evt_RightLoopCompleted | |
RightRamp | Evt_RightRampStarted | Evt_RightRampCompleted | |
* | OuterLoopRight | Evt_OuterLoopRightStarted | Evt_OuterLoopRightCompleted |
* | InnerLoopHole | Evt_InnerLoopHole Evt_BallEnteredHole (int 2) | Evt_BallEnteredHole2 |
* | ScoopHole | Evt_Scoop Evt_BallEnteredHole (int 3) | Evt_BallEnteredHole3 |
* | OuterLoopHole | Evt_OuterLoopHole Evt_BallEnteredHole (int 6) | Evt_BallEnteredHole6 |
LeftRampLeftTarget | sw_target0_active | sw_target0_inactive | |
LeftRampRightTarget | sw_target1_active | sw_target1_inactive | |
ScoopTarget | sw_target2_active | sw_target2_inactive | |
RightLoopTarget | sw_target3_active | sw_target3_inactive | |
CaptiveBallTarget | sw_captiveBall_active | sw_captiveBall_inactive |
The driver can distinguish between an inner or outer loop shot from left-to-right or right-to-left, but the switch that completes the BallPath also starts the BallPath in the opposite direction. The BallPath in the opposite direction never completes and times out. Unfortunately, that means StartedEvents for inner and outer loops are unsuitable to give an early audio or visual cue that the shot is in progress. For these shots, it’s better to give feedback only with the CompletedEvent. The RightLoop is not affected by this since it is unidirectional.
For loop and ramp shots (OuterLoopLeft, InnerLoopLeft, LeftRamp, InnerLoopRight, RightLoop, RightRamp, OuterLoopRight), the event argument for the StartedEvent is the EntranceName as a string. The event argument of the CompletedEvent is the ExitName as a string. The application typically ignores the event argument for these events. For these shots only, the driver also posts the ModeToModes event Evt_ShotMade just before the CompletedEvent (event argument is the BallPath name as a string).
The Boolean setting “Award right loop w/ target” determines whether target3 awards a RightLoop shot when hit. If not using target3, the RightLoop is completed when the rightLoop switch is activated. In both cases, the StartedEvent is sent immediately before the CompletedEvent in response to the switch activation. This means the RightLoop BallPath StartedEvent is unsuitable to give an early audio or visual cue.
InnerLoopHole is a unidirectional hole entry through VUK 2. ScoopHole is the hole entry corresponding to the bidirectional TroughLauncher through VUK 3 named LeftVUK. OuterLoopHole is the hole entry corresponding to the bidirectional TroughLauncher through VUK 6 named RightVUK. Interestingly, Lexy Lightspeed also had exactly 2 TroughLaunchers named LeftVUK and RightVUK.
CCR has a TroughLauncher with custom code on VUK 6 named RightVUKToLeftInlane. The module definition file uses VUK 14 which is VUK 6 + 8. Adding a multiple of 8 is what indicates this TroughLauncher shares the same VUK with another TroughLauncher.
TroughLauncher LeftVUK Destination is wrong in CCR.json version 2.4.0.0. It says LowerPlayfield when it should be UpperPlayfield.
The StartedEvents for Hole BallPaths are wrong in CCR.json version 2.4.0.0. The driver sends the same ModeToModes event for all 3 Hole BallPaths: Evt_BallEnteredHole. The event argument is the VUK number as an int.
The SDK spec says a driver that implements a Hole BallPath on a bidirectional TroughLauncher must block the Evt_TroughLauncherEntry event from reaching the application. The CCR module driver mode that implements this runs at priority 170. Make sure the mode in your application that handles Hole BallPaths and Evt_TroughLauncherEntry is at a lower priority. In P3SampleApp, that mode is HomeMode and it runs at priority 20.
Target BallPaths are pure switch events. The driver does not post ModeToModes events for Target BallPaths. This is allowed by the BallPath spec.
This table lists the events posted by the module driver when a particular BallPath is completed. An event in bold indicates an unusual event.
BallPath | Events Posted |
OuterLoopLeft | Evt_OuterLoopLeftStarted Evt_ShotMade ("OuterLoopLeft") Evt_OuterLoopLeftCompleted Evt_OuterLoopRightStarted |
InnerLoopLeft | Evt_InnerLoopLeftStarted Evt_ShotMade ("InnerLoopLeft") Evt_InnerLoopLeftCompleted Evt_InnerLoopRightStarted |
LeftRamp | Evt_LeftRampStarted Evt_ShotMade ("LeftRamp") Evt_LeftRampCompleted |
InnerLoopRight | Evt_InnerLoopRightStarted Evt_InnerLoopLeftStarted Evt_ShotMade ("InnerLoopRight") Evt_InnerLoopRightCompleted |
RightLoop | Evt_RightLoopStarted Evt_ShotMade ("RightLoop") Evt_RightLoopCompleted |
RightRamp | Evt_RightRampStarted Evt_BallInRingMagnet Evt_MagnetRingLostBall Evt_BallInRingMagnet Evt_MagnetRingLostBall Evt_BallInRingMagnet Evt_MagnetRingLostBall Evt_ShotMade ("RightRamp") Evt_RightRampCompleted |
OuterLoopRight | Evt_OuterLoopRightStarted Evt_OuterLoopLeftStarted Evt_ShotMade ("OuterLoopRight") Evt_OuterLoopRightCompleted |
InnerLoopHole | Evt_BallEnteredHole (int 2) Evt_BallEnteredHole2 |
ScoopHole | Evt_BallEnteredHole (int 3) Evt_BallEnteredHole3 |
OuterLoopHole | Evt_BallEnteredHole (int 6) Evt_BallEnteredHole6 |
Raising an up post will block the ball path within the loop. The inner loop up post consistently diverts the ball into the inner loop hole. The outer loop up post typically sends the ball back where it came from; only slow balls are diverted into the outer loop hole.
To enable the up post for a specific shot:
PostModeEventToModes("Evt_EnableBlock", "InnerLoopLeft");
PostModeEventToModes("Evt_EnableBlock", "InnerLoopRight");
PostModeEventToModes("Evt_EnableBlock", "OuterLoopLeft");
PostModeEventToModes("Evt_EnableBlock", "OuterLoopRight");
The up post stays down but raises briefly as soon as the entrance switch is detected for the shot.
The outer-loop up post is temporarily disabled while the outerLoopMagnet is holding a ball. The up post will be re-enabled automatically when the magnet no longer holds the ball.
To disable the up post for a specific shot:
PostModeEventToModes("Evt_DisableBlock", "InnerLoopLeft");
PostModeEventToModes("Evt_DisableBlock", "InnerLoopRight");
PostModeEventToModes("Evt_DisableBlock", "OuterLoopLeft");
PostModeEventToModes("Evt_DisableBlock", "OuterLoopRight");
CCR’s UsageInstructions.txt does an excellent job of explaining the ring magnet API.
This section summarizes the CCR module driver API. Events not documented in UsageInstructions.txt are shown in bold.
Magnet Names
The magnet name is sent and received as a string.
Magnet Name | Description |
"RightRampRingLeft" | The leftmost/highest magnet on the right ramp |
"RightRampRingCenter" | The middle magnet on the right ramp |
"RightRampRingRight" | The rightmost/lowest magnet on the right ramp |
The outerLoopMagnet is designed to stabilize the ball during a RightVUKToLeftInlane launch. It is not designed to catch a ball flying around the loop. This explains why there is no API for it.
Shot Names
The shot name is sent and received as a string.
Shot Name | Description |
"InnerLoopLeft" | Inner loop entered from the left |
"InnerLoopRight" | Inner loop entered from the right |
"OuterLoopLeft" | Outer loop entered from the left |
"OuterLoopRight" | Outer loop entered from the right |
Request events
Usage: PostModeEventToModes(eventName, evtData);
Event Name | Event Data | Description |
Evt_DisableBlock | shotName | Disable the up post for that shot. |
Evt_EnableBlock | shotName | Enable the up post for that shot. |
Evt_MagnetRingCascade | magnetName | Tell the magnet to accelerate an incoming ball to push the caught ball and hopefully catch the incoming ball. |
Evt_MagnetRingCatch | magnetName | Tell the magnet to catch/hold an incoming ball. |
Evt_MagnetRingRelease | magnetName | Tell the magnet to ignore incoming balls and let the caught ball roll out if already caught. |
Evt_MagnetRingThrow | magnetName | Tell the magnet to throw/accelerate an incoming ball. |
Evt_MagnetRingThrowHard | magnetName | Tell the magnet to throw/accelerate an incoming ball with high strength. |
Status events
Usage: AddModeEventHandler(eventName, handler, Priority);
Event Name | Event Data | Description |
Evt_BallInRingMagnet | magnetName | Ring magnet center switch activated. |
Evt_MagnetRingLostBall | magnetName | A caught ball is no longer held by the magnet. |
Evt_MagnetRingHasTwoBalls | magnetName | Multiple switches active for this magnet. |
Evt_MagnetRingCaughtBall | magnetName | A ball has settled on the magnet. |
Blocking with the up post is temporarily disabled in the outer loop when the outerLoopMagnet holds a caught ball during a RightVUKToLeftInlane launch.
Remember to disable magnets when the mode is stopped because that is not done automatically.