What's new?
1. Add new model: DJI Matrices 350 RTK.
2. Fixed some issues.
| | |
| | | "ant-design-vue/es/switch/style/css", |
| | | "ant-design-vue/es/table/style/css", |
| | | "ant-design-vue/es/tag/style/css", |
| | | "ant-design-vue/es/time-picker/style/css", |
| | | "ant-design-vue/es/tooltip/style/css", |
| | | "ant-design-vue/es/tree/style/css", |
| | | "ant-design-vue/es/upload/style/css", |
| | |
| | | <span>Take off</span> |
| | | </Button> |
| | | </DroneControlPopover> |
| | | <Button :loading="cmdItem.loading" size="small" ghost @click="sendControlCmd(cmdItem, index)"> |
| | | <Button :loading="cmdItem.loading" size="small" ghost @click="sendControlCmd(cmdItem, 0)"> |
| | | {{ cmdItem.operateText }} |
| | | </Button> |
| | | </div> |
| | |
| | | return store.state.clientId |
| | | }) |
| | | |
| | | const initCmdList = baseCmdList.find(item => item.cmdKey === DeviceCmd.ReturnHome) |
| | | const initCmdList = baseCmdList.find(item => item.cmdKey === DeviceCmd.ReturnHome) as DeviceCmdItem |
| | | const cmdItem = ref(initCmdList) |
| | | |
| | | const { |
| | |
| | | action: cmdItem.action |
| | | }, false) |
| | | if (result && flightController.value) { |
| | | message.success('Return home successful') |
| | | exitFlightCOntrol() |
| | | } else { |
| | | message.error('Failed to return home') |
| | | } |
| | | cmdItem.loading = false |
| | | } |
| | |
| | | maxSpeed: MAX_SPEED, |
| | | rthAltitude: null as null | number, |
| | | rcLostAction: LostControlActionInCommandFLight.RETURN_HOME, |
| | | exitWaylineWhenRcLost: WaylineLostControlActionInCommandFlight.RETURN_HOME |
| | | exitWaylineWhenRcLost: WaylineLostControlActionInCommandFlight.EXEC_LOST_ACTION |
| | | }) |
| | | |
| | | function onShowTakeoffToPointPopover () { |
| | |
| | | takeoffToPointPopoverData.securityTakeoffHeight = null |
| | | takeoffToPointPopoverData.rthAltitude = null |
| | | takeoffToPointPopoverData.rcLostAction = LostControlActionInCommandFLight.RETURN_HOME |
| | | takeoffToPointPopoverData.exitWaylineWhenRcLost = WaylineLostControlActionInCommandFlight.RETURN_HOME |
| | | takeoffToPointPopoverData.exitWaylineWhenRcLost = WaylineLostControlActionInCommandFlight.EXEC_LOST_ACTION |
| | | } |
| | | |
| | | async function onTakeoffToPointConfirm (confirm: boolean) { |
| | |
| | | useMqtt(deviceTopicInfo) |
| | | |
| | | // 飞行控制 |
| | | const drcState = computed(() => { |
| | | return store.state.deviceState?.dockInfo[props.sn]?.link_osd?.drc_state === DrcStateEnum.CONNECTED |
| | | }) |
| | | const flightController = ref(drcState.value) |
| | | // const drcState = computed(() => { |
| | | // return store.state.deviceState?.dockInfo[props.sn]?.link_osd?.drc_state === DrcStateEnum.CONNECTED |
| | | // }) |
| | | const flightController = ref(false) |
| | | |
| | | async function onClickFightControl () { |
| | | if (flightController.value) { |
| | |
| | | } |
| | | |
| | | // drc mqtt message |
| | | const { drcInfo } = useDroneControlMqttEvent(props.sn) |
| | | const { drcInfo, errorInfo } = useDroneControlMqttEvent(props.sn) |
| | | |
| | | const { |
| | | handleKeyup, |
| | |
| | | } |
| | | cameraAimPopoverData.visible = false |
| | | } |
| | | |
| | | watch(() => errorInfo, (errorInfo) => { |
| | | if (errorInfo.value) { |
| | | message.error(errorInfo.value) |
| | | console.error(errorInfo.value) |
| | | errorInfo.value = '' |
| | | } |
| | | }, { |
| | | immediate: true, |
| | | deep: true |
| | | }) |
| | | </script> |
| | | |
| | | <style lang='scss' scoped> |
| | |
| | | DRCHsiInfo, |
| | | DRCOsdInfo, |
| | | DRCDelayTimeInfo, |
| | | DrcResponseInfo, |
| | | } from '/@/types/drc' |
| | | |
| | | export function useDroneControlMqttEvent (sn: string) { |
| | |
| | | const hsiInfo = ref('') |
| | | const osdInfo = ref('') |
| | | const delayInfo = ref('') |
| | | const errorInfo = ref('') |
| | | |
| | | function handleHsiInfo (data: DRCHsiInfo) { |
| | | hsiInfo.value = `method: ${DRC_METHOD.HSI_INFO_PUSH}\r\n ${JSON.stringify(data)}\r\n ` |
| | |
| | | |
| | | function handleDelayTimeInfo (data: DRCDelayTimeInfo) { |
| | | delayInfo.value = `method: ${DRC_METHOD.DELAY_TIME_INFO_PUSH}\r\n ${JSON.stringify(data)}\r\n ` |
| | | } |
| | | |
| | | function handleDroneControlErrorInfo (data: DrcResponseInfo) { |
| | | if (!data.result) { |
| | | return |
| | | } |
| | | errorInfo.value = `Drc error code: ${data.result}, seq: ${data.output?.seq}` |
| | | } |
| | | |
| | | function handleDroneControlMqttEvent (payload: any) { |
| | |
| | | handleDelayTimeInfo(payload.data) |
| | | break |
| | | } |
| | | case DRC_METHOD.DRONE_EMERGENCY_STOP: |
| | | case DRC_METHOD.DRONE_CONTROL: { |
| | | handleDroneControlErrorInfo(payload.data) |
| | | break |
| | | } |
| | | } |
| | | drcInfo.value = hsiInfo.value + osdInfo.value + delayInfo.value |
| | | } |
| | |
| | | }) |
| | | |
| | | return { |
| | | drcInfo: drcInfo |
| | | drcInfo: drcInfo, |
| | | errorInfo: errorInfo |
| | | } |
| | | } |
| | |
| | | } |
| | | if (data.type === ControlSourceChangeType.Payload && data.sn === payloadSn) { |
| | | payloadControlSource.value = data.control_source |
| | | message.info(`Payload control is changed to ${ payloadControlSource.value }.`) |
| | | return |
| | | message.info(`Payload control is changed to ${payloadControlSource.value}.`) |
| | | } |
| | | } |
| | | |
| | | function handleProgress(key: string, message: string, error: number) { |
| | | function handleProgress (key: string, message: string, error: number) { |
| | | if (error !== 0) { |
| | | notification.error({ |
| | | key: key, |
| | |
| | | } |
| | | case EBizCode.DrcStatusNotify: { |
| | | const { sn: deviceSn, result, message: msg } = payload.data as DrcStatusNotifyMessage |
| | | if (deviceSn !== sn) return |
| | | // handleProgress(EBizCode.DrcStatusNotify, `device(sn: ${deviceSn}) ${msg}`, result) |
| | | |
| | | break |
| | |
| | | export function useManualControl (deviceTopicInfo: DeviceTopicInfo, isCurrentFlightController: Ref<boolean>) { |
| | | const activeCodeKey = ref(null) as Ref<KeyCode | null> |
| | | const mqttHooks = useMqtt(deviceTopicInfo) |
| | | |
| | | let seq = 0 |
| | | function handlePublish (params: DroneControlProtocol) { |
| | | const body = { |
| | | method: DRC_METHOD.DRONE_CONTROL, |
| | |
| | | } |
| | | handleClearInterval() |
| | | myInterval = setInterval(() => { |
| | | body.data.seq = seq++ |
| | | seq++ |
| | | window.console.log('keyCode>>>>', activeCodeKey.value, body) |
| | | body.data.seq = new Date().getTime() |
| | | mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, { qos: 0 }) |
| | | }, 50) |
| | | } |
| | |
| | | const SPEED = 5 // check |
| | | const HEIGHT = 5 // check |
| | | const W_SPEED = 20 // 机头角速度 |
| | | seq = 0 |
| | | switch (keyCode) { |
| | | case 'KeyA': |
| | | if (activeCodeKey.value === keyCode) return |
| | |
| | | |
| | | function resetControlState () { |
| | | activeCodeKey.value = null |
| | | seq = 0 |
| | | handleClearInterval() |
| | | } |
| | | |
| | |
| | | case DRC_METHOD.DELAY_TIME_INFO_PUSH: |
| | | case DRC_METHOD.HSI_INFO_PUSH: |
| | | case DRC_METHOD.OSD_INFO_PUSH: |
| | | case DRC_METHOD.DRONE_CONTROL: |
| | | case DRC_METHOD.DRONE_EMERGENCY_STOP: |
| | | EventBus.emit('droneControlMqttInfo', payloadObj) |
| | | break |
| | | default: |
| | |
| | | class="ml10" |
| | | v-model:value="agoraPara.token" |
| | | placeholder="Token" |
| | | @change="encodeToken" |
| | | ></a-input> |
| | | <span class="ml10">Channel:</span> |
| | | <a-input |
| | |
| | | liveState: false |
| | | }) |
| | | const nonSwitchable = 'normal' |
| | | |
| | | const onRefresh = async () => { |
| | | dronePara.droneList = [] |
| | | dronePara.cameraList = [] |
| | |
| | | |
| | | onMounted(() => { |
| | | onRefresh() |
| | | agoraPara.token = encodeURIComponent(agoraPara.token) |
| | | agoraClient = AgoraRTC.createClient({ mode: 'live', codec: 'vp8' }) |
| | | agoraClient.setClientRole('audience', { level: 2 }) |
| | | if (agoraClient.connectionState === 'DISCONNECTED') { |
| | | agoraClient.join(agoraPara.appid, agoraPara.channel, agoraPara.token) |
| | | } |
| | | // Subscribe when a remote user publishes a stream |
| | | agoraClient.on('user-joined', async (user: IAgoraRTCRemoteUser) => { |
| | | message.info('user[' + user.uid + '] join') |
| | |
| | | // Get `RemoteVideoTrack` in the `user` object. |
| | | const remoteVideoTrack = user.videoTrack! |
| | | // Dynamically create a container in the form of a DIV element for playing the remote video track. |
| | | const remotePlayerContainer: any = document.getElementById('player') |
| | | remotePlayerContainer.id = user.uid.toString() |
| | | remoteVideoTrack.play(remotePlayerContainer) |
| | | remoteVideoTrack.play(document.getElementById('player') as HTMLElement) |
| | | } |
| | | }) |
| | | agoraClient.on('user-unpublished', async (user: any) => { |
| | |
| | | message.error(e.msg) |
| | | }) |
| | | }) |
| | | |
| | | const handleError = (err: any) => { |
| | | console.error(err) |
| | | } |
| | | const handleJoinChannel = (uid: any) => { |
| | | agoraPara.uid = uid |
| | | } |
| | | const encodeToken = (e: any) => { |
| | | agoraPara.token = encodeURIComponent(agoraPara.token) |
| | | } |
| | | const onStart = async () => { |
| | | const that = this |
| | |
| | | } |
| | | agoraClient.setClientRole('audience', { level: 2 }) |
| | | if (agoraClient.connectionState === 'DISCONNECTED') { |
| | | agoraClient |
| | | .join(agoraPara.appid, agoraPara.channel, agoraPara.token) |
| | | await agoraClient.join(agoraPara.appid, agoraPara.channel, agoraPara.token) |
| | | } |
| | | livePara.videoId = |
| | | dronePara.droneSelected + |
| | |
| | | '&sn=' + |
| | | dronePara.droneSelected + |
| | | '&token=' + |
| | | agoraPara.token + |
| | | encodeURIComponent(agoraPara.token) + |
| | | '&uid=' + |
| | | agoraPara.uid |
| | | |
| | |
| | | }) |
| | | } |
| | | const onStop = async () => { |
| | | if ( |
| | | dronePara.droneSelected == null || |
| | | dronePara.cameraSelected == null || |
| | | dronePara.claritySelected == null |
| | | ) { |
| | | message.warn('waring: not select live para!!!') |
| | | return |
| | | } |
| | | livePara.videoId = |
| | | dronePara.droneSelected + |
| | | '/' + |
| | |
| | | }).then(res => { |
| | | if (res.code === 0) { |
| | | message.success(res.message) |
| | | livePara.liveState = false |
| | | dronePara.lensSelected = '' |
| | | console.log('stop play livestream') |
| | | } |
| | | livePara.liveState = false |
| | | dronePara.lensSelected = '' |
| | | console.log('stop play livestream') |
| | | }) |
| | | } |
| | | const onDroneSelect = (val: SelectOption) => { |
| | |
| | | dronePara.videoSelected = firstVideo.value |
| | | dronePara.lensList = firstVideo.more |
| | | dronePara.lensSelected = firstVideo.label |
| | | dronePara.isDockLive = dronePara.lensList.length > 0 |
| | | dronePara.isDockLive = dronePara.lensList?.length > 0 |
| | | } |
| | | const onVideoSelect = (val: SelectOption) => { |
| | | dronePara.videoSelected = val.value |
| | |
| | | videoSelected.value = firstVideo.value |
| | | lensList.value = firstVideo.more |
| | | lensSelected.value = firstVideo.label |
| | | isDockLive.value = lensList.value.length > 0 |
| | | isDockLive.value = lensList.value?.length > 0 |
| | | } |
| | | const onVideoSelect = (val: SelectOption) => { |
| | | videoSelected.value = val.value |
| | |
| | | Create Plan |
| | | </div> |
| | | <div class="content"> |
| | | <a-form ref="valueRef" layout="horizontal" :hideRequiredMark="true" :rules="rules" :model="planBody"> |
| | | <a-form-item label="Plan Name" name="name" :labelCol="{span: 24}"> |
| | | <a-form ref="valueRef" layout="horizontal" :hideRequiredMark="true" :rules="rules" :model="planBody" labelAlign="left"> |
| | | <a-form-item label="Plan Name" name="name" :labelCol="{span: 23}"> |
| | | <a-input style="background: black;" placeholder="Please enter plan name" v-model:value="planBody.name"/> |
| | | </a-form-item> |
| | | <!-- 航线 --> |
| | |
| | | </div> |
| | | </a-form-item> |
| | | <!-- 任务类型 --> |
| | | <a-form-item label="Plan Timer" class="plan-timer-form-item"> |
| | | <a-form-item label="Plan Timer" class="plan-timer-form-item" :labelCol="{span: 23}"> |
| | | <div style="white-space: nowrap;"> |
| | | <a-radio-group v-model:value="planBody.task_type" button-style="solid"> |
| | | <a-radio-button :value="TaskType.Immediate">Immediate</a-radio-button> |
| | | <a-radio-button :value="TaskType.Single">Timed&One-Time</a-radio-button> |
| | | <a-radio-button v-for="type in TaskTypeOptions" :value="type.value" :key="type.value">{{ type.label }}</a-radio-button> |
| | | </a-radio-group> |
| | | </div> |
| | | </a-form-item> |
| | | <!-- 执行时间 --> |
| | | <a-form-item label="Start Time" v-if="planBody.task_type === TaskType.Single" name="select_execute_time"> |
| | | <a-form-item label="Start Time" v-if="planBody.task_type === TaskType.Timed" name="select_execute_time" :labelCol="{span: 23}"> |
| | | <a-date-picker |
| | | v-model:value="planBody.select_execute_time" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | show-time |
| | | show-time |
| | | placeholder="Select Time" |
| | | style="width: 280px;" |
| | | /> |
| | | /> |
| | | </a-form-item> |
| | | <!-- RTH Altitude Relative to Dock --> |
| | | <a-form-item label="RTH Altitude Relative to Dock (m)" :labelCol="{span: 24}" name="rth_altitude"> |
| | | <a-input v-model:value="planBody.rth_altitude" style="background: black !important;"> |
| | | </a-input> |
| | | <a-form-item label="RTH Altitude Relative to Dock (m)" :labelCol="{span: 23}" name="rth_altitude"> |
| | | <a-input-number v-model:value="planBody.rth_altitude" :min="20" :max="1500" class="width-100" required> |
| | | </a-input-number> |
| | | </a-form-item> |
| | | <!-- Lost Action --> |
| | | <a-form-item label="Lost Action" :labelCol="{span: 24}" name="out_of_control_action"> |
| | | <a-form-item label="Lost Action" :labelCol="{span: 23}" name="out_of_control_action"> |
| | | <div style="white-space: nowrap;"> |
| | | <a-radio-group v-model:value="planBody.out_of_control_action" button-style="solid"> |
| | | <a-radio-button v-for="action in OutOfControlActionOptions" :value="action.value" :key="action.value"> |
| | |
| | | </a-radio-group> |
| | | </div> |
| | | </a-form-item> |
| | | <a-form-item style="width: 280px;"> |
| | | <a-form-item class="width-100" style="margin-bottom: 40px;"> |
| | | <div class="footer"> |
| | | <a-button class="mr10" style="background: #3c3c3c;" @click="closePlan">Cancel |
| | | </a-button> |
| | |
| | | </a-form> |
| | | </div> |
| | | </div> |
| | | <div v-if="drawerVisible" style="position: absolute; left: 330px; width: 280px; height: 100vh; float: right; top: 0; z-index: 1000; color: white; background: #282828;"> |
| | | <div v-if="drawerVisible" style="position: absolute; left: 335px; width: 280px; height: 100vh; float: right; top: 0; z-index: 1000; color: white; background: #282828;"> |
| | | <div> |
| | | <router-view :name="routeName"/> |
| | | </div> |
| | |
| | | |
| | | <script lang="ts" setup> |
| | | import { computed, onMounted, onUnmounted, reactive, ref, toRaw, UnwrapRef } from 'vue' |
| | | import { CloseOutlined, RocketOutlined, CameraFilled, UserOutlined } from '@ant-design/icons-vue' |
| | | import { CloseOutlined, RocketOutlined, CameraFilled, UserOutlined, PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons-vue' |
| | | import { ELocalStorageKey, ERouterName } from '/@/types' |
| | | import { useMyStore } from '/@/store' |
| | | import { WaylineType, WaylineFile } from '/@/types/wayline' |
| | | import { Device, EDeviceType } from '/@/types/device' |
| | | import { createPlan, CreatePlan } from '/@/api/wayline' |
| | | import { getRoot } from '/@/root' |
| | | import { TaskType, OutOfControlActionOptions, OutOfControlAction } from '/@/types/task' |
| | | import { TaskType, OutOfControlActionOptions, OutOfControlAction, TaskTypeOptions } from '/@/types/task' |
| | | import moment, { Moment } from 'moment' |
| | | import { RuleObject } from 'ant-design-vue/es/form/interface' |
| | | |
| | |
| | | // console.log('planBody', createPlanBody) |
| | | createPlan(workspaceId, createPlanBody) |
| | | .then(res => { |
| | | setTimeout(() => { |
| | | disabled.value = false |
| | | }, 1500) |
| | | disabled.value = false |
| | | }).finally(() => { |
| | | closePlan() |
| | | }) |
| | |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | width: 285px; |
| | | |
| | | .header { |
| | | height: 52px; |
| | |
| | | align-items: center; |
| | | } |
| | | |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | } |
| | | |
| | | .content { |
| | | height: calc(100% - 54px); |
| | | overflow-y: auto; |
| | |
| | | margin: 10px; |
| | | } |
| | | |
| | | form label, input { |
| | | form label, input, .ant-input, .ant-calendar-range-picker-separator, |
| | | .ant-input:hover, .ant-time-picker .anticon, .ant-calendar-picker .anticon { |
| | | background-color: #232323; |
| | | color: #fff; |
| | | } |
| | |
| | | } |
| | | |
| | | .plan-timer-form-item { |
| | | // flex-direction: column; |
| | | |
| | | .ant-radio-button-wrapper{ |
| | | background-color: #232323; |
| | | color: #fff; |
| | | |
| | | width: 80%; |
| | | text-align: center; |
| | | &.ant-radio-button-wrapper-checked{ |
| | | background-color: #1890ff; |
| | | } |
| | |
| | | <span style="color: #737373">{{ device.data.gateway_sn }}</span> |
| | | </a-col> |
| | | </a-row> |
| | | <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" v-if="device.data.online_status"> |
| | | <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" v-if="device.data.online_status && device.data.sn"> |
| | | <a-col :span="1"></a-col> |
| | | <a-col :span="9">Aircraft Sn</a-col> |
| | | <a-col :span="13" class="flex-align-end flex-column" > |
| | |
| | | <span class="ml5" style="color: #939393;">Settings</span> |
| | | </div> |
| | | <div class="fz16" style="background-color: white; border-radius: 4px;"> |
| | | <a-row v-if="device.data.online_status" style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="bindingDevice"> |
| | | <a-row v-if="device.data.online_status && device.data.sn" style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="bindingDevice"> |
| | | <a-col :span="1"></a-col> |
| | | <a-col :span="11"> |
| | | Device Binding |
| | |
| | | onMounted(() => { |
| | | apiPilot.onBackClickReg() |
| | | apiPilot.onStopPlatform() |
| | | const oldDevice = localStorage.getItem(ELocalStorageKey.Device) |
| | | if (oldDevice) { |
| | | device.data = JSON.parse(oldDevice) |
| | | } |
| | | |
| | | window.connectCallback = (arg: any) => { |
| | | connectCallback(arg) |
| | |
| | | message.warn('Data is not available, please restart the remote control.') |
| | | return |
| | | } |
| | | const oldDevice = localStorage.getItem(ELocalStorageKey.Device) |
| | | if (oldDevice) { |
| | | device.data = JSON.parse(oldDevice) |
| | | } |
| | | |
| | | device.data.sn = apiPilot.getAircraftSN() |
| | | getDeviceInfo() |
| | | |
| | |
| | | } |
| | | |
| | | function getDeviceInfo () { |
| | | if (device.data.sn === EStatusValue.DISCONNECT) { |
| | | if (!device.data.sn || device.data.sn === EStatusValue.DISCONNECT) { |
| | | return |
| | | } |
| | | getDeviceBySn(bindParam.workspace_id, device.data.sn).then(res => { |
| | |
| | | .main-content { |
| | | flex: 1; |
| | | color: $text-white-basic; |
| | | width: 285px; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | if (info.host.job_number !== undefined) { |
| | | dock.work_osd = info.host |
| | | return |
| | | } |
| | | }, |
| | | SET_DRAW_VISIBLE_INFO (state, bool) { |
| | |
| | | M30 = 67, |
| | | M300 = 60, |
| | | Mavic3EnterpriseAdvanced= 77, |
| | | M350 = 89, |
| | | } |
| | | |
| | | // DJI负载类型枚举值 |
| | |
| | | M3T: `${DOMAIN.DRONE}-${DRONE_TYPE.Mavic3EnterpriseAdvanced}-${DEVICE_SUB_TYPE.ONE}`, |
| | | |
| | | M300: `${DOMAIN.DRONE}-${DRONE_TYPE.M300}-${DEVICE_SUB_TYPE.ZERO}`, |
| | | M350: `${DOMAIN.DRONE}-${DRONE_TYPE.M350}-${DEVICE_SUB_TYPE.ZERO}`, |
| | | |
| | | FPV: `${DOMAIN.PAYLOAD}-${PAYLOAD_TYPE.FPV}-${DEVICE_SUB_TYPE.ZERO}`, |
| | | H20: `${DOMAIN.PAYLOAD}-${PAYLOAD_TYPE.H20}-${DEVICE_SUB_TYPE.ZERO}`, |
| | |
| | | [DEVICE_MODEL_KEY.M3T]: 'Mavic 3T', |
| | | // [DEVICE_MODEL_KEY.M3M]: 'Mavic 3M', |
| | | [DEVICE_MODEL_KEY.M300]: 'M300 RTK', |
| | | [DEVICE_MODEL_KEY.M350]: 'M350 RTK', |
| | | |
| | | // payload |
| | | [DEVICE_MODEL_KEY.FPV]: 'FPV', |
| | |
| | | M30 = '0-67-0' as any, |
| | | M30T = '0-67-1' as any, |
| | | M300 = '0-60-0' as any, |
| | | M350 = DEVICE_MODEL_KEY.M350 as any, |
| | | Z30 = '1-20-0' as any, |
| | | XT2 = '1-26-0' as any, |
| | | FPV = '1-39-0' as any, |
| | |
| | | y?: number; // 前进后退方向速度,正值为W指令 负值为S指令 单位:m/s |
| | | h?: number;// 上下高度值,正值为上升指令 负值为下降指令 单位:m |
| | | w?: number; // 机头角速度,正值为顺时针,负值为逆时针 单位:degree/s (web端暂无此设计) |
| | | step_x?: number; // 水平方向步长 |
| | | step_y?: number; // 前后方向步长 |
| | | step_h?: number; // 高度方向步长 |
| | | step_w?: number; // 机头转向步长 |
| | | seq?: number; // 从0计时 |
| | | freq?: number; // 指令发送频率 |
| | | delay_time?: number; // 指令从发送到设备端接收可容忍的时间 发送频率+链路传输时长 |
| | | } |
| | | |
| | | // 低延时osd |
| | |
| | | sdr_cmd_delay: number; // sdr链路命令延时,单位:ms |
| | | liveview_delay_list: LiveViewDelayItem[]; |
| | | } |
| | | |
| | | export interface DrcResponseInfo { |
| | | result: number; |
| | | output: { |
| | | seq: number |
| | | } |
| | | } |
| | |
| | | // 任务类型 |
| | | export enum TaskType { |
| | | Immediate = 0, // 立即执行 |
| | | Single = 1, // 单次定时任务 |
| | | Timed = 1, // 单次定时任务 |
| | | } |
| | | |
| | | export const TaskTypeMap = { |
| | | [TaskType.Immediate]: 'Immediate', |
| | | [TaskType.Single]: 'Timed & One-Time', |
| | | [TaskType.Timed]: 'Timed', |
| | | } |
| | | |
| | | export const TaskTypeOptions = [ |
| | | { value: TaskType.Immediate, label: TaskTypeMap[TaskType.Immediate] }, |
| | | { value: TaskType.Timed, label: TaskTypeMap[TaskType.Timed] }, |
| | | ] |
| | | |
| | | // 失控动作 |
| | | export enum OutOfControlAction { |
| | | ReturnToHome = 0, |