TorqueSensorModule

TorqueSensorModule is the signal-conditioning chain for a joint torque sensor.
3.30–3.34

TorqueSensorModule is the signal-conditioning chain for a joint torque sensor. It converts raw sensor counts to engineering units, corrects the sensor’s non-linearity, removes its dominant noise frequency, and then splits the result into two signals: a slow one that is the load the joint is carrying, and a fast one that is the structure vibrating around it.

That split is the point. The two need different treatment — the load goes to a force controller, the vibration drives an active-damping correction that this block also produces.

flowchart LR
    i1(["sensorTorqueActual — raw sensor counts"]) --> B["TorqueSensorModule"]
    i2(["sensorTorqueReference — commanded torque"]) --> B
    i3(["disable"]) --> B
    B --> o1(["staticTorqueActual — the load"])
    B --> o2(["dynamicTorqueActual — the vibration"])
    B --> o3(["disturbanceCorrection — damping output"])
    B --> o4(["isEnabled"])

The chain is: counts → engineering units → non-linearity correction → notch filter → split. The static branch low-passes the result. The dynamic branch subtracts sensorTorqueReference first, then high-passes it, so it measures deviation from what was commanded. That deviation drives a controller whose smoothed output is disturbanceCorrection.

Almost everything is configured below this block, in seven sub-trees. This page’s own eight paths are the wiring; the tuning is in the sub-trees.

disturbanceCorrection reads zero until you configure the controller sub-tree. Its gains all default to zero. The two torque outputs work regardless.

Signals

Inputs

Path Unit Range Description
sensorTorqueActual counts unbounded The raw torque sensor reading, before any conversion.
sensorTorqueReference N·m unbounded The torque being commanded. It is subtracted in the dynamic branch only — the static output is the absolute load and does not use it. Leave it at zero if you only want the load.
disable - - True forces disturbanceCorrection to zero. The two torque outputs keep working. Use it for a runtime override; use enable for the configured intent.

Outputs

Path Unit Description
staticTorqueActual N·m The load the joint is carrying — the slow content of the conditioned signal. Published whether or not the block is enabled, so you can commission the whole chain with the correction disconnected.
dynamicTorqueActual N·m The vibration: the fast content of the conditioned signal, measured relative to sensorTorqueReference. Also published while disabled.
disturbanceCorrection N·m The damping correction derived from the vibration. The only output gated by enable. Zero until the controller sub-tree is configured.
isEnabled - True when enable is true and disable is false. It does not mean a correction is being produced.

Parameters

Path Unit Default Range Effect
enable - true - False forces disturbanceCorrection to zero and leaves both torque outputs reporting.

One parameter at this level. The configuration lives in seven sub-trees:

Sub-tree What it does Where to read
transducer Counts to newton-metres, and the sensor tare transducer.md
polynomialCorrection Corrects the sensor’s non-linearity, up to 5th order polynomial.md
IIRFilter Notch filter for the sensor’s dominant noise frequency. Ships as a pass-through — it does nothing until you supply coefficients. Note the capitalised path name iir-filter.md
staticTorqueFilter Low-pass that extracts the load. Its cut-off sets the split frequency low-pass-1.md
dynamicTorqueFilter High-pass that extracts the vibration. Its cut-off is the other half of the split high-pass-2.md
controller The damping controller. Its gains default to zero pid.md
vibrationCorrectionFilter Smooths the correction. Its cut-off is forced to 1 Hz at every start and cannot be configured — see Limits and errors low-pass-1.md

enable is persistent and survives a restart, as is everything in the sub-trees.

Setup

  1. Set enable false. Both torque outputs still report, so the whole conditioning chain can be commissioned with nothing reaching the machine.

  2. Configure transducer with your sensor’s counts-per-newton-metre. Apply a known load and confirm staticTorqueActual reads the right value in N·m.

  3. Tare the sensor with no load applied. This needs an application call — there is no parameter for it. If your application does not offer one, work around it with an offset in the transducer sub-tree.

  4. If the sensor is non-linear, configure polynomialCorrection. Check it against known loads across the range, not at one point.

  5. Trace staticTorqueActual with the joint held still and look for a dominant noise frequency. If there is one, design a notch for it and write the coefficients into the IIRFilter sub-tree. Design them for your task rate — those coefficients are in samples, not seconds.

  6. Set the split: staticTorqueFilter’s cut-off decides what counts as load, and dynamicTorqueFilter’s decides what counts as vibration. Start with both around the frequency where your structure rings.

  7. Feed sensorTorqueReference from your torque command and confirm dynamicTorqueActual sits near zero while the joint tracks that command.

  8. Configure the controller sub-tree. Set its output limits and integrator limits before any gain — its integrator bounds default to ±0.1, which binds almost at once.

    Step 8 is what makes the block act on the machine. Until now every output has been observation only. Set enable true last, and raise the controller’s gains from zero with the joint clear.

