EmotionFSM
EmotionFSM is effectively the director of the system. By using events posted by the interaction services, it handles transitions to each emotional state and deals with inactivity timeouts. It also handles passive animation and eye motion control, which run when the user is not actively interacting with the PAL.
CuddlingService
CuddlingService handles the cuddling interaction. When other interactions are occurring, the service defers the cuddling interaction until it receives a no-interaction event or it is forced into idle. Note that this deferral queue has a size of one. The service responds to the interaction by updating the animation with an increasing 'cuddle meter,' which is controlled by 'ActiveCuddlingLevel' and DM_Display (the animation generator).
CuddlingService employs an event checker to sense the cuddling interaction. When the state of the cuddling input pin changes in response to button-released and button-pressed triggers, the event checker responds by posting cuddling-detected and cuddling-stopped events back to CuddlingService.
FeedingService
FeedingService handles the feeding interaction. When other interactions are occurring, the service defers the feeding interaction until it receives a no-interaction event or it is forced into idle. Note that this deferral queue has a size of one. The service responds to the interaction by posting an animation event to LEDFSM and a movement command to EyeServoService.
FeedingService employs an event check to sense the feeding interaction. When the state of the feeding input pin changes in response to an object breaking the beam of IR light to the phototransistor, the event checker responds by posting a food detected event back to FeedingService.
PettingService
PettingService handles the petting interaction. When other interactions are occurring, the service ignores petting inputs. The service responds to the interaction by updating the animation and vibration motor strength based on an increasing 'petting meter' and the location of the petting hand on the petting surface. The service responds to movement across the petting surface by moving the eyes to follow the petting hand. The interaction times out when the petting hand is in static contact with the petting surface.
PettingService employs event checkers for both the petting force and petting location sensing mechanisms. Each event checker responds to changes in the analog voltage reading at the corresponding input pin. The petting force event checker posts volume-up and volume-down events to VolumeService depending on the direction of the change at the corresponding input pin. The petting location event checker operates similarly and posts petting and petting-update events back to the PettingService. However, additional logic is incorporated in the event checker to ensure that the petting location is not updated on the rising and falling edges of the input waveform, but rather on its plateaus.
DM_Display
DM_Display is the animation framework designed to work with the LED matrix. Designed to be flexible and easy to use, the framework relies on predefined shapes (circles, hearts, semicircles...) that can be placed in an x-y grid representing the display. By stacking shapes we can create images, and by varying the coordinates over time (via different frames), we can create motion.
Animations are hard-coded by programmer-defined generator functions which are called when new animations are requested. The framework uses this function to pre-load every frame of the animation and stores this in a buffer that LEDFSM draws off of to update the display. The framework is also capable of overriding any active animation via 'override animations.' An example of this is blinking, which is pseudorandomly triggered and overrides the active animation with an animation of eyes closing.
Animation test: Overriding the 'love' animation with blinking
LEDFSM
LEDFSM handles updating the 32x16 LED matrix by relying on DM_Display functions and its animation buffer. This includes transitioning between each frame of the animation and handling requests to change the active animation. While it is updating each row of the display for a single frame, it will defer animation changes to avoid screen-tearing.
EyeServoService
EyeServoService handles the PWM-controlled, servomotor-actuated motion of the LED matrix carriage. Similar to the animation system, this framework allows the programmer to easily create a set of predefined motions and to call on them when required. The service is capable of running these motions cyclically (e.g., breathing) or as one-shots (e.g., eating).
The framework uses 'waypoints' stored in an array and an interpolation density parameter n to create acceleration and deceleration. When a motion path is generated, the framework reads the desired waypoint locations (in degrees) and interpolates between them n times, equally spaced. When combined with a constant step delay, we can control speed by varying the spacing between the waypoints.
Note that this service contains a function that maps the range of valid PWM signals (must be determined through testing) to the range of possible input angles (0-180°).
Motion test: Cyclical motion, shown on the final mechanism used for the eye motion
SoundboardService
SoundboardService is responsible for playing and pausing audio files in response to specific interactions. It responds to petting events sent from PettingService to play a mysterious "purring" sound when the user is actively petting The Void. The service is also set up to play a "zen" sound when zen state is achieved and respond to keyboard inputs to post volume-up and volume-down events to VolumeService.
VibeService
VibeService handles actuation of the vibration motor embedded in the petting surface. Unlike the other motors, this service relies on timer timeout events instead of the PWM module to control its actuation magnitude. The service creates pulses with varying pulse width by changing the timer delay between on/off commands, which directly correlates to the vibration strength of the motor. Thus, this service still relies on PWM principles to operate.
VolumeService
VolumeService handles volume control for the soundboard. It processes volume-up and volume-down commands from SoundboardService and PettingService as a series of pulses to the volume pins on the soundboard. The service equates three pulses to every volume command so as to prevent framework latency and event loss from queue congestion. Note that the deferral queue size has a size of twenty-four to accommodate event preloading upon initialization. The default volume of the soundboard is near its maximum output. In order to set the default volume lower, volume-down events are preloaded in the deferral queue upon initialization and recalled immediately upon execution of the run function. Fifty millisecond timers ensure that each pulse to a soundboard volume pin remains low for long enough to latch.
ServoTimerService
ServoTimerService controls the sixty second servomotor clock. The servomotor angle is controlled by PWM and updates this angle every second (by a known angle corresponding to the ticks on the physical dial). To active the timer, a 'run timer' event must be received. To stop and reset, the 'to-idle' event must be received.
Note that this service also contains a function that maps the range of valid PWM signals (must be determined through testing) to the range of possible input angles (0-180°).