mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-10 06:06:47 -04:00
Update assumptions about PLC interface.
This commit is contained in:
@@ -207,7 +207,6 @@ func (arena *Arena) LoadMatch(match *model.Match) error {
|
||||
// Reset the realtime scores.
|
||||
arena.RedRealtimeScore = NewRealtimeScore()
|
||||
arena.BlueRealtimeScore = NewRealtimeScore()
|
||||
arena.Plc.ResetCounts()
|
||||
arena.FieldReset = false
|
||||
arena.scale = new(game.Seesaw)
|
||||
arena.redSwitch = new(game.Seesaw)
|
||||
@@ -376,7 +375,6 @@ func (arena *Arena) Update() {
|
||||
arena.AudienceDisplayScreen = "match"
|
||||
arena.AudienceDisplayNotifier.Notify(nil)
|
||||
arena.FieldTestMode = ""
|
||||
arena.Plc.ResetCounts()
|
||||
arena.sendGameSpecificDataPacket()
|
||||
if !arena.MuteMatchSounds {
|
||||
arena.PlaySoundNotifier.Notify("match-warmup")
|
||||
@@ -677,10 +675,10 @@ func (arena *Arena) handlePlcInput() {
|
||||
}
|
||||
|
||||
// Handle vaults.
|
||||
redForceCubes, redLevitateCubes, redBoostCubes, blueForceCubes, blueLevitateCubes, blueBoostCubes :=
|
||||
redForceDistance, redLevitateDistance, redBoostDistance, blueForceDistance, blueLevitateDistance, blueBoostDistance :=
|
||||
arena.Plc.GetVaults()
|
||||
arena.redVault.UpdateCubes(redForceCubes, redLevitateCubes, redBoostCubes)
|
||||
arena.blueVault.UpdateCubes(blueForceCubes, blueLevitateCubes, blueBoostCubes)
|
||||
arena.redVault.UpdateCubes(redForceDistance, redLevitateDistance, redBoostDistance)
|
||||
arena.blueVault.UpdateCubes(blueForceDistance, blueLevitateDistance, blueBoostDistance)
|
||||
redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost := arena.Plc.GetPowerUpButtons()
|
||||
arena.redVault.UpdateButtons(redForce, redLevitate, redBoost, currentTime)
|
||||
arena.blueVault.UpdateButtons(blueForce, blueLevitate, blueBoost, currentTime)
|
||||
|
||||
153
field/plc.go
153
field/plc.go
@@ -13,15 +13,14 @@ import (
|
||||
)
|
||||
|
||||
type Plc struct {
|
||||
IsHealthy bool
|
||||
address string
|
||||
handler *modbus.TCPClientHandler
|
||||
client modbus.Client
|
||||
Inputs [37]bool
|
||||
Counters [0]uint16
|
||||
Coils [8]bool
|
||||
cycleCounter int
|
||||
resetCountCycles int
|
||||
IsHealthy bool
|
||||
address string
|
||||
handler *modbus.TCPClientHandler
|
||||
client modbus.Client
|
||||
Inputs [inputCount]bool
|
||||
Registers [registerCount]uint16
|
||||
Coils [coilCount]bool
|
||||
cycleCounter int
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -34,57 +33,58 @@ const (
|
||||
// Discrete inputs
|
||||
const (
|
||||
fieldEstop = iota
|
||||
scaleNear
|
||||
scaleFar
|
||||
redEstop1
|
||||
redEstop2
|
||||
redEstop3
|
||||
redSwitchNear
|
||||
redSwitchFar
|
||||
redForceCube1
|
||||
redForceCube2
|
||||
redForceCube3
|
||||
redForceButton
|
||||
redLevitateCube1
|
||||
redLevitateCube2
|
||||
redLevitateCube3
|
||||
redLevitateButton
|
||||
redBoostCube1
|
||||
redBoostCube2
|
||||
redBoostCube3
|
||||
redBoostButton
|
||||
blueEstop1
|
||||
blueEstop2
|
||||
blueEstop3
|
||||
redConnected1
|
||||
redConnected2
|
||||
redConnected3
|
||||
blueConnected1
|
||||
blueConnected2
|
||||
blueConnected3
|
||||
scaleNear
|
||||
scaleFar
|
||||
redSwitchNear
|
||||
redSwitchFar
|
||||
blueSwitchNear
|
||||
blueSwitchFar
|
||||
blueForceCube1
|
||||
blueForceCube2
|
||||
blueForceCube3
|
||||
blueForceButton
|
||||
blueLevitate1
|
||||
blueLevitate2
|
||||
blueLevitate3
|
||||
blueLevitateButton
|
||||
blueBoostCube1
|
||||
blueBoostCube2
|
||||
blueBoostCube3
|
||||
blueBoostButton
|
||||
redForceActivate
|
||||
redLevitateActivate
|
||||
redBoostActivate
|
||||
blueForceActivate
|
||||
blueLevitateActivate
|
||||
blueBoostActivate
|
||||
inputCount
|
||||
)
|
||||
|
||||
// 16-bit registers
|
||||
const ()
|
||||
const (
|
||||
red1Bandwidth = iota
|
||||
red2Bandwidth
|
||||
red3Bandwidth
|
||||
blue1Bandwidth
|
||||
blue2Bandwidth
|
||||
blue3Bandwidth
|
||||
redForceDistance
|
||||
redLevitateDistance
|
||||
redBoostDistance
|
||||
blueForceDistance
|
||||
blueLevitateDistance
|
||||
blueBoostDistance
|
||||
registerCount
|
||||
)
|
||||
|
||||
// Coils
|
||||
const (
|
||||
redForceLight = iota
|
||||
redLevitateLight
|
||||
redBoostLight
|
||||
blueForceLight
|
||||
blueLevitateLight
|
||||
blueBoostLight
|
||||
resetCounts
|
||||
heartbeat
|
||||
heartbeat = iota
|
||||
stackLightGreen
|
||||
stackLightOrange
|
||||
stackLightRed
|
||||
stackLightBlue
|
||||
coilCount
|
||||
)
|
||||
|
||||
func (plc *Plc) SetAddress(address string) {
|
||||
@@ -163,51 +163,15 @@ func (plc *Plc) GetScaleAndSwitches() ([2]bool, [2]bool, [2]bool) {
|
||||
}
|
||||
|
||||
// Returns the state of the red and blue vault power cube sensors.
|
||||
func (plc *Plc) GetVaults() ([3]bool, [3]bool, [3]bool, [3]bool, [3]bool, [3]bool) {
|
||||
var redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost [3]bool
|
||||
|
||||
redForce[0] = plc.Inputs[redForceCube1]
|
||||
redForce[1] = plc.Inputs[redForceCube2]
|
||||
redForce[2] = plc.Inputs[redForceCube3]
|
||||
redLevitate[0] = plc.Inputs[redLevitateCube1]
|
||||
redLevitate[1] = plc.Inputs[redLevitateCube2]
|
||||
redLevitate[2] = plc.Inputs[redLevitateCube3]
|
||||
redBoost[0] = plc.Inputs[redBoostCube1]
|
||||
redBoost[1] = plc.Inputs[redBoostCube2]
|
||||
redBoost[2] = plc.Inputs[redBoostCube3]
|
||||
blueForce[0] = plc.Inputs[blueForceCube1]
|
||||
blueForce[1] = plc.Inputs[blueForceCube2]
|
||||
blueForce[2] = plc.Inputs[blueForceCube3]
|
||||
blueLevitate[0] = plc.Inputs[blueLevitate1]
|
||||
blueLevitate[1] = plc.Inputs[blueLevitate2]
|
||||
blueLevitate[2] = plc.Inputs[blueLevitate3]
|
||||
blueBoost[0] = plc.Inputs[blueBoostCube1]
|
||||
blueBoost[1] = plc.Inputs[blueBoostCube2]
|
||||
blueBoost[2] = plc.Inputs[blueBoostCube3]
|
||||
|
||||
return redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost
|
||||
func (plc *Plc) GetVaults() (uint16, uint16, uint16, uint16, uint16, uint16) {
|
||||
return plc.Registers[redForceDistance], plc.Registers[redLevitateDistance], plc.Registers[redBoostDistance],
|
||||
plc.Registers[blueForceDistance], plc.Registers[blueLevitateDistance], plc.Registers[blueBoostDistance]
|
||||
}
|
||||
|
||||
// Returns the state of the red and blue power up buttons on the vaults.
|
||||
func (plc *Plc) GetPowerUpButtons() (bool, bool, bool, bool, bool, bool) {
|
||||
return plc.Inputs[redForceButton], plc.Inputs[redLevitateButton], plc.Inputs[redBoostButton],
|
||||
plc.Inputs[blueForceButton], plc.Inputs[blueLevitateButton], plc.Inputs[blueBoostButton]
|
||||
}
|
||||
|
||||
// Resets the counter counts to zero.
|
||||
func (plc *Plc) ResetCounts() {
|
||||
plc.Coils[resetCounts] = true
|
||||
plc.resetCountCycles = 0
|
||||
}
|
||||
|
||||
// Sets the state of the lights inside the power up buttons on the vaults.
|
||||
func (plc *Plc) SetPowerUpLights(redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost bool) {
|
||||
plc.Coils[redForceLight] = redForce
|
||||
plc.Coils[redLevitateLight] = redLevitate
|
||||
plc.Coils[redBoostLight] = redBoost
|
||||
plc.Coils[blueForceLight] = blueForce
|
||||
plc.Coils[blueLevitateLight] = blueLevitate
|
||||
plc.Coils[blueBoostLight] = blueBoost
|
||||
return plc.Inputs[redForceActivate], plc.Inputs[redLevitateActivate], plc.Inputs[redBoostActivate],
|
||||
plc.Inputs[blueForceActivate], plc.Inputs[blueLevitateActivate], plc.Inputs[blueBoostActivate]
|
||||
}
|
||||
|
||||
func (plc *Plc) GetCycleState(max, index, duration int) bool {
|
||||
@@ -258,22 +222,22 @@ func (plc *Plc) readInputs() bool {
|
||||
}
|
||||
|
||||
func (plc *Plc) readCounters() bool {
|
||||
if len(plc.Counters) == 0 {
|
||||
if len(plc.Registers) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
registers, err := plc.client.ReadHoldingRegisters(0, uint16(len(plc.Counters)))
|
||||
registers, err := plc.client.ReadHoldingRegisters(0, uint16(len(plc.Registers)))
|
||||
if err != nil {
|
||||
log.Printf("PLC error reading registers: %v", err)
|
||||
return false
|
||||
}
|
||||
if len(registers)/2 < len(plc.Counters) {
|
||||
if len(registers)/2 < len(plc.Registers) {
|
||||
log.Printf("Insufficient length of PLC counters: got %d bytes, expected %d words.", len(registers),
|
||||
len(plc.Counters))
|
||||
len(plc.Registers))
|
||||
return false
|
||||
}
|
||||
|
||||
copy(plc.Counters[:], byteToUint(registers, len(plc.Counters)))
|
||||
copy(plc.Registers[:], byteToUint(registers, len(plc.Registers)))
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -288,11 +252,6 @@ func (plc *Plc) writeCoils() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if plc.resetCountCycles > 5 {
|
||||
plc.Coils[resetCounts] = false // Need to send a short pulse to reset the counters.
|
||||
} else {
|
||||
plc.resetCountCycles++
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ type Vault struct {
|
||||
}
|
||||
|
||||
// Updates the state of the vault given the state of the individual power cube sensors.
|
||||
func (vault *Vault) UpdateCubes(forceCubes, levitateCubes, boostCubes [3]bool) {
|
||||
vault.numForceCubes = countCubes(forceCubes)
|
||||
vault.numLevitateCubes = countCubes(levitateCubes)
|
||||
vault.numBoostCubes = countCubes(boostCubes)
|
||||
func (vault *Vault) UpdateCubes(forceDistance, levitateDistance, boostDistance uint16) {
|
||||
vault.numForceCubes = countCubes(forceDistance)
|
||||
vault.numLevitateCubes = countCubes(levitateDistance)
|
||||
vault.numBoostCubes = countCubes(boostDistance)
|
||||
}
|
||||
|
||||
// Updates the state of the vault given the state of the power up buttons.
|
||||
@@ -48,14 +48,15 @@ func (vault *Vault) GetNumCubes() int {
|
||||
return vault.numForceCubes + vault.numLevitateCubes + vault.numBoostCubes
|
||||
}
|
||||
|
||||
func countCubes(cubes [3]bool) int {
|
||||
if cubes[0] {
|
||||
if cubes[1] {
|
||||
if cubes[2] {
|
||||
return 3
|
||||
}
|
||||
return 2
|
||||
}
|
||||
func countCubes(distance uint16) int {
|
||||
// TODO(patrick): Update with real values once there is a physical setup to test with.
|
||||
if distance >= 3000 {
|
||||
return 3
|
||||
}
|
||||
if distance >= 2000 {
|
||||
return 2
|
||||
}
|
||||
if distance >= 1000 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
|
||||
@@ -10,49 +10,50 @@ import (
|
||||
)
|
||||
|
||||
func TestVaultNumCubes(t *testing.T) {
|
||||
// TODO(patrick): Update with real values once there is a physical setup to test with.
|
||||
vault := Vault{}
|
||||
assert.Equal(t, 0, vault.GetNumCubes())
|
||||
|
||||
vault.UpdateCubes([3]bool{true, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(1000, 0, 0)
|
||||
assert.Equal(t, 1, vault.GetNumCubes())
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, false, true}, [3]bool{true, false, false})
|
||||
vault.UpdateCubes(0, 1000, 1000)
|
||||
assert.Equal(t, 2, vault.GetNumCubes())
|
||||
|
||||
vault.UpdateCubes([3]bool{false, true, true}, [3]bool{false, false, true}, [3]bool{true, true, false})
|
||||
vault.UpdateCubes(0, 0, 2000)
|
||||
assert.Equal(t, 2, vault.GetNumCubes())
|
||||
|
||||
vault.UpdateCubes([3]bool{true, true, false}, [3]bool{true, true, false}, [3]bool{true, true, true})
|
||||
vault.UpdateCubes(2000, 2000, 3000)
|
||||
assert.Equal(t, 7, vault.GetNumCubes())
|
||||
|
||||
vault.UpdateCubes([3]bool{true, true, true}, [3]bool{true, true, true}, [3]bool{true, true, true})
|
||||
vault.UpdateCubes(3000, 3000, 3000)
|
||||
assert.Equal(t, 9, vault.GetNumCubes())
|
||||
}
|
||||
|
||||
func TestVaultLevitate(t *testing.T) {
|
||||
vault := Vault{}
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(0, 0, 0)
|
||||
vault.UpdateButtons(false, true, false, time.Now())
|
||||
assert.False(t, vault.LevitatePlayed)
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(0, 1000, 0)
|
||||
vault.UpdateButtons(false, true, false, time.Now())
|
||||
assert.False(t, vault.LevitatePlayed)
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, true, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(0, 2000, 0)
|
||||
vault.UpdateButtons(false, true, false, time.Now())
|
||||
assert.False(t, vault.LevitatePlayed)
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, true, true}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(0, 3000, 0)
|
||||
vault.UpdateButtons(true, false, true, time.Now())
|
||||
assert.False(t, vault.LevitatePlayed)
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, true, true}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(0, 3000, 0)
|
||||
vault.UpdateButtons(false, true, false, time.Now())
|
||||
assert.True(t, vault.LevitatePlayed)
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{true, true, true}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(0, 3000, 0)
|
||||
vault.UpdateButtons(false, false, false, time.Now())
|
||||
assert.True(t, vault.LevitatePlayed)
|
||||
}
|
||||
@@ -61,16 +62,16 @@ func TestVaultForce(t *testing.T) {
|
||||
vault := Vault{alliance: blueAlliance}
|
||||
ResetPowerUps()
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(0, 0, 0)
|
||||
vault.UpdateButtons(true, false, false, time.Now())
|
||||
assert.Nil(t, vault.ForcePowerUp)
|
||||
|
||||
vault.UpdateCubes([3]bool{true, true, true}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(3000, 0, 0)
|
||||
vault.UpdateButtons(false, true, true, time.Now())
|
||||
assert.Nil(t, vault.ForcePowerUp)
|
||||
|
||||
// Activation with one cube.
|
||||
vault.UpdateCubes([3]bool{true, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(1000, 0, 0)
|
||||
vault.UpdateButtons(true, false, false, time.Now())
|
||||
if assert.NotNil(t, vault.ForcePowerUp) {
|
||||
assert.Equal(t, blueAlliance, vault.ForcePowerUp.alliance)
|
||||
@@ -81,7 +82,7 @@ func TestVaultForce(t *testing.T) {
|
||||
// Activation with two cubes.
|
||||
vault = Vault{alliance: redAlliance}
|
||||
ResetPowerUps()
|
||||
vault.UpdateCubes([3]bool{true, true, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(2000, 0, 0)
|
||||
vault.UpdateButtons(true, false, false, time.Now())
|
||||
if assert.NotNil(t, vault.ForcePowerUp) {
|
||||
assert.Equal(t, redAlliance, vault.ForcePowerUp.alliance)
|
||||
@@ -92,7 +93,7 @@ func TestVaultForce(t *testing.T) {
|
||||
// Activation with three cubes.
|
||||
vault = Vault{alliance: blueAlliance}
|
||||
ResetPowerUps()
|
||||
vault.UpdateCubes([3]bool{true, true, true}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(3000, 0, 0)
|
||||
vault.UpdateButtons(true, false, false, time.Now())
|
||||
assert.NotNil(t, vault.ForcePowerUp)
|
||||
if assert.NotNil(t, vault.ForcePowerUp) {
|
||||
@@ -101,7 +102,7 @@ func TestVaultForce(t *testing.T) {
|
||||
assert.Equal(t, 3, vault.ForcePowerUp.level)
|
||||
}
|
||||
|
||||
vault.UpdateCubes([3]bool{true, true, true}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(3000, 0, 0)
|
||||
vault.UpdateButtons(false, false, false, time.Now())
|
||||
assert.NotNil(t, vault.ForcePowerUp)
|
||||
}
|
||||
@@ -110,16 +111,16 @@ func TestVaultBoost(t *testing.T) {
|
||||
vault := Vault{alliance: blueAlliance}
|
||||
ResetPowerUps()
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{false, false, false})
|
||||
vault.UpdateCubes(0, 0, 0)
|
||||
vault.UpdateButtons(false, false, true, time.Now())
|
||||
assert.Nil(t, vault.BoostPowerUp)
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, true, true})
|
||||
vault.UpdateCubes(0, 0, 3000)
|
||||
vault.UpdateButtons(true, true, false, time.Now())
|
||||
assert.Nil(t, vault.BoostPowerUp)
|
||||
|
||||
// Activation with one cube.
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, false, false})
|
||||
vault.UpdateCubes(0, 0, 1000)
|
||||
vault.UpdateButtons(false, false, true, time.Now())
|
||||
if assert.NotNil(t, vault.BoostPowerUp) {
|
||||
assert.Equal(t, blueAlliance, vault.BoostPowerUp.alliance)
|
||||
@@ -130,7 +131,7 @@ func TestVaultBoost(t *testing.T) {
|
||||
// Activation with two cubes.
|
||||
vault = Vault{alliance: redAlliance}
|
||||
ResetPowerUps()
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, true, false})
|
||||
vault.UpdateCubes(0, 0, 2000)
|
||||
vault.UpdateButtons(false, false, true, time.Now())
|
||||
if assert.NotNil(t, vault.BoostPowerUp) {
|
||||
assert.Equal(t, redAlliance, vault.BoostPowerUp.alliance)
|
||||
@@ -141,7 +142,7 @@ func TestVaultBoost(t *testing.T) {
|
||||
// Activation with three cubes.
|
||||
vault = Vault{alliance: blueAlliance}
|
||||
ResetPowerUps()
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, true, true})
|
||||
vault.UpdateCubes(0, 0, 3000)
|
||||
vault.UpdateButtons(false, false, true, time.Now())
|
||||
assert.NotNil(t, vault.BoostPowerUp)
|
||||
if assert.NotNil(t, vault.BoostPowerUp) {
|
||||
@@ -150,7 +151,7 @@ func TestVaultBoost(t *testing.T) {
|
||||
assert.Equal(t, 3, vault.BoostPowerUp.level)
|
||||
}
|
||||
|
||||
vault.UpdateCubes([3]bool{false, false, false}, [3]bool{false, false, false}, [3]bool{true, true, true})
|
||||
vault.UpdateCubes(0, 0, 3000)
|
||||
vault.UpdateButtons(false, false, false, time.Now())
|
||||
assert.NotNil(t, vault.BoostPowerUp)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func (web *Web) fieldGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
Counters []uint16
|
||||
Coils []bool
|
||||
}{web.arena.EventSettings, web.arena.AllianceStationDisplays, web.arena.FieldTestMode, web.arena.Plc.Inputs[:],
|
||||
web.arena.Plc.Counters[:], web.arena.Plc.Coils[:]}
|
||||
web.arena.Plc.Registers[:], web.arena.Plc.Coils[:]}
|
||||
err = template.ExecuteTemplate(w, "base", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
Reference in New Issue
Block a user