Tuning

  1. Get the units right before anything else. If staticTorqueActual is not in real newton-metres, every downstream number is wrong.
  2. Tune the notch against a measurement, not a guess. Trace the raw signal at rest, find the peak, and design for that frequency.
  3. Set the split frequency from the structure, not from feel. Below your structure’s ringing frequency is load; above it is vibration. If the two overlap, this block cannot separate them.
  4. Check the split works: apply a steady load and confirm it appears on staticTorqueActual and not on dynamicTorqueActual. Then excite the structure and confirm the reverse.
  5. Tune the controller last, and as a controller — set its output limits and integrator limits first, then raise the proportional gain until the ringing is damped, then back off.
  6. Watch disturbanceCorrection on a trace while you do it. If it saturates or sits pinned, the controller’s integrator limits are too tight.
  7. Re-check the notch coefficients after any task-rate change. They are defined in samples, so the same coefficients are a different filter at a different rate.

A noisy torque with a step and 25 Hz vibration, split into a static outputthat follows the 8 Nm load and a dynamic output that carries the vibration andsits near zero otherwise.

Read the split off the two curves: the load appears on one and the ringing on the other.

Symptom Cause Action
disturbanceCorrection reads zero with isEnabled true Expected: the controller sub-tree’s gains all default to zero Configure the controller, per Setup step 8
disturbanceCorrection saturates or sits pinned The controller’s integrator limits default to ±0.1 Raise them in the controller sub-tree before raising ki
A correction appears at full value the moment the block is enabled The controller keeps integrating while disabled, so it re-enables already wound Enable with the joint at rest, or reset the controller first
Both torque outputs read zero The notch filter was disabled in its own sub-tree, which outputs zero rather than passing through Re-enable it, or leave it as the pass-through it ships as
The notch does nothing Expected: it ships as a pass-through with no coefficients Design a notch and write num and den into the IIRFilter sub-tree
The notch behaves nothing like the design Its coefficients were designed for a different sample rate Redesign at the controller’s actual task period
staticTorqueActual is in the wrong units The transducer sub-tree is not configured for your sensor Work Setup step 2
staticTorqueActual has an offset with no load The sensor is not tared Tare it — this needs an application call, not a parameter
staticTorqueActual is right at one load and wrong at another The sensor is non-linear and polynomialCorrection is not configured Work Setup step 4 with several known loads
The load appears on dynamicTorqueActual The split frequency is too low Raise dynamicTorqueFilter’s cut-off
Vibration appears on staticTorqueActual The split frequency is too high Lower staticTorqueFilter’s cut-off
dynamicTorqueActual is large even when the joint is tracking well sensorTorqueReference is not linked, so the whole load reads as deviation Link the commanded torque
Changing vibrationCorrectionFilter’s cut-off had no effect Expected: it is forced to 1 Hz at every start and your value is overwritten It cannot be changed from configuration
A non-numeric value appeared and will not clear There is no reset in this block, and the filters hold it Restart the controller
You need this on several joints Not possible — one sensor per instance Use one instance per joint

A starting point for a joint whose structure rings near 25 Hz on a 1 ms task, with the correction path not yet active:

enable = false
transducer:          configure counts per Nm for your sensor
polynomialCorrection: leave at its pass-through default at first
IIRFilter:           leave as pass-through until a noise peak is measured
staticTorqueFilter:  omega = 63.0     (10 Hz)
dynamicTorqueFilter: omega = 157.0    (25 Hz), beta = 1.0
controller:          kp = 0, ki = 0, kd = 0, output limits set first

Then work Setup step 8. This is a starting point, not a final tuning.

Limits and errors

Limit Set by What happens Reported
vibrationCorrectionFilter cut-off Fixed in code Forced to 1 Hz every time the controller initialises, overriding whatever your configuration sets. It is the one setting in the sub-trees you cannot change Not reported; read the sub-tree value back after a restart
controller gains Nothing All default to zero, so disturbanceCorrection is zero until configured. Its integrator bounds default to ±0.1 Not reported
Notch coefficients Nothing Not checked for stability. A badly designed set can make the whole chain grow without bound — see the filter’s own page Not reported
Sensor tare Not exposed Taring is available only through an application call, not from the parameter tree Not reported
staticTorqueActual, dynamicTorqueActual Nothing Unbounded, and published whether or not the block is enabled Not reported
disturbanceCorrection The controller sub-tree’s own output limits Bounded only by what you set there. Zero while disabled Not reported
Chain state Nothing There is no reset input. The filters and the controller hold their state across a stop, and a non-numeric value can only be cleared by a restart Not reported
Channel count Fixed One sensor per instance, always Not reported

The block raises no errors or warnings and logs nothing. Every failure above shows as a value on a trace, not as a message.


Verified against motorcortex-control3 3.30.0 (bc348fd).