How to Configure Pan/Tilt Control for AtomSwing via WebUI
Configure AtomSwing pan/tilt positioning through the Vue.js-based WebUI by adjusting sliders in Setting.vue, which dispatch move commands to the firmware's MotorMove handler in libcallback/command.c.
The mnakada/atomcam_tools firmware extends Atom cameras with comprehensive pan/tilt support for the AtomSwing model. This functionality is exposed through an intuitive web interface that translates user interactions into precise motor commands. Understanding the configuration flow—from Vue.js components to low-level motor drivers—enables you to effectively control camera positioning and set up automated cruise points.
Understanding the AtomSwing Pan/Tilt Architecture
The pan/tilt system operates through three distinct layers: the web frontend, a command dispatcher, and the hardware abstraction layer.
Web UI Layer (Setting.vue)
The primary interface resides in web/source/vue/Setting.vue, which renders interactive sliders using Element UI components. The template defines two ElSlider controls:
- Tilt Slider: Vertical orientation, range 0–180 degrees
- Pan Slider: Horizontal orientation, range 0–355 degrees
These sliders bind to the component's reactive pan and tilt data fields. When values change, the @change and @input events trigger the Move method, which constructs and dispatches the motor command.
Command Dispatch Layer (command.c)
The firmware's command table in libcallback/command.c maps text commands to handler functions:
static const struct {
const char *name;
int (*handler)(int argc, char *argv[]);
} command_table[] = {
{ "move", &MotorMove },
// ... other commands
};
When the WebUI sends a move command via WebSocket or HTTP CGI, the dispatcher parses the arguments and invokes MotorMove.
Motor Driver Layer (motor.c)
The MotorMove function in libcallback/motor.c validates parameters and calls the Ingenic SDK:
int MotorMove(int argc, char *argv[]) {
float pan = atof(argv[1]); // 0-355
float tilt = atof(argv[2]); // 0-180
int speed = argc > 3 ? atoi(argv[3]) : 9;
int pri = argc > 4 ? atoi(argv[4]) : 2;
return local_sdk_motor_move_abs_angle(pan, tilt, speed,
&motor_move_done,
&motor_move_canceled, pri);
}
The local_sdk_motor_move_abs_angle function executes the hardware movement with the specified speed and priority.
Configuring Pan/Tilt Position via the WebUI
Using the Slider Controls
Access the Camera tab in the AtomSwing WebUI to reveal the pan/tilt controls. The interface displays:
- Vertical Tilt Slider: Drag to set elevation (0° = down, 180° = up)
- Horizontal Pan Slider: Drag to set azimuth (0°–355°)
The Vue.js component automatically clamps values to valid ranges and triggers movement:
async Move() {
if (!this.posValid || !this.moveDone) return;
await this.Exec(`move ${this.pan} ${this.tilt} 5 3`, 'socket');
this.StillImageInterval();
// Request position confirmation after 3 seconds
if (this.moveTimeout) clearTimeout(this.moveTimeout);
this.moveTimeout = setTimeout(() => {
this.moveTimeout = null;
this.Exec('posrec');
}, 3000);
}
The Exec method transmits the command via WebSocket (socket transport) for low-latency control.
Understanding the Move Command Syntax
The move command accepts four parameters:
move <pan> <tilt> [speed] [priority]
- pan: Absolute horizontal angle (0–355 degrees)
- tilt: Absolute vertical angle (0–180 degrees)
- speed: Movement velocity (0–9, where 9 is fastest; default 9)
- priority: Command precedence (0–9, where 0 is highest; default 2)
Lower priority values override ongoing movements. The WebUI defaults to speed 5 and priority 3 for smooth, user-initiated adjustments.
Resetting to Initial Position
Click the Initial Position button to home the motors. This triggers the MoveInit method:
MoveInit() {
this.Exec('moveinit');
}
The moveinit command instructs the firmware to reset the motor's absolute coordinate system, typically moving to a mechanical home position (0°, 90°) depending on hardware calibration.
Advanced Configuration: Cruise Points
Setting Up Cruise Points in SettingCruise.vue
For automated patrol patterns, use the cruise list functionality in web/source/vue/SettingCruise.vue. This component allows you to:
- Define multiple waypoints with specific pan/tilt coordinates
- Set dwell time at each position
- Synchronize selected waypoints with the main control sliders
When you select a cruise point from the list, the component updates the parent Setting.vue state:
// Synchronization logic in SettingCruise.vue
selectCruisePoint(point) {
this.$parent.pan = point.pan;
this.$parent.tilt = point.tilt;
this.$parent.Move();
}
This ensures the visual sliders reflect the saved position before execution.
Summary
- Web Interface: Configure pan/tilt through
Setting.vuesliders (pan 0–355°, tilt 0–180°) which trigger theMovemethod - Command Flow: UI sends
move <pan> <tilt> [speed] [priority]via WebSocket tolibcallback/command.c, dispatched toMotorMoveinlibcallback/motor.c - Hardware Control:
local_sdk_motor_move_abs_angleexecutes absolute positioning with configurable speed (0–9) and priority levels - Homing: Use the Initial Position button to issue
moveinitand reset motor coordinates - Automation: Define patrol routes through
SettingCruise.vueby saving multiple pan/tilt waypoints
Frequently Asked Questions
What is the valid range for pan and tilt values in the AtomSwing WebUI?
The AtomSwing supports pan values from 0 to 355 degrees and tilt values from 0 to 180 degrees. These limits are enforced by the slider components in web/source/vue/Setting.vue and validated in the MotorMove function within libcallback/motor.c before calling the SDK.
How does the priority parameter affect motor movement?
The priority parameter (0–9, default 2) determines command precedence when multiple movement requests occur simultaneously. Lower numbers indicate higher priority—commands with priority 0 will interrupt ongoing movements, while priority 9 commands may queue or be ignored if the motor is busy. The WebUI uses priority 3 for user-initiated moves to balance responsiveness with system stability.
Can I control pan/tilt programmatically outside the WebUI?
Yes, you can send raw text commands to the firmware's command socket or HTTP CGI endpoint. The syntax follows the same pattern used by the WebUI: move <pan> <tilt> [speed] [priority]. For example, sending move 180 90 9 0 via TCP socket or CGI script will center the camera at maximum speed with highest priority, bypassing the Vue.js interface entirely.
What happens if the motor is already moving when a new command is issued?
Behavior depends on the priority of the new command relative to the executing command. If the new command has equal or lower priority (higher numeric value), it typically queues or is rejected. If it has higher priority (lower numeric value), the local_sdk_motor_move_abs_angle function cancels the current movement via the motor_move_canceled callback and begins the new positioning. The WebUI waits for moveDone to become true before issuing subsequent commands to prevent command flooding.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →