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:

  1. Vertical Tilt Slider: Drag to set elevation (0° = down, 180° = up)
  2. 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:

  1. Define multiple waypoints with specific pan/tilt coordinates
  2. Set dwell time at each position
  3. 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.vue sliders (pan 0–355°, tilt 0–180°) which trigger the Move method
  • Command Flow: UI sends move <pan> <tilt> [speed] [priority] via WebSocket to libcallback/command.c, dispatched to MotorMove in libcallback/motor.c
  • Hardware Control: local_sdk_motor_move_abs_angle executes absolute positioning with configurable speed (0–9) and priority levels
  • Homing: Use the Initial Position button to issue moveinit and reset motor coordinates
  • Automation: Define patrol routes through SettingCruise.vue by 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →