1# 设备转动控制开发指南 2<!--Kit: Mechanic Kit--> 3<!--Subsystem: Mechanic--> 4<!--Owner: @hobbycao--> 5<!--Designer: @saga2025--> 6<!--Tester: @zhaodengqi--> 7<!--Adviser: @foryourself--> 8 9从API version 20开始,支持使用机械设备管理。在视频录制和直播等应用场景中,开发者希望为拥有机械体配件设备的用户提供更丰富的拍摄体验,如控制机械体配件设备转动功能。 10 11拍摄控制,可以将手机作为控制终端,操控云台或机械臂等机械体配件设备进行精准的角度调整和运动轨迹控制,帮助开发者快速构建控制机械配件设备的应用。 12 13## 接口介绍 14 15机械设备管理公开API接口使用指导请参见[MechanicManager API参考](../reference/apis-mechanic-kit/js-apis-mechanicManager.md)。 16机械设备管理系统API接口使用指导请参见[MechanicManager API参考](../reference/apis-mechanic-kit/js-apis-mechanicManager-sys.md)。 17 18| 接口名 | 描述 | 19| -------------------------------------------------------------------- | -------------------------- | 20|on(type: 'attachStateChange', callback: Callback\<AttachStateChangeInfo>): void | 注册attachStateChange事件的回调监听,等待连接状态变化。<br>**说明**:从API version 20开始支持。| 21|off(type: 'attachStateChange', callback?: Callback\<AttachStateChangeInfo>): void | 取消注册attachStateChange事件的回调监听。<br>**说明**:从API version 20开始支持。| 22|getAttachedMechDevices(): MechInfo[] | 获取已连接的机械体设备列表。<br>**说明**:从API version 20开始支持。| 23|setUserOperation(operation: Operation, mac: string, params: string): void | 设置用户操作。<br>**说明**:从API version 20开始支持。| 24|setCameraTrackingEnabled(isEnabled: boolean): void | 启用或禁用摄像头跟踪。<br>**说明**:从API version 20开始支持。| 25|getCameraTrackingEnabled(): boolean | 检查是否启用了摄像头跟踪。<br>**说明**:从API version 20开始支持。| 26|getCameraTrackingLayout(): CameraTrackingLayout | 获取此机械设备摄像头跟踪布局。<br>**说明**:从API version 20开始支持。| 27|rotate(mechId: number, angles: RotationAngles, duration: number): Promise\<Result> | 将机械体设备旋转到相对角度。<br>**说明**:从API version 20开始支持。| 28|rotateToEulerAngles(mechId: number, angles: EulerAngles, duration: number): Promise\<Result> | 将机械体设备旋转到绝对角度。<br>**说明**:从API version 20开始支持。| 29|getMaxRotationTime(mechId: number): number | 获取机械体设备的最大连续旋转持续时间。<br>**说明**:从API version 20开始支持。| 30|getMaxRotationSpeed(mechId: number): RotationSpeed | 获取机械设备的最大旋转速度。<br>**说明**:从API version 20开始支持。| 31|stopMoving(mechId: number): Promise\<void> | 停止机械体设备的移动。<br>**说明**:从API version 20开始支持。| 32|getCurrentAngles(mechId: number): EulerAngles | 获取机械体设备的当前角度。<br>**说明**:从API version 20开始支持。| 33|getRotationLimits(mechId: number): RotationLimits | 获取指定机械体设备相对于参考点的最大旋转角度。<br>**说明**:从API version 20开始支持。| 34|getRotationAxesStatus(mechId: number): RotationAxesStatus | 获取旋转轴的状态。<br>**说明**:从API version 20开始支持。| 35|on(type: 'rotationAxesStatusChange', callback: Callback\<RotationAxesStateChangeInfo>): void | 注册rotationAxesStatusChange事件的回调监听。<br>**说明**:从API version 20开始支持。| 36|off(type: 'rotationAxesStatusChange', callback?: Callback\<RotationAxesStateChangeInfo>): void | 取消注册rotationAxesStatusChange事件的回调监听。<br>**说明**:从API version 20开始支持。| 37 38## 开发步骤 39 40### 开发准备 41 421. 一台支持MechanicKit协议的机械体配件设备。 43 442. 机械体配件设备与开发设备完成蓝牙连接。 45 46### 管理设备连接状态 47 48动态管理设备连接状态,确保设备连接或断开时应用能及时响应。 49 501. 导入机械设备管理模块文件。 51 52 ```ts 53 import mechanicManager from '@kit.MechanicKit'; 54 ``` 55 562. 获取已连接的机械设备列表。 57 58 ```ts 59 let savedMechanicIds: number[] = []; 60 61 try { 62 const devices = mechanicManager.getAttachedMechDevices(); 63 console.log('Connected devices:', devices); 64 65 devices.forEach(device => { 66 console.log(`Device ID: ${device.mechId}`); 67 console.log(`Device Name: ${device.mechName}`); 68 console.log(`Device Type: ${device.mechDeviceType}`); 69 70 //保存设备类型为GIMBAL_DEVICE的设备的MechId 71 if (device.mechDeviceType === mechanicManager.MechDeviceType.GIMBAL_DEVICE) { 72 savedMechanicIds.push(device.mechId); 73 console.log(`GIMBAL_TYPE device saved ID: ${device.mechId}`); 74 } else { 75 console.log(`Skip non-gimbal devices: ${device.mechId}`); 76 } 77 }); 78 79 console.log('List of saved gimbal device IDs:', savedMechanicIds); 80 } catch (err) { 81 console.error('Error getting attached devices:', err); 82 } 83 ``` 84 853. 监听设备连接状态变化。 86 87 ```ts 88 const attachStateChangeCallback = (info: mechanicManager.AttachStateChangeInfo) => { 89 if (info.state === mechanicManager.AttachState.ATTACHED) { 90 console.log('Device attached:', info.mechInfo); 91 // 处理设备连接逻辑 92 handleDeviceAttached(info.mechInfo); 93 } else if (info.state === mechanicManager.AttachState.DETACHED) { 94 console.log('Device detached:', info.mechInfo); 95 // 处理设备断开逻辑 96 handleDeviceDetached(info.mechInfo); 97 } 98 }; 99 100 // 注册监听 101 mechanicManager.on('attachStateChange', attachStateChangeCallback); 102 ``` 103 1044. 处理设备连接和断开事件。 105 106 ```ts 107 mechanicManager.on('attachStateChange', attachStateChangeCallback); 108 109 function handleDeviceAttached(mechInfo: mechanicManager.MechInfo) { 110 console.log(`New device is connected: ${mechInfo.mechName} (ID: ${mechInfo.mechId})`); 111 savedMechanicIds.push(mechInfo.mechId); 112 // To do sth. 113 } 114 115 function handleDeviceDetached(mechInfo: mechanicManager.MechInfo) { 116 console.log(`Device disconnected: ${mechInfo.mechName} (ID: ${mechInfo.mechId})`); 117 savedMechanicIds.filter(id => id !== mechInfo.mechId); 118 // To do sth. 119 } 120 ``` 121 1225. 取消监听。 123 124 ```ts 125 // 取消特定回调的监听 126 mechanicManager.off('attachStateChange', attachStateChangeCallback); 127 ``` 128 129### 控制设备转动 130 131精准控制机械体配件设备转动,如角度调整和运动轨迹控制等,帮助开发者实现灵活的机械体配件设备操作功能。 132 1331. 查询设备当前状态和限制。 134 135 ```ts 136 try { 137 // 初始化设备功能,例如获取设备状态 138 const devices = mechanicManager.getAttachedMechDevices(); 139 console.log('Connected devices:', devices); 140 141 devices.forEach(device => { 142 console.log(`Device ID: ${device.mechId}`); 143 console.log(`Device Name: ${device.mechName}`); 144 console.log(`Device Type: ${device.mechDeviceType}`); 145 }); 146 147 // 注册设备连接状态监听 148 const attachStateChangeCallback = (info: mechanicManager.AttachStateChangeInfo) => { 149 if (info.state === mechanicManager.AttachState.ATTACHED) { 150 console.log('Device attached:', info.mechInfo); 151 } else if (info.state === mechanicManager.AttachState.DETACHED) { 152 console.log('Device detached:', info.mechInfo); 153 } 154 }; 155 mechanicManager.on('attachStateChange', attachStateChangeCallback); 156 // 获取当前角度 157 const currentAngles = mechanicManager.getCurrentAngles(savedMechanicIds[0]); 158 console.log('current angle:', currentAngles); 159 160 // 获取旋转限制 161 const rotationLimits = mechanicManager.getRotationLimits(savedMechanicIds[0]); 162 console.log('Rotation limit:', rotationLimits); 163 164 // 获取最大旋转速度 165 const maxSpeed = mechanicManager.getMaxRotationSpeed(savedMechanicIds[0]); 166 console.log('Maximum rotation speed:', maxSpeed); 167 168 // 获取速度控制最大持续时间 169 const maxTime = mechanicManager.getMaxRotationTime(savedMechanicIds[0]); 170 console.log('Maximum spin time:', maxTime); 171 } catch (err) { 172 console.error('Failed to query device status:', err); 173 } 174 ``` 175 1762. 执行相对角度旋转。 177 178 ```ts 179 //执行转动控制前需要先关闭跟踪拍摄功能 180 mechanicManager.setCameraTrackingEnabled(false); 181 182 async function rotateByRelativeAngles() { 183 try { 184 const mechId = savedMechanicIds[0]; // 设备ID 185 186 // 查询当前角度 187 const currentAngles = mechanicManager.getCurrentAngles(mechId); 188 if (!currentAngles || currentAngles.yaw === undefined || currentAngles.pitch === undefined || 189 currentAngles.roll === undefined) { 190 console.error('Failed to retrieve current angles or angles are undefined.'); 191 return; 192 } 193 194 // 获取旋转限位 195 const rotationLimits = mechanicManager.getRotationLimits(mechId); 196 if (!rotationLimits || rotationLimits.negativeYawMax === undefined || rotationLimits.positiveYawMax === undefined || 197 rotationLimits.negativePitchMax === undefined || rotationLimits.positivePitchMax === undefined || 198 rotationLimits.negativeRollMax === undefined || rotationLimits.positiveRollMax === undefined) { 199 console.error('Failed to retrieve rotation limits or limits are undefined.'); 200 return; 201 } 202 console.log('Rotation limits:', rotationLimits); 203 204 // 定义目标角度并确保类型正确 205 const angles: mechanicManager.RotationAngles = { 206 yaw: Math.PI / 4, // 偏航角:45度 207 pitch: Math.PI / 6, // 俯仰角:30度 208 roll: 0 // 横滚角:0度 209 }; 210 211 // 检查目标角度是否超出限位 212 if ( 213 currentAngles.yaw + (angles.yaw ?? 0) > rotationLimits.negativeYawMax || 214 currentAngles.yaw + (angles.yaw ?? 0) < rotationLimits.positiveYawMax || 215 currentAngles.pitch + (angles.pitch ?? 0) > rotationLimits.negativePitchMax || 216 currentAngles.pitch + (angles.pitch ?? 0) < rotationLimits.positivePitchMax || 217 currentAngles.roll + (angles.roll ?? 0) > rotationLimits.negativeRollMax || 218 currentAngles.roll + (angles.roll ?? 0) < rotationLimits.positiveRollMax 219 ) { 220 console.error('Target angles exceed rotation limits.'); 221 return; 222 } 223 224 const duration = 2000; // 旋转持续时间:2秒 225 226 // 执行旋转 227 const result = await mechanicManager.rotate(mechId, angles, duration); 228 console.info(`Rotation Result: ${result}`); 229 } catch (err) { 230 console.error('Failed to rotate relative angle:', err); 231 } 232 } 233 ``` 234 2353. 以指定速度持续转动。 236 237 ```ts 238 async function rotateBySpeed() { 239 try { 240 const mechId = savedMechanicIds[0]; // 假设使用第一个设备 241 242 // 获取速度控制最大持续时间 243 const maxTime = mechanicManager.getMaxRotationTime(mechId); 244 console.log('Maximum spin time:', maxTime); 245 246 // 获取最大旋转速度 247 const maxSpeed = mechanicManager.getMaxRotationSpeed(mechId); 248 if (!maxSpeed || maxSpeed.yawSpeed === undefined || maxSpeed.pitchSpeed === undefined || maxSpeed.rollSpeed === undefined) { 249 console.error('Failed to retrieve maximum rotation speed or speed values are undefined.'); 250 return; 251 } 252 console.log('Maximum rotation speed:', maxSpeed); 253 // 定义旋转速度和持续时间 254 const speed : mechanicManager.RotationSpeed = { 255 yawSpeed: maxSpeed.yawSpeed / 2, // 偏航速度:最大速度的一半 256 pitchSpeed: maxSpeed.pitchSpeed / 2, // 俯仰速度:最大速度的一半 257 rollSpeed: maxSpeed.rollSpeed / 2 // 横滚速度:最大速度的一半 258 }; 259 const duration = Math.min(maxTime, 5000); // 持续时间:不超过最大持续时间,最多5秒 260 261 // 执行旋转 262 const result = await mechanicManager.rotateBySpeed(mechId, speed, duration); 263 console.info(`Rotation by speed result: ${result}`); 264 } catch (err) { 265 console.error('Failed to rotate by speed:', err); 266 } 267 } 268 ``` 269 2704. 监听旋转轴状态变化。 271 272 ```ts 273 const rotationAxesCallback = (info: mechanicManager.RotationAxesStateChangeInfo) => { 274 console.log('Rotating Axes state change:', info); 275 const mechId = info.mechId; 276 const status = info.status; 277 278 console.log(`Device ${mechId} status update:`); 279 console.log(`- Yaw axes enabled: ${status.yawEnabled}`); 280 console.log(`- Pitch axes enabled: ${status.pitchEnabled}`); 281 console.log(`- Roll axes enabled: ${status.rollEnabled}`); 282 283 if (status.yawLimited !== undefined) { 284 console.log(`- Yaw axis restriction state: ${status.yawLimited}`); 285 } 286 }; 287 288 // 注册监听 289 mechanicManager.on('rotationAxesStatusChange', rotationAxesCallback); 290 ``` 291 2925. 停止设备运动。 293 294 ```ts 295 async function stopDeviceMoving() { 296 try { 297 const mechId = savedMechanicIds[0]; 298 await mechanicManager.stopMoving(mechId); 299 console.log('The device has stopped moving'); 300 } catch (err) { 301 console.error('Failed to stop device movement:', err); 302 } 303 } 304 ``` 305 306### 调试验证 307 308为了确保机械设备管理功能正常工作,请按照以下步骤进行调试验证: 309 310**建立连接** 311 3121. 确保机械体配件设备与开发设备通过蓝牙成功配对并建立连接。 3132. 将开发设备正确放置在机械体配件设备上。 314 315**功能验证步骤** 316 3171. **设备列表查询**:调用 `getAttachedMechDevices` 接口查询当前已连接的机械体配件设备列表,验证设备是否正确识别。 3182. **设备转动控制**:调用 `setCameraTrackingEnabled` 关闭跟踪功能,通过 `getCameraTrackingEnabled` 验证状态,调用 `rotate` 或 `rotateBySpeed` 控制设备转动。 319 320**验证结果说明** 321 322- 如果 `getAttachedMechDevices` 返回包含机械体配件设备信息的设备列表,表示设备识别正常。 323- 如果调用 `rotate` 或 `rotateBySpeed` 按预期开始转动,表示转动控制正常。 324