Google Speech Recognition icon Google Speech Recognition Google Speech for ARC: cloud speech recognition with waveform, configurable response scripts and PandoraBot support Try it →
Asked
Smoothing Frequency Detector to Mega servo

Smoothing Frequency Detector To Mega Servo

I’ve got an Arduino Mega 2560 connected to ARC over USB using the ARC Arduino capability, with a single MG996R on ARC servo port D0 (Mega pin 22). The servo is powered from a separate 6V BEC with the grounds tied to the Mega and PC. I’m using the Frequency Detector robot skill with a USB condenser mic pointed at a small piano keyboard app. In the skill, I set Min/Max frequency to 300-1000 Hz and assigned D0 to move between 20-160 degrees. The frequency readout looks reasonable, but the servo chatters hard and occasionally slams to min/max even when the tone is steady.

What I’ve tried: reducing mic gain and moving the mic closer, disabling the skill’s direct servo movement, and instead reading a variable in JavaScript (I set the skill’s variable output to $freqHz) and doing my own smoothing and clamping. Example:

let f = getVar("$freqHz") || 0;
if (f < 300 || f > 1000) return; // ignore out-of-range
avg = (typeof avg === 'number') ? (0.8*avg + 0.2*f) : f;
let pos = Math.max(20, Math.min(160, Math.round(20 + (avg-300)*(140/(1000-300)))));
ServoSpeed("D0", 1);
Servo("D0", pos);
Sleep(100);

This helps, but I still see occasional spikes in the Data Log (sometimes near 0 Hz or big jumps), which translate into a twitch even with clamping. Questions:

  • Does Frequency Detector expose any amplitude/confidence variable I can gate on, or a threshold to ignore low-energy detections?
  • Is there a ControlCommand to programmatically toggle the skill’s Pause so I can hold the last good value during dropouts?
  • Does ServoSpeed() actually apply to the Arduino Mega firmware driver, or do I need a different approach (e.g., incremental stepping in a loop or another ARC skill) to guarantee smooth motion on D0?

What’s the recommended way in ARC to gate/smooth Frequency Detector output for reliable servo motion on an Arduino Mega without these occasional snap-to-min/max twitches?



Related Hardware (view all EZB hardware)
Synthiam ARC enables Arduino Mega 2560 control with 8 ADC, 13 PWM, 21 digital ports and 24 servos; includes firmware, shield and tutorials
USB
Servos 24
Camera
Audio
UART 3
I2C
ADC 8
Digital 21

Related Robot Skills (view all robot skills)
Script by Synthiam
Multi-language ARC Script: build, run and debug Blockly, JavaScript, EZ-Script or Python with Intellisense, run/save/load and Roboscratch support
Control two continuous servos for bidirectional robot movement with speed sliders, configurable ports/stop values, testing and brake/coast options.

ARC Pro

Upgrade to ARC Pro

Stay on the cutting edge of robotics with ARC Pro, guaranteeing that your robot is always ahead of the game.

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#1  

You’re on the right track moving the smoothing into a script. The snap-to-min/max behavior usually means the detector is occasionally outputting a bad read, and the servo is faithfully obeying it.

Short answers

1) Does Frequency Detector expose amplitude/confidence?

Usually no confidence value is exposed for gating unless the skill explicitly documents one. If the skill’s variable output is only frequency, then the safest approach is to build your own validity filter:

  • ignore values outside the expected range
  • reject sudden impossible jumps
  • require several consecutive "good" reads before updating the servo
  • hold the last valid position during dropouts

If the skill has a settings kebab menu on the top right, check whether it exposes extra options like smoothing, sensitivity, or output variables. If not, then scripting is the way to go.

2) Can you programmatically pause the skill?

If the skill supports a ControlCommand, it will be listed in that skill’s kebab menu / cheat sheet or inside the script editor’s command list.

Try this pattern from a script:

controlCommand("Frequency Detector", "SomeCommand");

But the exact command name depends on the skill. If the Frequency Detector manual does not show a pause command, then ARC cannot guess it. In that case, the script should simply ignore bad data and hold the last good servo position instead of pausing the skill.

3) Does ServoSpeed() apply to the Arduino Mega firmware?

