Exemple #1
0
 def sweep (self):
     self.part ('Timers')
     self.regularPhaseTimer.reset (self.regularPhaseTimer > self.tEastWestBlink or self.cycleMode or self.nightMode or self.offMode)
     self.cyclePhaseTimer.reset (self.cyclePhaseTimer > self.tWestBlink or self.regularMode or self.nightMode or self.offMode)
     self.blinkTimer.reset (self.blinkTimer > self.tBlink)
     self.blinkPulse.trigger (self.blinkTimer == 0)
     self.blink.mark (not self.blink, self.blinkPulse)
     
     self.part ('Mode switching')
     self.modePulse.trigger (self.modeButton)
     self.modeStep.set ((self.modeStep + 1) % 4, self.modePulse)
     self.regularMode.mark (self.modeStep == 0)
     self.cycleMode.mark (self.modeStep == 1)
     self.nightMode.mark (self.modeStep == 2)
     self.offMode.mark (self.modeStep == 3)
     
     self.part ('Regular mode phases')
     self.northSouthGreen.mark (0 < self.regularPhaseTimer < self.tNorthSouthGreen)
     self.northSouthBlink.mark (self.tNorthSouthGreen < self.regularPhaseTimer < self.tNorthSouthBlink)
     self.eastWestGreen.mark (self.tNorthSouthBlink < self.regularPhaseTimer < self.tEastWestGreen)
     self.eastWestBlink.mark (self.tEastWestGreen < self.regularPhaseTimer)
     
     self.part ('Cycle mode phases')
     self.northGreen.mark (0 < self.cyclePhaseTimer < self.tNorthGreen)
     self.northBlink.mark (self.tNorthGreen < self.cyclePhaseTimer < self.tNorthBlink)
     
     self.eastGreen.mark (self.tNorthBlink < self.cyclePhaseTimer < self.tEastGreen)
     self.eastBlink.mark (self.tEastGreen < self.cyclePhaseTimer < self.tEastBlink)
     
     self.southGreen.mark (self.tEastBlink < self.cyclePhaseTimer < self.tSouthGreen)
     self.southBlink.mark (self.tSouthGreen < self.cyclePhaseTimer < self.tSouthBlink)
     
     self.westGreen.mark (self.tSouthBlink < self.cyclePhaseTimer < self.tWestGreen)
     self.westBlink.mark (self.tWestGreen < self.cyclePhaseTimer)
     
     self.part ('Traffic lamps')
     self.northGreenLamp.mark (self.northSouthGreen or self.northGreen)
     self.northYellowLamp.mark ((self.northSouthBlink or self.northBlink or self.nightMode) and self.blink)
     self.northRedLamp.mark (not (self.northSouthGreen or self.northGreen or self.northSouthBlink or self.northBlink or self.nightMode or self.offMode))
     
     self.eastGreenLamp.mark (self.eastWestGreen or self.eastGreen)
     self.eastYellowLamp.mark ((self.eastWestBlink or self.eastBlink or self.nightMode) and self.blink)
     self.eastRedLamp.mark (not (self.eastWestGreen or self.eastGreen or self.eastWestBlink or self.eastBlink or self.nightMode or self.offMode))
     
     self.southGreenLamp.mark (self.northSouthGreen or self.southGreen)
     self.southYellowLamp.mark ((self.northSouthBlink or self.southBlink or self.nightMode) and self.blink)
     self.southRedLamp.mark (not (self.northSouthGreen or self.southGreen or self.northSouthBlink or self.southBlink or self.nightMode or self.offMode))
     
     self.westGreenLamp.mark (self.eastWestGreen or self.westGreen)
     self.westYellowLamp.mark ((self.eastWestBlink or self.westBlink or self.nightMode) and self.blink)
     self.westRedLamp.mark (not (self.eastWestGreen or self.westGreen or self.eastWestBlink or self.westBlink or self.nightMode or self.offMode))
     
     self.part ('Street illumination')
     self.brightPulse.trigger (self.brightButton)
     self.brightDirection.mark (not self.brightDirection, self.brightPulse)
     self.brightDelta.set (-self.brightFluxus * sp.world.period, self.brightDirection, self.brightFluxus * sp.world.period)
     self.streetLamp.set (sp.limit (self.streetLamp + self.brightDelta, self.brightMin, self.brightMax), self.brightButton)
