Implement PLC integration for all outputs.

This commit is contained in:
Patrick Fairbank
2020-04-04 22:48:20 -07:00
parent ae4b03dfbc
commit 3739cd8690
4 changed files with 84 additions and 11 deletions

View File

@@ -766,7 +766,7 @@ func (arena *Arena) handlePlcInput() {
if arena.Plc.IsEnabled() {
// Handle power ports.
redPortCells, bluePortCells := arena.Plc.GetPowerPorts()
redPowerPort := arena.RedRealtimeScore.powerPort
redPowerPort := &arena.RedRealtimeScore.powerPort
redPowerPort.UpdateState(redPortCells, redScore.CellCountingStage(teleopStarted), matchStartTime, currentTime)
redScore.AutoCellsBottom = redPowerPort.AutoCellsBottom
redScore.AutoCellsOuter = redPowerPort.AutoCellsOuter
@@ -774,7 +774,7 @@ func (arena *Arena) handlePlcInput() {
redScore.TeleopCellsBottom = redPowerPort.TeleopCellsBottom
redScore.TeleopCellsOuter = redPowerPort.TeleopCellsOuter
redScore.TeleopCellsInner = redPowerPort.TeleopCellsInner
bluePowerPort := arena.BlueRealtimeScore.powerPort
bluePowerPort := &arena.BlueRealtimeScore.powerPort
bluePowerPort.UpdateState(bluePortCells, blueScore.CellCountingStage(teleopStarted), matchStartTime,
currentTime)
blueScore.AutoCellsBottom = bluePowerPort.AutoCellsBottom
@@ -786,12 +786,12 @@ func (arena *Arena) handlePlcInput() {
// Handle control panel.
redColor, redSegmentCount, blueColor, blueSegmentCount := arena.Plc.GetControlPanels()
redControlPanel := arena.RedRealtimeScore.ControlPanel
redControlPanel := &arena.RedRealtimeScore.ControlPanel
redControlPanel.CurrentColor = redColor
redControlPanel.UpdateState(redSegmentCount, redScore.StageAtCapacity(game.Stage2, teleopStarted),
redScore.StageAtCapacity(game.Stage3, teleopStarted), currentTime)
redScore.ControlPanelStatus = redControlPanel.ControlPanelStatus
blueControlPanel := arena.BlueRealtimeScore.ControlPanel
blueControlPanel := &arena.BlueRealtimeScore.ControlPanel
blueControlPanel.CurrentColor = blueColor
blueControlPanel.UpdateState(blueSegmentCount, blueScore.StageAtCapacity(game.Stage2, teleopStarted),
blueScore.StageAtCapacity(game.Stage3, teleopStarted), currentTime)
@@ -820,7 +820,13 @@ func (arena *Arena) handlePlcInput() {
}
}
// Updates the PLC's coils based on its inputs and the current scoring state.
func (arena *Arena) handlePlcOutput() {
matchStartTime := arena.MatchStartTime
currentTime := time.Now()
redScore := &arena.RedRealtimeScore.CurrentScore
blueScore := &arena.BlueRealtimeScore.CurrentScore
switch arena.MatchState {
case PreMatch:
if arena.lastMatchState != PreMatch {
@@ -849,15 +855,49 @@ func (arena *Arena) handlePlcOutput() {
scoreReady := arena.RedRealtimeScore.FoulsCommitted && arena.BlueRealtimeScore.FoulsCommitted &&
arena.alliancePostMatchScoreReady("red") && arena.alliancePostMatchScoreReady("blue")
arena.Plc.SetStackLights(false, false, !scoreReady, false)
if arena.lastMatchState != PostMatch {
go func() {
time.Sleep(time.Second * game.PowerPortTeleopGracePeriodSec)
arena.Plc.SetPowerPortMotors(false)
}()
}
arena.Plc.SetStageActivatedLights([3]bool{false, false, false}, [3]bool{false, false, false})
arena.Plc.SetControlPanelLights(false, false)
case AutoPeriod:
arena.Plc.SetStackLights(false, false, false, true)
arena.Plc.SetPowerPortMotors(true)
fallthrough
case PausePeriod:
fallthrough
case TeleopPeriod:
arena.Plc.SetStackLights(false, false, false, true)
if arena.lastMatchState != TeleopPeriod {
arena.Plc.SetStageActivatedLights(arena.RedScoreSummary().StagesActivated,
arena.BlueScoreSummary().StagesActivated)
controlPanelLightState := func(state game.ControlPanelLightState) bool {
switch state {
case game.ControlPanelLightOn:
return true
case game.ControlPanelLightFlashing:
return arena.Plc.GetCycleState(2, 0, 2)
default:
return false
}
}
arena.Plc.SetControlPanelLights(
controlPanelLightState(arena.RedRealtimeScore.ControlPanel.ControlPanelLightState),
controlPanelLightState(arena.BlueRealtimeScore.ControlPanel.ControlPanelLightState))
// If the PLC reports a ball jam, blink the orange light and the power port color.
redJam, blueJam := arena.Plc.GetPowerPortJams()
blink := arena.Plc.GetCycleState(2, 0, 2)
arena.Plc.SetStackLights(redJam && blink, blueJam && blink, (redJam || blueJam) && !blink, true)
}
if game.ShouldAssessRung(matchStartTime, currentTime) {
arena.Plc.SetShieldGeneratorLights(redScore.RungIsLevel, blueScore.RungIsLevel)
} else {
arena.Plc.SetShieldGeneratorLights(false, false)
}
}
func (arena *Arena) handleEstop(station string, state bool) {

View File

@@ -9,7 +9,7 @@ import "time"
const (
powerPortAutoGracePeriodSec = 5
powerPortTeleopGracePeriodSec = 5
PowerPortTeleopGracePeriodSec = 5
rungAssessmentDelaySec = 5
)

View File

@@ -23,7 +23,7 @@ type PowerPort struct {
func (powerPort *PowerPort) UpdateState(portCells [3]int, stage Stage, matchStartTime, currentTime time.Time) {
autoValidityDuration := GetDurationToAutoEnd() + powerPortAutoGracePeriodSec*time.Second
autoValidityCutoff := matchStartTime.Add(autoValidityDuration)
teleopValidityDuration := GetDurationToTeleopEnd() + powerPortTeleopGracePeriodSec*time.Second
teleopValidityDuration := GetDurationToTeleopEnd() + PowerPortTeleopGracePeriodSec*time.Second
teleopValidityCutoff := matchStartTime.Add(teleopValidityDuration)
newBottomCells := portCells[0] - totalPortCells(powerPort.AutoCellsBottom, powerPort.TeleopCellsBottom)

View File

@@ -224,6 +224,11 @@ func (plc *Plc) GetPowerPorts() ([3]int, [3]int) {
}
}
// Returns whether each of the red and blue power ports are jammed.
func (plc *Plc) GetPowerPortJams() (bool, bool) {
return plc.inputs[redPowerPortJam], plc.inputs[bluePowerPortJam]
}
// Returns the current color and number of segment transitions for each of the red and blue control panels.
func (plc *Plc) GetControlPanels() (game.ControlPanelColor, int, game.ControlPanelColor, int) {
return game.ControlPanelColor(plc.registers[redControlPanelColor]), int(plc.registers[redControlPanelSegments]),
@@ -235,7 +240,7 @@ func (plc *Plc) GetRungs() (bool, bool) {
return plc.inputs[redRungIsLevel], plc.inputs[blueRungIsLevel]
}
// Set the on/off state of the stack lights on the scoring table.
// Sets the on/off state of the stack lights on the scoring table.
func (plc *Plc) SetStackLights(red, blue, orange, green bool) {
plc.coils[stackLightRed] = red
plc.coils[stackLightBlue] = blue
@@ -243,15 +248,43 @@ func (plc *Plc) SetStackLights(red, blue, orange, green bool) {
plc.coils[stackLightGreen] = green
}
// Set the on/off state of the stack lights on the scoring table.
// Triggers the "match ready" chime if the state is true.
func (plc *Plc) SetStackBuzzer(state bool) {
plc.coils[stackLightBuzzer] = state
}
// Sets the on/off state of the field reset light.
func (plc *Plc) SetFieldResetLight(state bool) {
plc.coils[fieldResetLight] = state
}
// Sets the on/off state of the agitator motors within each power port.
func (plc *Plc) SetPowerPortMotors(state bool) {
plc.coils[powerPortMotors] = state
}
// Sets the on/off state of the lights mounted within the shield generator trussing.
func (plc *Plc) SetStageActivatedLights(red, blue [3]bool) {
plc.coils[redStage1Light] = red[0]
plc.coils[redStage2Light] = red[1]
plc.coils[redStage3Light] = red[2]
plc.coils[blueStage1Light] = blue[0]
plc.coils[blueStage2Light] = blue[1]
plc.coils[blueStage3Light] = blue[2]
}
// Sets the on/off state of the red and blue alliance stack lights mounted to the control panel.
func (plc *Plc) SetControlPanelLights(red, blue bool) {
plc.coils[redControlPanelLight] = red
plc.coils[blueControlPanelLight] = blue
}
// Sets the on/off state of the red and blue alliance stack lights mounted to the top of the shield generator.
func (plc *Plc) SetShieldGeneratorLights(red, blue bool) {
plc.coils[redTrussLight] = red
plc.coils[blueTrussLight] = blue
}
func (plc *Plc) GetCycleState(max, index, duration int) bool {
return plc.cycleCounter/duration%max == index
}