当前位置:   article > 正文

Cesium 无人机航线规划_cesium 无人机巡检实时视频投射及模拟数据采集

cesium 无人机巡检实时视频投射及模拟数据采集

鉴于大疆司空平台和大疆无人机app高度绑定,导致很多东西没办法定制化。

从去年的时候就打算仿大疆开发一套完整的平台,包括无人机app以及仿司空2的管理平台,集航线规划、任务派发、实时图像、无人机管理等功能的平台。

当前阶段主要实现了:

1、无人机实时数据(包括视频、音频、拍照数据、位置信息以及无人机姿态)回传至web端,web端实时预览

2、web端实时编辑航线,编辑好的航线直接派发到无人机,无人机按照编辑航线进行作业;
3、......

后续我们还做了喊话、图像自动识别动功能

......

下面是基于Cesium开发的航线编辑功能,后面会对这个这个模块的实现进行记录,供大家参考。
当前我做的是三维空间的航线编辑,还有种方式是快速编辑(此处不做说明)。

简单操作说明:
航点编辑支持两种方式:键盘和鼠标点击。        
W -- 向前
S  -- 向后

A -- 向左

D -- 向右

并且相机姿态编辑,也支持键盘和鼠标操作:

⬆ --  镜头抬升
⬇  -- 镜头降低
⬅ -- 镜头左转
➡ -- 镜头右转

具体操作大家可以参考司空2的平台,后续我会将此功能放到线上,大家也可以体验。

后续我写完了,统一放出核心代码。当前仅作记录。

  1. // 根据距离计算位置
  2. computeByDistance(offset) {
  3. // 根据相机的heading 计算前后左右的朝向
  4. let heading = this.startMoveHeading;
  5. const center = Cesium.Matrix4.multiplyByPoint(this.localMtx_inverse, this.localCenter, new Cesium.Cartesian3());
  6. const x = (offset.a.val || 0) - (offset.d.val || 0);
  7. const y = (offset.w.val || 0) - (offset.s.val || 0);
  8. const directionX = Cesium.Cartesian3.multiplyByScalar(new Cesium.Cartesian3(1, 0, 0), -1 * x, new Cesium.Cartesian3());
  9. const directionY = Cesium.Cartesian3.multiplyByScalar(new Cesium.Cartesian3(0, 1, 0), y, new Cesium.Cartesian3());
  10. let newc = Cesium.Cartesian3.add(center, directionX, new Cesium.Cartesian3());
  11. newc = Cesium.Cartesian3.add(newc, directionY, new Cesium.Cartesian3());
  12. const rotationZ = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(-1 * heading || 0), new Cesium.Matrix3());
  13. newc = Cesium.Matrix3.multiplyByVector(rotationZ, newc.clone(), new Cesium.Cartesian3());
  14. const res = Cesium.Matrix4.multiplyByPoint(this.localMtx, newc.clone(), new Cesium.Cartesian3());
  15. return res;
  16. }
  17. computeHeadingPitch(offset) {
  18. const heading = (offset.ArrowRight.val || 0) - (offset.ArrowLeft.val || 0);
  19. const pitch = (offset.ArrowUp.val || 0) - (offset.ArrowDown.val || 0);
  20. return { heading, pitch }
  21. }

--------------------------------------------- 2024-04-17 更新 --------------------------------------------- 

这两天没写什么,主要新增了个方向罗盘

新增了相机范围显示功能,并且同步了相机窗口和主窗口的联动