Exemple #2
0
    def sweep(self):
        self.part('Torso')
        self.torTorq.set(sp.limit(self.torGain * self.torVolt, self.torMax),
                         self.torEnab, 0)
        self.torBrake.mark(not self.torEnab)
        self.torAccel.set(self.torSpeed / -sp.world.period, self.torBrake,
                          self.torTorq / self.torInert)
        self.torSpeed.set(self.torSpeed + self.torAccel * sp.world.period)
        self.torAng.set(self.torAng + self.torSpeed * sp.world.period)

        self.part('upper arm')
        self.uppTorq.set(sp.limit(self.uppGain * self.uppVolt, self.uppMax),
                         self.uppEnab, 0)
        self.uppBrake.mark(not self.uppEnab)
        self.uppAccel.set(self.uppSpeed / -sp.world.period, self.uppBrake,
                          self.uppTorq / self.uppInert)
        self.uppSpeed.set(self.uppSpeed + self.uppAccel * sp.world.period)
        self.uppAng.set(self.uppAng + self.uppSpeed * sp.world.period)

        self.part('fore arm')
        self.forTorq.set(sp.limit(self.forGain * self.forVolt, self.forMax),
                         self.forEnab, 0)
        self.forBrake.mark(not self.forEnab)
        self.forAccel.set(self.forSpeed / -sp.world.period, self.forBrake,
                          self.forTorq / self.forInert)
        self.forSpeed.set(self.forSpeed + self.forAccel * sp.world.period)
        self.forAng.set(self.forAng + self.forSpeed * sp.world.period)

        self.part('wrist')
        self.wriTorq.set(sp.limit(self.wriGain * self.wriVolt, self.wriMax),
                         self.wriEnab, 0)
        self.wriBrake.mark(not self.wriEnab)
        self.wriAccel.set(self.wriSpeed / -sp.world.period, self.wriBrake,
                          self.wriTorq / self.wriInert)
        self.wriSpeed.set(self.wriSpeed + self.wriAccel * sp.world.period)
        self.wriAng.set(self.wriAng + self.wriSpeed * sp.world.period)

        self.part('hand and fingers')
        self.hanAng.set(self.hanAngSet, self.hanEnab)
        self.finAng.set(self.finAngSet, self.finEnab)
