Rudder
The rudder angle on a half circle, positive to starboard, with a bar or a needle and a setpoint marker.
On this page
Code
import {
AdviceType,
InstrumentState,
ObcRudderVariant,
Priority,
Rudder,
TickmarkStyle,
type AngleAdvice,
} from "@bosunkit/instruments";
import { useEffect, useState, type CSSProperties, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"The autopilot steering downwind in a quartering sea on a live feed: the commanded angle swings to meet each wave, " +
"the rudder follows it, the caution zone near the stops triggers when the command goes past 25 degrees, and the " +
"helmsman adjusts the setpoint on a second dial while the emergency tiller's sensor starts up.";
/** Hard over on a Hanse 460 is about 38 degrees; past 25 the rudder stalls and the pilot is losing the boat. */
const MAX_ANGLE: number = 40;
const ADVICES: AngleAdvice[] = [
{ minAngle: -8, maxAngle: 8, type: AdviceType.advice, hinted: true },
{ minAngle: 25, maxAngle: 40, type: AdviceType.caution, hinted: true },
{ minAngle: -40, maxAngle: -25, type: AdviceType.caution, hinted: true },
];
const PANEL: CSSProperties = {
display: "flex",
flexWrap: "wrap",
alignItems: "flex-end",
justifyContent: "center",
gap: 24,
width: "100%",
maxWidth: 660,
};
const FIGURE: CSSProperties = { display: "flex", flexDirection: "column", alignItems: "center", gap: 6, margin: 0 };
const CAPTION: CSSProperties = { fontSize: 13, color: "var(--text-dim)", textAlign: "center", maxWidth: 240 };
/** The pilot's commanded angle in degrees at a time in seconds, positive to starboard. */
function commandAt(time: number): number {
const set: number = Math.max(0, Math.sin(time / 9)) ** 4;
return 14 * Math.sin((2 * Math.PI * time) / 8) + 14 * set * Math.sign(Math.sin((2 * Math.PI * time) / 8));
}
export default function Showcase(): ReactElement {
const [second, setSecond]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);
useEffect((): (() => void) => {
const interval: number = window.setInterval((): void => {
setSecond((previous: number): number => previous + 1);
}, 1000);
return (): void => {
window.clearInterval(interval);
};
}, []);
const command: number = Math.round(commandAt(second));
// The hydraulic drive takes about a second to reach the command.
const angle: number = commandAt(second - 1);
// On the helm dial the helmsman moves the setpoint between 5 and 15 degrees to starboard every ten seconds,
// turning the knob for the last two.
const helmSetpoint: number = Math.floor(second / 10) % 2 === 0 ? 5 : 15;
const adjusting: boolean = second % 10 >= 8;
return (
<div style={PANEL}>
<figure style={FIGURE}>
<div style={{ width: 300, height: 170 }}>
<Rudder
angle={angle}
variant={ObcRudderVariant.Bar}
maxAngle={MAX_ANGLE}
setpoint={command}
autoAtSetpoint
autoAtSetpointDeadband={2}
setpointAtZeroDeadband={0.5}
animateSetpoint
advices={ADVICES}
priority={Priority.enhanced}
tickmarkStyle={TickmarkStyle.enhanced}
showLabels
zoomToFitArc
/>
</div>
<figcaption style={CAPTION}>Autopilot: the bar, its command and the zones, zoomed onto the arc</figcaption>
</figure>
<figure style={FIGURE}>
<Rudder
angle={angle}
variant={ObcRudderVariant.Needle}
maxAngle={MAX_ANGLE}
setpoint={helmSetpoint}
newSetpoint={adjusting ? (helmSetpoint === 5 ? 15 : 5) : undefined}
touching={adjusting}
animateSetpoint
advices={ADVICES}
tickmarksInside
showLabels
faceDiameter={150}
/>
<figcaption style={CAPTION}>Helm: the needle and a setpoint being adjusted</figcaption>
</figure>
<figure style={FIGURE}>
<Rudder
angle={0}
maxAngle={MAX_ANGLE}
setpoint={0}
setpointOverride
atSetpoint
state={InstrumentState.loading}
faceDiameter={110}
/>
<figcaption style={CAPTION}>Emergency tiller, sensor starting</figcaption>
</figure>
</div>
);
}
The rudder instrument shows the rudder angle on the lower half of a circle, with zero at the bottom. A positive angle
is to starboard and the scale spans plus and minus maxAngle, 90 degrees by default. The bar variant fills the arc
from zero, the needle variant turns a pointer, and a setpoint marker shows the commanded angle. It ports obc-rudder;
the overview lists the other instruments.
Examples
Rudder
Code
import { Rudder } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string = "The rudder 12 degrees to port, filled from the zero mark at the bottom.";
export default function RudderExample(): ReactElement {
return (
<div style={{ width: 200, height: 200 }}>
<Rudder angle={-12} />
</div>
);
}
Small face
Code
import { Rudder } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string =
"A rudder on a face pinned to 180 pixels, which sizes itself and needs no surrounding box.";
export default function SmallFace(): ReactElement {
return <Rudder angle={-12} faceDiameter={180} />;
}
Feedback and command
Pass the measured rudder angle as the value and the commanded angle as the setpoint. Positive angles describe starboard in this component. Confirm that convention in the equipment adapter; reversing a sensor's sign in a page style would make the numeric and drawn values disagree.
Choose maxAngle from the installed equipment and retain a numeric reading near the dial. A setpoint marker
shows a requested angle, not proof that the rudder moved. Keep actuator mode, feedback loss and command failure
visible in the containing control view.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| angle | number | undefined | 0 | Rudder angle in degrees; positive fills to starboard. |
| variant | ObcRudderVariant | undefined | ObcRudderVariant.Bar | Display variant: filled arc from zero (default) or a rotating needle. |
| maxAngle | number | undefined | 90 | Symmetric ± range around the bottom zero (default 90°). |
| showLabels | boolean | undefined | false | Show numeric angle labels at tickmarks. |
| tickmarksInside | boolean | undefined | false | Whether to render tickmarks inside the ring. |
| state | InstrumentState | undefined | InstrumentState.active | Instrument state: active (default), loading or off. loading and off draw the bar, the needle and the
setpoint marker in the muted frame colors. |
| priority | Priority | undefined | Priority.regular | Color priority: regular (gray palette, default) or enhanced (blue palette) for the bar, the needle and the
setpoint marker. |
| tickmarkStyle | TickmarkStyle | undefined | TickmarkStyle.regular | Tickmark color style. regular (default) draws every tick in the dim tertiary color; enhanced draws ticks in the
brighter primary color and tertiary ticks in the secondary color. |
| advices | AngleAdvice[] | undefined | [] | Caution/alert arcs; triggered state derives from the SETPOINT being in range. |
| zoomToFitArc | boolean | undefined | false | Enlarge the visible arc to fill the container. |
| faceDiameter | number | undefined | – | Outer-ring diameter in CSS pixels. When set, the instrument renders at a fixed intrinsic size derived from the ring, arc shape and label reserve — so instruments sharing the same value have identical ring circumference regardless of label width or arc extent. When unset (default), the instrument fills its container. |
| className | string | undefined | – | Class names added to the instrument's root element. |
| setpoint | number | undefined | – | Target setpoint value. |
| newSetpoint | number | undefined | – | Adjustment preview (2-step interface): while defined, the original setpoint marker dims and a focus-state marker renders at this value. |
| atSetpoint | boolean | undefined | false | Manual at-setpoint override; used when autoAtSetpoint is false. |
| touching | boolean | undefined | false | User is physically interacting with the control. Forces focus rendering and suppresses at-setpoint detection while true. |
| autoAtSetpoint | boolean | undefined | true | Enable automatic at-setpoint detection (default true). |
| autoAtSetpointDeadband | number | undefined | 2 | Tolerance for auto at-setpoint detection (default 2). |
| setpointAtZeroDeadband | number | undefined | 0.5 | Zero-snap tolerance for the marker's equalZero state (default 0.5). |
| setpointOverride | boolean | undefined | false | Derive the setpoint color from priority even when loading/off. |
| animateSetpoint | boolean | undefined | false | Enable the CSS-animated confirm transition. |
Related
- Rate of turn: how fast the vessel turns for that rudder angle.
- Heading: where the bow points.
- Data integrity: the states a value can be in, and what the crew does.