![]() |
HitLib 1.3.0
VEX V5 LED animation library for PROS
|
Every animation is available on both hitlib::LedStrand and hitlib::LedGroup. Group calls fan out to every strand in the group simultaneously.
All calls are thread-safe and take effect on the next refresh tick.
Generates a gradient between two colors and scrolls it continuously. invert reverses the scroll direction. seamless (default true) loops the gradient back to the first color instead of cutting straight from the second color back to the first at the wrap.
Full HSV rainbow scrolled across the strip.
Blinks the whole strip: every LED lights at once for onMs, then the whole strip shows bgColor for offMs, and the cycle repeats.
On and off times are independent, so blink rate and duty cycle are set separately. 100, 100 is an even 5 Hz blink, while 100, 400 keeps the same brief flash at 2 Hz. Durations are rounded to whole refresh ticks and clamped to a minimum of one tick, so a strand can't be asked to blink faster than its refreshMs interval.
Randomly spawns sparkles from the palette that fade in, hold briefly, then fade out.
repeating applies to both travel styles: with true the pattern tiles across the whole strip, with false a single copy travels the strip on its own.
A second animation buffer, independent of the base animation. Shown directly in splice mask regions that set useOverlay.
The overlay carries the same vocabulary as the base animations, minus bounce: it is a single scrolling buffer, and bouncing needs a wider master pattern to slide a window over. Use the base animation when you want that.
Fills the strip from one end in proportion to a 0-255 level, and dims the LED at the edge of the fill part-way so a short strand still shows a smooth ramp rather than one step per pixel.
With gradient, the two colors are laid out across the whole strip, not across the lit part, so a given pixel is always the same color no matter how full the meter is, as a VU-style scale needs; a gradient stretched over the fill would recolor every pixel on every update.
Three things can move a meter, and they are mutually exclusive - whichever was set up last owns it, so a strip handed to a song never has a stale sensor fighting it for the same pixels:
| Set up with | Moved by | |
|---|---|---|
| By hand | levelFill() | your code calling setLevel() |
| From a value | levelSource() | the strand, once per tick |
| From a song | musicSync() | the baked envelope, against the wall clock |
levelSource() hands the strand a reader and the range it maps onto the strip. From then on the bar tracks the value with no code in your control loop at all:
The two bounds are in whatever units the reader already speaks - degrees, percent, millimetres, RPM - so nothing has to be scaled into 0-255 first:
Set it up once - in initialize(), or in a mode's onActivate so the meter follows that mode - and call clearLevelSource() or setLevel() to take it back by hand.
A few details worth knowing:
Pattern Studio has this as its Fill animation: pick what the bar follows from a list of the things a V5 robot actually has - battery capacity, motor heat, position, velocity or efficiency, a rotation sensor, an IMU heading, a distance sensor, a potentiometer - and the exported header carries the reader already written, including the #include it needs. Anything not on the list exports as a LevelFn hook to assign from your own code, and the export's banner spells out the assignment.
The same meter, driven by a song instead of by hand.
The V5 can neither hear audio nor decode a song, so it is resolved on the desktop. Pattern Studio reads an audio file - MP3, M4A, FLAC, OGG, WAV - or a MIDI, measures its loudness in three frequency bands, and exports each band a strand uses as a table of one byte per frame. On the robot, playback is an array lookup and a lerp per tick, no matter how long the song is.
Playback is anchored to the wall clock at the moment musicSync() runs, so call it when the music starts, typically from a mode's onActivate. Samples are interpolated between frames, so the fill stays smooth even when the envelope's frame rate is coarser than refreshMs.
Each strand picks the part of the song it follows, so a robot with two strips can run them off one track without them moving together:
| Band | What it follows |
|---|---|
| Bass | Kick and bass. Pumps on the beat, and what most strips want. |
| Mid | Vocals, snare, guitars. Follows the body of the arrangement. |
| Treble | Hats and cymbals. Sparse and sparkly. |
| Full mix | Everything at once. Steadiest, least rhythmic. |
Only the bands a design actually uses are exported, so following the bass alone costs one table rather than four.
A percentage gain applied to every sample: above 100 the quiet passages reach further up the strip (and loud ones clip at full), below 100 only the peaks register. It is the one knob worth retuning on the robot, so it has its own setter and needs no re-export:
Everything about how the song drives the strip - which band, how hard it punches, how fast it falls away - is decided in Pattern Studio and baked into the table. A three-minute song at the default 25 ms frame is about 8 KB of flash per band.
Overrides part of the strip, either as equal alternating bins sharing the overlay buffer (spliceMask) or as arbitrarily placed regions that each animate independently (spliceMaskCustom). The two forms are mutually exclusive whichever was called most recently is what's active.
A GAUGE region is the odd one out: it animates from a reading rather than from a clock. Each one polls its own value every tick and colors itself off its own scale, so a single strip can carry several independent meters – which the strand-wide [level meter]( ef LedStrand::levelFill) cannot do, there being one of those per strand.
The scale is a list of stops given in the reading's own units, so it says what it means. Below the first stop and above the last, the gauge holds that stop's color, so a scale never has to cover a range you don't care about.
style picks what the region does with its level: HEAT (the default) colors every pixel it owns at once, and BAR fills the region proportionally instead, like a miniature levelFill(). blend picks what happens between two stops: LERP slides between their colors, and STEP holds each one until the next is actually reached – the honest choice when the stops are thresholds something crosses rather than points on a ramp.
Leave read as nullptr and the region is hand-driven instead, through setRegionLevel() – setLevel()'s counterpart for one region.
The case gauges exist for: a strip under the drivebase, split into one segment per motor, each colored by how hot its own motor is. motorHeatGauge() is a gauge region arriving pre-loaded with the V5's own derating schedule, so the colors mean something specific rather than being a pretty ramp – green cold, yellow nearing the first cut, then orange, red and deep red for the 50%, 25% and 12.5% current limits, and magenta at 70 °C where the motor shuts down.
The V5 reports motor temperature in coarse steps rather than as a continuous reading, which is why the preset ships with smoothing at 80: without it a segment jumps from one stop color straight to the next instead of creeping between them.
Pattern Studio builds the whole thing without any of this being typed: set one region up as a Gauge on Motor Temperature (which brings the six stops with it), then press Divide to lay out however many equal segments the strip holds and change each one's port.