Exemple #3
0
    def sweep(self):
        self.local_sail_angle.set(self.local_sail_angle - 1, self.local_sail_angle > self.target_sail_angle)
        self.local_sail_angle.set(self.local_sail_angle + 1, self.local_sail_angle < self.target_sail_angle)
        self.global_sail_angle.set((self.sailboat_rotation + self.local_sail_angle + 180) % 360)

        self.gimbal_rudder_angle.set(self.gimbal_rudder_angle - 1,
                                     self.gimbal_rudder_angle > self.target_gimbal_rudder_angle)
        self.gimbal_rudder_angle.set(self.gimbal_rudder_angle + 1,
                                     self.gimbal_rudder_angle < self.target_gimbal_rudder_angle)


        if not self.pause:
            # Calculate forward force in N based on the angle between the sail and the wind
            self.sail_alpha.set(sp.abs(self.global_sail_angle - sp.world.wind.wind_direction) % 360)
            self.sail_alpha.set(sp.abs(180 - self.sail_alpha) % 360, self.sail_alpha > 90)
            self.boot_wind.set(self.forward_velocity)
            self.alfa.set(sp.world.wind.wind_direction - self.sailboat_rotation)

            # headforce = sail area * wind pressure
            # wind pressure = 0.613 * wind speed ^ 2
            self.head_wind_force.set(2 * 0.613 * 2 * self.forward_velocity)

            #bereken de kracht van de apparent wind door de echte wind te gebruiken en de rotatie van de boot
            self.apparent_wind.set(sp.sqrt(sp.world.wind.wind_scalar * sp.world.wind.wind_scalar + self.head_wind_force * self.head_wind_force + 2 * sp.world.wind.wind_scalar * self.head_wind_force * sp.cos(self.alfa)))
            
            #bereken de hoek van de apparent wind aan de hand van de echte wind en de rotatie van de boot
            self.apparent_wind_angle.set(sp.acos(round((sp.world.wind.wind_scalar * sp.cos(self.alfa) + self.head_wind_force) / self.apparent_wind, 2)))
            # print(round((sp.world.wind.wind_scalar * sp.cos(self.alfa) + self.forward_velocity) / self.apparent_wind, 2))
            self.perpendicular_sail_force.set(self.apparent_wind * sp.sin(self.sail_alpha))
            self.forward_sail_force.set(self.perpendicular_sail_force * sp.sin(self.local_sail_angle))
            self.forward_sail_force.set(sp.abs(self.forward_sail_force))
            self.drag.set((0.83 * self.forward_velocity - 0.38))
            if self.drag < 0:
                self.drag.set(0)
            # Sailing against wind
            min_threshold = (self.global_sail_angle - 180) % 360
            max_threshold = (self.global_sail_angle + 180) % 360
            self.forward_sail_force.set(self.forward_sail_force,
                                        is_sailing_against_wind(min_threshold,
                                                                max_threshold,
                                                                self.local_sail_angle,
                                                                self.global_sail_angle,
                                                                sp.world.wind.wind_direction))

            # Newton's second law
            self.drag_deacceleration.set(self.drag / self.mass)
            self.acceleration.set((self.forward_sail_force / self.mass) - self.drag_deacceleration)
            self.forward_velocity.set(sp.limit(self.forward_velocity + self.acceleration * sp.world.period, 20))

            # Splitting forward velocity vector into vertical and horizontal components
            self.vertical_velocity.set(sp.sin(self.sailboat_rotation) * self.forward_velocity)
            self.horizontal_velocity.set(sp.cos(self.sailboat_rotation) * self.forward_velocity)

            self.position_x.set(self.position_x + self.horizontal_velocity * 0.001)
            self.position_y.set(self.position_y + self.vertical_velocity * 0.001)
            self.rotation_speed.set(0.001 * self.gimbal_rudder_angle * self.forward_velocity)
            self.sailboat_rotation.set((self.sailboat_rotation - self.rotation_speed) % 360)
            self.boot_direction.set(180 + self.sailboat_rotation)
            self.head_wind_direction.set((self.boot_direction + 180) % 360)

            if sp.world.wind.wind_direction <= self.head_wind_direction:
                self.true_apparent_wind.set((self.head_wind_direction - self.apparent_wind_angle) % 360)
            else:
                self.true_apparent_wind.set((self.head_wind_direction + self.apparent_wind_angle) % 360)
    def sweep(self):
        self.local_sail_angle.set(
            self.local_sail_angle - 1,
            self.local_sail_angle > self.target_sail_angle)
        self.local_sail_angle.set(
            self.local_sail_angle + 1,
            self.local_sail_angle < self.target_sail_angle)
        self.global_sail_angle.set(
            (self.sailboat_rotation + self.local_sail_angle + 180) % 360)

        self.gimbal_rudder_angle.set(
            self.gimbal_rudder_angle - 1,
            self.gimbal_rudder_angle > self.target_gimbal_rudder_angle)
        self.gimbal_rudder_angle.set(
            self.gimbal_rudder_angle + 1,
            self.gimbal_rudder_angle < self.target_gimbal_rudder_angle)

        if not self.pause:
            # Calculate forward force in N based on the angle between the sail and the wind
            self.sail_alpha.set(
                sp.abs(self.global_sail_angle - sp.world.wind.wind_direction) %
                360)
            self.sail_alpha.set(
                sp.abs(180 - self.sail_alpha) % 360, self.sail_alpha > 90)
            self.perpendicular_sail_force.set(sp.world.wind.wind_scalar *
                                              sp.sin(self.sail_alpha))
            self.forward_sail_force.set(self.perpendicular_sail_force *
                                        sp.sin(self.local_sail_angle))
            self.forward_sail_force.set(sp.abs(self.forward_sail_force))

            # Sailing against wind
            min_threshold = (self.global_sail_angle - 180) % 360
            max_threshold = (self.global_sail_angle + 180) % 360
            self.forward_sail_force.set(
                0,
                is_sailing_against_wind(min_threshold, max_threshold,
                                        self.local_sail_angle,
                                        self.global_sail_angle,
                                        sp.world.wind.wind_direction))

            # Newton's second law
            self.drag.set(self.forward_velocity * 0.05)
            self.acceleration.set(self.forward_sail_force / self.mass -
                                  self.drag)
            self.forward_velocity.set(
                sp.limit(
                    self.forward_velocity +
                    self.acceleration * sp.world.period, 8))

            # Splitting forward velocity vector into vertical and horizontal components
            self.vertical_velocity.set(
                sp.sin(self.sailboat_rotation) * self.forward_velocity)
            self.horizontal_velocity.set(
                sp.cos(self.sailboat_rotation) * self.forward_velocity)

            self.position_x.set(self.position_x +
                                self.horizontal_velocity * 0.001)
            self.position_y.set(self.position_y +
                                self.vertical_velocity * 0.001)
            self.rotation_speed.set(0.001 * self.gimbal_rudder_angle *
                                    self.forward_velocity)
            self.sailboat_rotation.set(
                (self.sailboat_rotation - self.rotation_speed) % 360)