当前在相机窗口进行鼠标按下拖动时,主窗口的锥体会同步进行运动,以下是核心代码:

  1. // viewer2 绑定鼠标事件,可通过鼠标控制镜头
  2. class ViewerClickHandler {
  3. constructor(viewer, opt) {
  4. this.viewer = viewer;
  5. this.opt = opt || {};
  6. this.startPX = undefined;
  7. this.handler = undefined;
  8. const dom = window.document.getElementById(this.viewer.container.id);
  9. this.width = dom.offsetWidth;
  10. this.height = dom.offsetHeight;
  11. // 禁止viewer的所有操作
  12. this.viewer.scene.screenSpaceCameraController.enableInputs = false;
  13. this.state = 'no'; // change end start
  14. this.bindHandler()
  15. }
  16. bindHandler() {
  17. if (!this.handler) this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
  18. this.handler.setInputAction((evt) => {
  19. // 初始化进入时,鼠标提示操作
  20. const px = evt.position;
  21. if (!this.startPX) {
  22. this.startPX = px;
  23. }
  24. if (this.opt.start) this.opt.start();
  25. this.state = 'start';
  26. }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
  27. this.handler.setInputAction((evt) => {
  28. // 初始化进入时,鼠标提示操作
  29. const px = evt.endPosition;
  30. if (!this.startPX) return;
  31. const heading = (px.x - this.startPX.x) * 30 / this.width;
  32. const pitch = - (px.y - this.startPX.y) * 30 / this.height;
  33. if (this.opt.change) this.opt.change(heading, pitch);
  34. this.state = 'change';
  35. }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  36. this.handler.setInputAction((evt) => {
  37. // 初始化进入时,鼠标提示操作
  38. if (this.startPX) {
  39. this.startPX = undefined;
  40. }
  41. if (this.opt.end) this.opt.end();
  42. this.state = 'end';
  43. }, Cesium.ScreenSpaceEventType.LEFT_UP);
  44. }
  45. destroy() {
  46. if (this.handler) this.handler.destroy();
  47. this.handler = undefined;
  48. this.state = 'no';
  49. }
  50. }
  51. // frustum和camera同步
  52. const combineCamera = {
  53. isactivate: false,
  54. frustum: undefined,
  55. viewer: undefined,
  56. viewer2: undefined,
  57. activate(frustum, viewer, viewer2) {
  58. if (!this.isactivate) {
  59. this.isactivate = true;
  60. this.frustum = frustum;
  61. this.viewer = viewer;
  62. this.viewer2 = viewer2;
  63. this.bindListener();
  64. }
  65. },
  66. disable() {
  67. if (this.isactivate) {
  68. this.isactivate = false;
  69. this.unbindListener();
  70. if (this.viewerHandler) {
  71. this.viewerHandler.destroy();
  72. this.viewerHandler = undefined;
  73. }
  74. }
  75. },
  76. removeCallback: undefined,
  77. removeCallback2: undefined,
  78. viewerHandler: undefined,
  79. bindListener() {
  80. const camera2 = this.viewer2.camera;
  81. if (!this.viewerHandler) {
  82. let initHeading, initPitch;
  83. this.viewerHandler = new ViewerClickHandler(this.viewer2, {
  84. start: () => {
  85. // 添加初始hp 防止每次都从0度方向开始
  86. initHeading = this.frustum.heading || 0;
  87. initPitch = this.frustum.pitch || 0;
  88. },
  89. change: (heading, pitch) => {
  90. // 修改viewer1中的椎体角度
  91. console.log(heading, this.frustum.heading + (heading || 0));
  92. this.frustum.update('', {
  93. heading: initHeading + heading,
  94. pitch: initPitch + pitch
  95. })
  96. // 修改当前视角
  97. camera2.flyTo({
  98. destination: this.frustum.position,
  99. orientation: {
  100. heading: Cesium.Math.toRadians(initHeading + heading || 0),
  101. pitch: Cesium.Math.toRadians(initPitch + pitch || 0),
  102. roll: 0
  103. },
  104. duration: 0
  105. });
  106. },
  107. end: () => {
  108. initHeading = undefined;
  109. initPitch = undefined;
  110. }
  111. })
  112. }
  113. this.removeCallback = this.viewer.scene.postRender.addEventListener(() => {
  114. if (this.viewerHandler && this.viewerHandler.state == 'change') return; // 操作视角时 不再通过此处来进行椎体同步
  115. // frustum ---> camera
  116. if(!this.frustum) return ;
  117. const heading = this.frustum?.heading;
  118. const pitch = this.frustum?.pitch;
  119. camera2.flyTo({
  120. destination: this.frustum.position,
  121. orientation: {
  122. heading: Cesium.Math.toRadians(heading || 0),
  123. pitch: Cesium.Math.toRadians(pitch || 0),
  124. roll: 0
  125. },
  126. duration: 0
  127. });
  128. }, false)
  129. },
  130. unbindListener() {
  131. if (this.removeCallback) {
  132. this.removeCallback();
  133. this.removeCallback = undefined;
  134. }
  135. }
  136. }

未完待续。。。。。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/583142
推荐阅读
相关标签
  

闽ICP备14008679号