For a standard positional servo on the Mega firmware, servo speed control may not behave like a real smoothing filter. The ARC servo command goes to the capability controller, but the hardware servo itself still moves according to the pulse changes. For an MG996R, the smoothness usually comes from:

  • reducing how often you command new positions
  • stepping gradually instead of jumping
  • filtering the input before sending a new position

So yes, a step/hold filter in JavaScript is the right approach.


Instead of sending every detected frequency straight to the servo, use:

  1. range check
  2. spike rejection
  3. low-pass smoothing
  4. rate limiting
  5. hold last valid position on dropout

Here’s a more robust ARC JavaScript example:

// Tuning
var minHz = 300;
var maxHz = 1000;
var minPos = 20;
var maxPos = 160;

var maxJumpHz = 80;     // reject sudden impossible frequency jumps
var alpha = 0.15;       // smoothing factor
var lastHz = getVar("$lastHz") || 0;
var filtHz = getVar("$filtHz") || 0;
var lastPos = getVar("$lastPos") || 90;

// Read frequency
var f = parseFloat(getVar("$freqHz"));
if (isNaN(f)) {
  return;
}

// Reject out-of-range values
if (f < minHz || f > maxHz) {
  print("Ignored out-of-range frequency: " + f);
  return;
}

// Reject spikes
if (lastHz > 0 && Math.abs(f - lastHz) > maxJumpHz) {
  print("Ignored spike: " + f + " Hz");
  return;
}

// Smooth
if (filtHz === 0) {
  filtHz = f;
} else {
  filtHz = (alpha * f) + ((1 - alpha) * filtHz);
}

// Map frequency to servo position
var t = (filtHz - minHz) / (maxHz - minHz);
var pos = Math.round(minPos + t * (maxPos - minPos));

// Clamp
if (pos < minPos) pos = minPos;
if (pos > maxPos) pos = maxPos;

// Rate limit servo movement
var maxStep = 2;
if (pos > lastPos + maxStep) pos = lastPos + maxStep;
if (pos < lastPos - maxStep) pos = lastPos - maxStep;

// Send only if changed enough
if (Math.abs(pos - lastPos) >= 1) {
  Servo.setPosition(d0, pos);
  print("Freq: " + f + " Filtered: " + Math.round(filtHz) + " Pos: " + pos);
}

// Save state
setVar("$lastHz", f);
setVar("$filtHz", filtHz);
setVar("$lastPos", pos);

Why this works better

Your current script smooths the frequency, but one wild spike can still slip through and cause a jump. The extra protections above help by:

  • rejecting 0 Hz / nonsense reads
  • blocking sudden jumps
  • only moving the servo a few degrees per update
  • holding the last stable position

That combination is usually what stops chatter.


A few important ARC notes

  • In ARC JavaScript, use Servo.setPosition(d0, pos), not Servo("D0", pos).
  • Use the constant port d0 without quotes.
  • Use print() for debug output.
  • ARC’s built-in sleep(100) is fine.
  • If your script is running in a loop, keep the loop timing consistent rather than writing too fast.

Best practical tuning tips

Try these values first:

  • alpha = 0.10 to 0.20
  • maxJumpHz = 50 to 100
  • servo update only every 50-100 ms
  • ignore any frequency below 300 or above 1000

Also, if the piano app produces harmonics or octave jumps, the detector may briefly lock onto a harmonic instead of the fundamental. That’s another reason to add spike rejection.


About pausing the skill

If you want, you can inspect the Frequency Detector skill’s settings kebab menu and see whether it exposes a ControlCommand list or a status variable. If it does, I can help you wire it into a script. If not, it’s usually cleaner to just keep your own last-good-value hold in JavaScript.


Best ARC workflow for this

For this kind of project, I’d recommend:

  1. Frequency Detector outputs to a variable like $freqHz
  2. Script reads that variable
  3. Script filters it
  4. Script drives the servo on d0

That gives you the most control and avoids the skill directly commanding the servo on every raw measurement.

You may also want to look at the ARC AI Assistant inside ARC for rewriting this script directly in the editor:
https://synthiam.com/Products/AI-Assistant

If you want, I can help you turn this into a full ARC script loop that continuously reads $freqHz, smooths it, and drives d0 with hysteresis and dropout hold.

I am a customer support AI and still learning. Please verify important answers in our support documentation. For advanced AI features, use the AI Script Agent built into ARC.