Exemple #5
0
    def sweep(self):
        self.part('gimbal angle blue/yellow')
        self.blueYellowRoughAngle.set(
            sp.limit(
                self.blueYellowRoughAngle + self.blueYellowDelta *
                self.thrusterTiltSpeed * sp.world.period,
                self.thrusterMaxAngle))
        self.blueYellowAngle.set(sp.snap(self.blueYellowRoughAngle, 0, 3))

        self.part('thruster angle green/red')
        self.greenRedRoughAngle.set(
            sp.limit(
                self.greenRedRoughAngle +
                self.greenRedDelta * self.thrusterTiltSpeed * sp.world.period,
                self.thrusterMaxAngle))
        self.greenRedAngle.set(sp.snap(self.greenRedRoughAngle, 0, 3))

        self.part('fuel throttle')
        self.throttlePercent.set(
            sp.limit(
                self.throttlePercent +
                self.throttleDelta * self.throttleSpeed * sp.world.period, 0,
                100))
        self.thrust.set(self.throttlePercent * self.thrusterMaxForce / 100)

        self.part('linear movement')

        thrusterForceVec = np.array((0, 0, self.thrust()))

        if cm.useQuaternions:
            thrusterRotQuat = sp.quatMul(
                sp.quatFromAxAng(np.array((1, 0, 0)), self.blueYellowAngle),
                sp.quatFromAxAng(np.array((0, 1, 0)), -self.greenRedAngle))
            shipForceVec = sp.quatVecRot(thrusterRotQuat, thrusterForceVec)
        else:
            # Local coord sys, so "forward" order
            thrusterRotMat = tf.getRotXMat(
                self.blueYellowAngle) @ tf.getRotYMat(-self.greenRedAngle)
            shipForceVec = thrusterRotMat @ thrusterForceVec

        self.forwardThrust.set(shipForceVec[2])
        self.blueYellowThrust.set(shipForceVec[1])
        self.greenRedThrust.set(shipForceVec[0])

        if cm.useQuaternions:
            worldForceVec = sp.quatVecRot(self._shipRotQuat, shipForceVec)
        else:
            worldForceVec = self._shipRotMat @ shipForceVec

        self.thrustX.set(worldForceVec[0])
        self.thrustY.set(worldForceVec[1])
        self.thrustZ.set(worldForceVec[2])

        earthGravVec = cm.getGravVec(
            self.shipMass, cm.earthMass, cm.earthDiam,
            sp.tEva((self.positionX, self.positionY, self.positionZ)))
        self.earthGravX.set(earthGravVec[0])
        self.earthGravY.set(earthGravVec[1])
        self.earthGravZ.set(earthGravVec[2])

        moonGravVec = cm.getGravVec(
            self.shipMass, cm.moonMass, cm.moonDiam,
            sp.tSub(sp.tEva((self.positionX, self.positionY, self.positionZ)),
                    (0, 0, cm.earthMoonDist)))
        self.moonGravX.set(moonGravVec[0])
        self.moonGravY.set(moonGravVec[1])
        self.moonGravZ.set(moonGravVec[2])

        self.totalForceX.set(self.thrustX + self.earthGravX + self.moonGravX)
        self.totalForceY.set(self.thrustY + self.earthGravY + self.moonGravY)
        self.totalForceZ.set(self.thrustZ + self.earthGravZ + self.moonGravZ)

        self.linAccelX.set(self.totalForceX / self.shipMass)
        self.linAccelY.set(self.totalForceY / self.shipMass)
        self.linAccelZ.set(self.totalForceZ / self.shipMass)

        self.linVelocX.set(self.linVelocX + self.linAccelX * sp.world.period)
        self.linVelocY.set(self.linVelocY + self.linAccelY * sp.world.period)
        self.linVelocZ.set(self.linVelocZ + self.linAccelZ * sp.world.period)

        self.positionX.set(self.positionX + self.linVelocX * sp.world.period)
        self.positionY.set(self.positionY + self.linVelocY * sp.world.period)
        self.positionZ.set(self.positionZ + self.linVelocZ * sp.world.period)

        self.part('angular movement')

        rSq = self.effectiveRadius * self.effectiveRadius
        hSq = self.effectiveHeight * self.effectiveHeight

        # Source: https://en.wikipedia.org/wiki/List_of_moments_of_inertia#List_of_3D_inertia_tensors
        shipInertMat = self.shipMass() / 12 * np.array(
            (((3 * rSq + hSq) / 12, 0, 0), (0, (3 * rSq + hSq) / 12, 0),
             (0, 0, rSq / 6)))
        invInertMat = np.linalg.inv(
            self._shipRotMat @ shipInertMat @ self._shipRotMat.T)

        self.blueYellowTorque.set(self.blueYellowThrust *
                                  self.effectiveHeight / 2)
        self.greenRedTorque.set(-self.greenRedThrust * self.effectiveHeight /
                                2)
        shipTorqueVec = np.array(
            (self.blueYellowTorque(), self.greenRedTorque(), 0))

        if cm.useQuaternions:
            rawTorqueVec = sp.quatVecRot(self._shipRotQuat, shipTorqueVec)
        else:
            rawTorqueVec = self._shipRotMat @ shipTorqueVec
        self.torqueX.set(rawTorqueVec[0])
        self.torqueY.set(rawTorqueVec[1])
        self.torqueZ.set(rawTorqueVec[2])
        torqueVec = np.array((self.torqueX(), self.torqueY(), self.torqueZ()))

        rawAngAccelVec = sp.degreesPerRadian * invInertMat @ torqueVec

        self.angAccelX.set(rawAngAccelVec[0])
        self.angAccelY.set(rawAngAccelVec[1])
        self.angAccelZ.set(rawAngAccelVec[2])

        self.angVelocX.set(self.angVelocX + self.angAccelX * sp.world.period)
        self.angVelocY.set(self.angVelocY + self.angAccelY * sp.world.period)
        self.angVelocZ.set(self.angVelocZ + self.angAccelZ * sp.world.period)
        angVelocVec = sp.radiansPerDegree * np.array(
            (self.angVelocX(), self.angVelocY(), self.angVelocZ()))

        # Actual integration over one timestep
        # Source: Friendly F# and C++ (fun with game physics), by Dr Giuseppe Maggiore and Dino Dini, May 22, 2014
        if cm.useQuaternions:
            # Quaternions are much more numerically stable
            self._shipRotQuat = sp.normized(
                self._shipRotQuat +
                sp.quatMul(sp.quatFromVec(angVelocVec), self._shipRotQuat) /
                2 * sp.world.period())

            self.shipRotQuat0.set(self._shipRotQuat[0])
            self.shipRotQuat1.set(self._shipRotQuat[1])
            self.shipRotQuat2.set(self._shipRotQuat[2])
            self.shipRotQuat3.set(self._shipRotQuat[3])

            self._shipRotQuat[0] = self.shipRotQuat0()
            self._shipRotQuat[1] = self.shipRotQuat1()
            self._shipRotQuat[2] = self.shipRotQuat2()
            self._shipRotQuat[3] = self.shipRotQuat3()

            self._shipRotMat = sp.rotMatFromQuat(self._shipRotQuat)
        else:
            # N.B. The rotation matrix cannot be found by applying angular velocity in x, y and z direction successively
            self._shipRotMat = self._shipRotMat + np.cross(
                angVelocVec, self._shipRotMat, axisb=0,
                axisc=0) * sp.world.period()
            if cm.useGramSchmidt:
                tf.modifiedGramSchmidt(self._shipRotMat)

        rawAttitudeVec = tf.getXyzAngles(self._shipRotMat)
        self.attitudeX.set(rawAttitudeVec[0])
        self.attitudeY.set(rawAttitudeVec[1])
        self.attitudeZ.set(rawAttitudeVec[2])

        self.part('sweep time measurement')
        self.sweepMin.set(sp.world.period, sp.world.period < self.sweepMin)
        self.sweepMax.set(sp.world.period, sp.world.period > self.sweepMax)
        self.sweepWatch.reset(self.sweepWatch > 2)
        self.sweepMin.set(1000, not self.sweepWatch)
Exemple #6
0
    def sweep(self):
        self.part('torso')
        self.torAngDif.set(self.torAngSet - self.torAng)
        self.torRound.mark(sp.abs(self.torAngDif) < self.torMarg)
        self.torSpeedSet.set(
            sp.limit(self.torSpeedFac * self.torAngDif, self.torSpeedMax))
        self.torSpeed.set((self.torAng - self.torAngOld) / sp.world.period)
        self.torSpeedDif.set(self.torSpeedSet - self.torSpeed)
        self.torVolt.set(
            sp.limit(self.torVoltFac * self.torSpeedDif, self.torVoltMax))
        self.torEnab.mark(self.go)
        self.torAngOld.set(self.torAng)

        self.part('upper arm')
        self.uppAngDif.set(self.uppAngSet - self.uppAng)
        self.uppRound.mark(sp.abs(self.uppAngDif) < self.uppMarg)
        self.uppSpeedSet.set(
            sp.limit(self.uppSpeedFac * self.uppAngDif, self.uppSpeedMax))
        self.uppSpeed.set((self.uppAng - self.uppAngOld) / sp.world.period)
        self.uppSpeedDif.set(self.uppSpeedSet - self.uppSpeed)
        self.uppVolt.set(
            sp.limit(self.uppVoltFac * self.uppSpeedDif, self.uppVoltMax))
        self.uppEnab.mark(self.go and self.torRound)
        self.uppAngOld.set(self.uppAng)

        self.part('fore arm')
        self.forAngDif.set(self.forAngSet - self.forAng)
        self.forRound.mark(sp.abs(self.forAngDif) < self.forMarg)
        self.forSpeedSet.set(
            sp.limit(self.forSpeedFac * self.forAngDif, self.forSpeedMax))
        self.forSpeed.set((self.forAng - self.forAngOld) / sp.world.period)
        self.forSpeedDif.set(self.forSpeedSet - self.forSpeed)
        self.forVolt.set(
            sp.limit(self.forVoltFac * self.forSpeedDif, self.forVoltMax))
        self.forEnab.mark(self.go and self.torRound and self.uppRound)
        self.forAngOld.set(self.forAng)

        self.part('wrist')
        self.wriAngDif.set(self.wriAngSet - self.wriAng)
        self.wriRound.mark(sp.abs(self.wriAngDif) < self.wriMarg)
        self.wriSpeedSet.set(
            sp.limit(self.wriSpeedFac * self.wriAngDif, self.wriSpeedMax))
        self.wriSpeed.set((self.wriAng - self.wriAngOld) / sp.world.period)
        self.wriSpeedDif.set(self.wriSpeedSet - self.wriSpeed)
        self.wriVolt.set(
            sp.limit(self.wriVoltFac * self.wriSpeedDif, self.wriVoltMax))
        self.wriEnab.mark(self.go and self.torRound and self.uppRound
                          and self.forRound)
        self.wriAngOld.set(self.wriAng)

        self.part('hand and fingers')
        self.hanEnab.mark(self.go and self.torRound and self.uppRound
                          and self.forRound and self.wriRound)
        self.finTimer.reset(not self.hanEnab)
        self.finEnab.mark(self.finTimer > self.finDelay)
        self.finLatch.latch(self.finTimer > 0.01)

        self.part('sweep time measurement')
        self.sweepMin.set(sp.world.period, sp.world.period < self.sweepMin)
        self.sweepMax.set(sp.world.period, sp.world.period > self.sweepMax)
        self.sweepWatch.reset(self.sweepWatch > 2)
        self.sweepMin.set(1000, not self.sweepWatch)
        self.sweepMax.set(0, not self.sweepWatch)
Exemple #7
0
    def sweep(self):
        self.part('Edge triggering of buttons')
        self.powerEdge.trigger(self.powerButton)
        self.power.mark(not self.power, not self.childLock and self.powerEdge)

        self.childLockChangeTimer.reset(not (
            self.power and self.childLockButton))
        self.childLockEdge.trigger(self.childLockChangeTimer > 5)
        self.childLock.mark(not self.childLock, self.childLockEdge)
        self.unlocked.mark(self.power and not self.childLock)

        self.plateSelectEdge.trigger(self.plateSelectButton)
        self.plateSelectDelta.set(1, self.unlocked and self.plateSelectEdge, 0)
        self.plateSelectNr.set(
            (self.plateSelectNr + self.plateSelectDelta) % 4, self.power, 0)

        self.upEdge.trigger(self.upButton)
        self.downEdge.trigger(self.downButton)

        self.part('Cooking alarm')
        self.alarmSelectEdge.trigger(self.power and self.alarmSelectButton)
        self.alarmSelected.mark(not self.alarmSelected, self.unlocked
                                and self.alarmSelectEdge)

        self.alarmChangeTimer.reset(not (
            self.alarmSelected and (self.upButton or self.downButton)))
        self.alarmChangeStep.set(1, self.alarmChangeTimer > 0, 0)
        self.alarmChangeStep.set(10, self.alarmChangeTimer > 10)
        self.alarmChangeStep.set(100, self.alarmChangeTimer > 20)

        self.alarmDelta.set(-self.alarmChangeStep, self.downButton,
                            self.alarmChangeStep)
        self.alarmTime.set(
            0, self.power and self.upButton and self.downButton,
            sp.limit(self.alarmTime + self.alarmDelta * sp.world.period, 0,
                     9999))

        self.alarmOn.latch(self.alarmChangeTimer > 0)
        self.alarmTimer.reset(not self.alarmOn or self.alarmChangeTimer > 0)
        self.alarmEdge.trigger(
            self.alarmTimer > self.alarmTime
            or (self.childLock and
                (self.powerButton or self.plateSelectButton
                 or self.alarmSelectButton or self.plateSelectButton
                 or self.upButton or self.downButton)))
        self.alarmOn.unlatch(self.alarmEdge or self.alarmTime == 0)

        self.alarmTimeLeft.set(max((self.alarmTime - self.alarmTimer), 0))

        self.part('Cooking plates')
        self.plate0Selected.mark(self.plateSelectNr == 0)
        self.plate1Selected.mark(self.plateSelectNr == 1)
        self.plate2Selected.mark(self.plateSelectNr == 2)
        self.plate3Selected.mark(self.plateSelectNr == 3)

        self.tempChange.mark(self.unlocked and not self.alarmSelected
                             and (self.upEdge or self.downEdge))
        self.tempDelta.set(-1, not self.alarmSelected and self.downButton, 1)

        self.plate0Temp.set(sp.limit(self.plate0Temp + self.tempDelta, 0, 9),
                            self.tempChange and self.plate0Selected)
        self.plate1Temp.set(sp.limit(self.plate1Temp + self.tempDelta, 0, 9),
                            self.tempChange and self.plate1Selected)
        self.plate2Temp.set(sp.limit(self.plate2Temp + self.tempDelta, 0, 9),
                            self.tempChange and self.plate2Selected)
        self.plate3Temp.set(sp.limit(self.plate3Temp + self.tempDelta, 0, 9),
                            self.tempChange and self.plate3Selected)

        self.part('Buzzer tone generation and pitch bend')
        self.buzzerOn.latch(self.alarmEdge)
        self.buzzerOnTimer.reset(not self.buzzerOn)
        self.buzzerOn.unlatch(self.buzzerOnTimer > self.buzzerOnTime)

        self.buzzerPitchTimer.reset(self.buzzerPitchTimer > 3)
        self.buzzerFreq.set(self.buzzerBaseFreq * (1 + self.buzzerPitchTimer))
        self.buzzerWaveTimer.reset(
            self.buzzerWaveTimer > 0.5 / self.buzzerFreq)
        self.buzzerEdge.trigger(self.buzzerWaveTimer == 0)
        self.buzzer.mark(not self.buzzer, self.buzzerOn and self.buzzerEdge)

        self.part('Numerical display')
        self.digitIndex.set((self.digitIndex + 1) % 4)

        self.plateDigitValue.set(self.plate0Temp, self.digitIndex == 3)
        self.plateDigitValue.set(self.plate1Temp, self.digitIndex == 2)
        self.plateDigitValue.set(self.plate2Temp, self.digitIndex == 1)
        self.plateDigitValue.set(self.plate3Temp, self.digitIndex == 0)

        self.alarmDigitValue.set(sp.digit(self.alarmTimeLeft, self.digitIndex))
        self.digitValue.set(self.alarmDigitValue, self.alarmSelected,
                            self.plateDigitValue)

        self.digitDot.mark(self.plate0Selected, self.digitIndex == 3)
        self.digitDot.mark(self.plate1Selected, self.digitIndex == 2)
        self.digitDot.mark(self.plate2Selected, self.digitIndex == 1)
        self.digitDot.mark(self.plate3Selected, self.digitIndex == 0)
        self.digitDot.mark(True, self.childLock)
        self.digitDot.mark(False, self.alarmSelected)

        self.part('Sweep time measurement')
        self.sweepMin.set(sp.world.period, sp.world.period < self.sweepMin)
        self.sweepMax.set(sp.world.period, sp.world.period > self.sweepMax)
        self.sweepWatch.reset(self.sweepWatch > 2)
        self.sweepMin.set(1000, not self.sweepWatch)
        self.sweepMax.set(0, not self.sweepWatch)