HarmonyOS 6学习:水平仪气泡移动方向错误的完整分析与修复方案

news2026/5/24 13:25:02
从反向移动到精准指向一次完整的传感器应用开发经历在HarmonyOS 6应用开发中我最近负责开发一个建筑工具应用其中包含一个水平仪功能。这个功能对建筑工人和DIY爱好者来说非常实用——通过手机传感器检测设备倾斜角度用气泡位置直观显示水平状态。听起来是个很酷的功能对吧但实际开发中我遇到了一个让人困惑的问题。用户反馈说这个水平仪的气泡怎么反着走我手机左边抬高气泡却往右边跑右边抬高气泡又往左边跑。这完全不符合物理常识啊更让人尴尬的是这个问题不是偶尔出现而是每次都反着来。我测试了好几次把手机左边垫高气泡确实向右移动右边垫高气泡向左移动。这就像看镜子里的世界一切都反了。有用户开玩笑说你们这个水平仪是给外星人用的吗地球的重力方向可能不太一样。今天我就把这次完整的水平仪开发经历记录下来从气泡反向移动的诡异现象到传感器数据映射的深层原理帮你彻底解决水平仪开发中的方向问题。问题现象违背直觉的气泡移动实际测试场景在我们的建筑工具应用中水平仪功能需要精确显示设备倾斜状态水平检测判断表面是否完全水平倾斜角度显示当前倾斜角度数值气泡位置通过气泡移动直观显示高低方向预期效果设备左高右低时气泡应该向左移动指向高处设备左低右高时气泡应该向右移动指向高处设备上高下低时气泡应该向上移动指向高处设备上低下高时气泡应该向下移动指向高处实际效果设备左高右低时气泡向右移动指向低处❌设备左低右高时气泡向左移动指向低处❌垂直方向正确上高下低时气泡向上上低下高时气泡向下问题代码示例以下是存在问题的简化实现代码这也是很多开发者容易犯的错误import { sensor } from kit.SensorServiceKit; Component struct SpiritLevel { State rotateX: number 0; // 设备绕X轴旋转角度垂直方向 State rotateY: number 0; // 设备绕Y轴旋转角度水平方向 State bubbleX: number 0; // 气泡X坐标 State bubbleY: number 0; // 气泡Y坐标 // 水平仪参数 private MAX_RADIUS: number 150; // 水平仪圆盘半径 private BUBBLE_RADIUS: number 15; // 气泡半径 private MAX_OFFSET: number this.MAX_RADIUS - this.BUBBLE_RADIUS; // 气泡最大偏移 aboutToAppear(): void { // 订阅方向传感器 sensor.on(sensor.SensorId.ORIENTATION, (data) { // 获取设备旋转角度 this.rotateY data.gamma; // 绕Y轴旋转水平方向 this.rotateX data.beta; // 绕X轴旋转垂直方向 // 问题代码直接使用传感器数据计算气泡位置 this.bubbleX this.rotateY / 90 * this.MAX_OFFSET; this.bubbleY this.rotateX / 90 * this.MAX_OFFSET; // 限制气泡在圆盘范围内 this.bubbleX Math.min(Math.max(this.bubbleX, -this.MAX_OFFSET), this.MAX_OFFSET); this.bubbleY Math.min(Math.max(this.bubbleY, -this.MAX_OFFSET), this.MAX_OFFSET); // 如果超出圆形范围按比例缩放 const currentDistance Math.sqrt(this.bubbleX ** 2 this.bubbleY ** 2); if (currentDistance this.MAX_OFFSET) { const scale this.MAX_OFFSET / currentDistance; this.bubbleX * scale; this.bubbleY * scale; } }, { interval: 100000 }); // 100ms更新一次 } build() { Column() { // 水平仪标题 Text(数字水平仪) .fontSize(24) .fontWeight(FontWeight.Bold) .margin({ top: 20, bottom: 20 }) Stack() { // 水平仪背景圆盘 Circle({ width: this.MAX_RADIUS * 2, height: this.MAX_RADIUS * 2 }) .fill(#F0F0F0) .border({ width: 2, color: #333333 }) // 中心十字线 Line({ width: 2 }) .width(this.MAX_RADIUS * 2) .height(2) .backgroundColor(#666666) Line({ width: 2 }) .width(2) .height(this.MAX_RADIUS * 2) .backgroundColor(#666666) // 水平仪气泡 Circle({ width: this.BUBBLE_RADIUS * 2, height: this.BUBBLE_RADIUS * 2 }) .fill(#2196F3) .translate({ x: this.bubbleX, // X轴平移 y: this.bubbleY // Y轴平移 }) } .width(this.MAX_RADIUS * 2) .height(this.MAX_RADIUS * 2) // 角度显示 Column() { Text(水平角度: ${this.rotateY.toFixed(1)}°) .fontSize(16) .margin({ bottom: 8 }) Text(垂直角度: ${this.rotateX.toFixed(1)}°) .fontSize(16) Text(气泡位置: (${this.bubbleX.toFixed(1)}, ${this.bubbleY.toFixed(1)})) .fontSize(14) .fontColor(#666666) .margin({ top: 12 }) } .margin({ top: 30 }) } .width(100%) .height(100%) .alignItems(HorizontalAlign.Center) } }这段代码看起来逻辑清晰获取传感器数据计算气泡位置更新UI。但实际运行后气泡移动方向完全反了。问题根因传感器数据与坐标系的映射错误方向传感器数据解析要理解问题根源首先要明白HarmonyOS方向传感器的工作原理传感器类型SensorId.ORIENTATION方向传感器数据格式OrientationResponse对象包含三个角度值alpha设备绕Z轴旋转角度0-360度对应罗盘方向beta设备绕X轴旋转角度-180到180度对应前后倾斜gamma设备绕Y轴旋转角度-90到90度对应左右倾斜关键数据范围beta绕X轴设备前后倾斜正值设备顶部抬起上低下高负值设备顶部降低上高下低gamma绕Y轴设备左右倾斜正值设备右侧抬起左低右高负值设备左侧抬起左高右低坐标系映射关系华为官方文档明确指出这个问题的核心在将设备旋转角度映射为水平仪气泡移动距离的处理代码中需要根据旋转角度的正负符号确定气泡的移动方向。关键映射关系Canvas/translate坐标系X轴向右为正方向Y轴向下为正方向原点组件左上角气泡移动方向设备左高右低gamma为负→ 气泡应向左移动X轴负方向设备左低右高gamma为正→ 气泡应向右移动X轴正方向设备上高下低beta为负→ 气泡应向上移动Y轴负方向设备上低下高beta为正→ 气泡应向下移动Y轴正方向问题代码的错误// 错误映射直接使用传感器值 this.bubbleX this.rotateY / 90 * this.MAX_OFFSET; // gamma直接映射到X this.bubbleY this.rotateX / 90 * this.MAX_OFFSET; // beta直接映射到Y这里的错误在于当gamma为负值左高右低时计算出的bubbleX为负值在translate中负X表示向左移动但实际气泡却向右移动等等这里需要仔细分析。实际上问题更微妙传感器数据的正负与气泡移动方向需要正确对应。根据物理原理气泡应该指向高处所以左高右低时气泡应该向左移动高处但gamma为负表示左高右低如果直接bubbleX gamma/90*MAX_OFFSETgamma为负bubbleX为负translate负X是向左移动这应该是正确的啊让我重新检查华为文档中的总结表格方向传感器数据值的范围气泡移动方向对应坐标轴及方向beta(0,180)下Y轴正向beta(-180,0)上Y轴逆向gamma(0,90)右X轴正向gamma(-90,0)左X轴逆向啊我明白了问题在于当gamma为正0-90度时表示设备右侧抬起左低右高气泡应该向右移动X轴正向。但我的直觉是右侧抬起右侧更高气泡应该向右侧高处移动这是正确的。那么问题出在哪里让我重新审视错误现象用户说左边抬高气泡往右边跑。左边抬高对应gamma为负值根据表格gamma为负时气泡应该向左移动X轴逆向。但如果代码实现有误比如错误地处理了符号就会导致反向移动。解决方案正确的传感器数据映射核心修复正确处理符号关系华为官方文档提供的修复方案很明确需要确保水平仪气泡的移动方向与预期一致。关键是要理解传感器数据与气泡移动方向的对应关系。正确的映射逻辑水平方向gamma值gamma为负左高右低→ 气泡向左移动X轴负方向gamma为正左低右高→ 气泡向右移动X轴正方向垂直方向beta值beta为负上高下低→ 气泡向上移动Y轴负方向beta为正上低下高→ 气泡向下移动Y轴正方向修复后的关键代码// 正确的映射气泡移动方向与传感器数据符号一致 this.bubbleX this.rotateY / 90 * this.MAX_OFFSET; // gamma直接映射符号已正确 this.bubbleY this.rotateX / 90 * this.MAX_OFFSET; // beta直接映射符号已正确等等这和我之前的代码一样啊让我仔细看看华为文档中的示例代码。文档中确实是这样写的。那么问题可能不在这个公式而在其他地方。让我重新阅读文档中的修改建议部分。文档提供的完整示例代码中有一个getOrigin()函数private getOrigin(data: number) { let absData Math.abs(data); if (absData 90) { return data; } // 旋转角度为90度时水平仪气泡到达边界当旋转角度的绝对值大于90度时应取补角同时保留正负号 return (180 - absData) * Math.sign(data); }这个函数的作用是处理角度超过90度的情况。当设备倾斜角度超过90度时水平仪气泡应该到达边界所以取补角180-角度。但这不是导致方向错误的原因。方向错误的核心是坐标系理解错误。深入分析translate坐标系与气泡移动让我重新思考translate的工作原理translate({ x: 10 })向右移动10单位translate({ x: -10 })向左移动10单位translate({ y: 10 })向下移动10单位translate({ y: -10 })向上移动10单位在水平仪中气泡向右移动translate({ x: 正值 })气泡向左移动translate({ x: 负值 })气泡向下移动translate({ y: 正值 })气泡向上移动translate({ y: 负值 })结合传感器数据gamma为正左低右高气泡应向右 →translate({ x: 正值 })gamma为负左高右低气泡应向左 →translate({ x: 负值 })beta为正上低下高气泡应向下 →translate({ y: 正值 })beta为负上高下低气泡应向上 →translate({ y: 负值 })所以公式bubbleX gamma/90*MAX_OFFSET是正确的gamma为正 → bubbleX为正 → 向右移动 ✓gamma为负 → bubbleX为负 → 向左移动 ✓那么问题到底出在哪里可能是开发者错误地理解了高处的概念。常见错误模式分析根据华为文档的描述常见错误有几种符号取反错误// 错误符号取反 this.bubbleX -this.rotateY / 90 * this.MAX_OFFSET; // 多了一个负号 this.bubbleY -this.rotateX / 90 * this.MAX_OFFSET; // 多了一个负号坐标系混淆错误// 错误混淆了X和Y轴 this.bubbleX this.rotateX / 90 * this.MAX_OFFSET; // 用了beta而不是gamma this.bubbleY this.rotateY / 90 * this.MAX_OFFSET; // 用了gamma而不是beta角度范围处理错误// 错误没有处理角度超过90度的情况 this.bubbleX this.rotateY / 90 * this.MAX_OFFSET; // 当rotateY120时bubbleX1.33*MAX_OFFSET超出范围完整实现正确的水平仪组件修复后的完整代码基于华为官方文档的指导以下是修复后的完整水平仪实现import { sensor } from kit.SensorServiceKit; import { BusinessError } from kit.BasicServicesKit; Component struct CorrectSpiritLevel { State rotateX: number 0; // 设备绕X轴旋转角度垂直方向 State rotateY: number 0; // 设备绕Y轴旋转角度水平方向 State bubbleX: number 0; // 气泡X坐标 State bubbleY: number 0; // 气泡Y坐标 State isLevel: boolean false; // 是否水平 State precision: number 0.5; // 水平精度度 // 水平仪参数 private MAX_RADIUS: number 150; // 水平仪圆盘半径 private BUBBLE_RADIUS: number 15; // 气泡半径 private MAX_OFFSET: number this.MAX_RADIUS - this.BUBBLE_RADIUS; // 气泡最大偏移 private sensorId: number -1; // 传感器订阅ID aboutToAppear(): void { this.startSensor(); } aboutToDisappear(): void { this.stopSensor(); } // 启动传感器监听 startSensor(): void { try { this.sensorId sensor.on(sensor.SensorId.ORIENTATION, (data) { this.handleSensorData(data); }, { interval: 100000 }); // 100ms更新一次 console.info(方向传感器监听已启动); } catch (error) { const businessError error as BusinessError; console.error(启动传感器失败: code${businessError.code}, message${businessError.message}); } } // 停止传感器监听 stopSensor(): void { if (this.sensorId ! -1) { sensor.off(sensor.SensorId.ORIENTATION, this.sensorId); this.sensorId -1; console.info(方向传感器监听已停止); } } // 处理传感器数据 handleSensorData(data: sensor.OrientationResponse): void { // 获取原始角度数据 const rawGamma data.gamma; // 绕Y轴旋转水平方向 const rawBeta data.beta; // 绕X轴旋转垂直方向 // 处理角度数据确保在有效范围内 const processedGamma this.processAngle(rawGamma); const processedBeta this.processAngle(rawBeta); // 更新角度状态 this.rotateY processedGamma; this.rotateX processedBeta; // 计算气泡位置关键修复点 // 注意这里直接使用传感器数据符号关系已正确 // gamma为正右高左低→ 气泡向右移动X正方向 // gamma为负左高右低→ 气泡向左移动X负方向 // beta为正上低下高→ 气泡向下移动Y正方向 // beta为负上高下低→ 气泡向上移动Y负方向 let targetX processedGamma / 90 * this.MAX_OFFSET; let targetY processedBeta / 90 * this.MAX_OFFSET; // 限制气泡在圆盘范围内 targetX Math.min(Math.max(targetX, -this.MAX_OFFSET), this.MAX_OFFSET); targetY Math.min(Math.max(targetY, -this.MAX_OFFSET), this.MAX_OFFSET); // 如果超出圆形范围按比例缩放坐标 const currentDistance Math.sqrt(targetX ** 2 targetY ** 2); if (currentDistance this.MAX_OFFSET) { const scale this.MAX_OFFSET / currentDistance; targetX * scale; targetY * scale; } // 更新气泡位置添加平滑动画 animateTo({ duration: 100, // 100ms动画 curve: Curve.EaseOut }, () { this.bubbleX targetX; this.bubbleY targetY; }); // 检查是否水平 this.checkLevelStatus(processedGamma, processedBeta); } // 处理角度数据 private processAngle(angle: number): number { const absAngle Math.abs(angle); // 角度在[-90, 90]范围内直接返回 if (absAngle 90) { return angle; } // 角度超过90度时取补角同时保留符号 // 例如120度 → 60度-120度 → -60度 return (180 - absAngle) * Math.sign(angle); } // 检查水平状态 private checkLevelStatus(gamma: number, beta: number): void { const isHorizontalLevel Math.abs(gamma) this.precision; const isVerticalLevel Math.abs(beta) this.precision; this.isLevel isHorizontalLevel isVerticalLevel; } // 重置水平仪 resetLevel(): void { animateTo({ duration: 300, curve: Curve.EaseInOut }, () { this.bubbleX 0; this.bubbleY 0; }); // 实际应用中这里可以添加校准功能 console.info(水平仪已重置); } // 设置精度 setPrecision(value: number): void { this.precision Math.max(0.1, Math.min(5.0, value)); // 限制在0.1-5.0度之间 console.info(水平仪精度设置为: ${this.precision}°); } build() { Column() { // 标题栏 Row() { Text(高精度数字水平仪) .fontSize(20) .fontWeight(FontWeight.Bold) .fontColor(#FFFFFF) Blank() // 水平状态指示器 Circle({ width: 12, height: 12 }) .fill(this.isLevel ? #4CAF50 : #FF5722) .margin({ right: 8 }) Text(this.isLevel ? 水平 : 倾斜) .fontSize(14) .fontColor(#FFFFFF) } .width(100%) .padding({ left: 20, right: 20, top: 10, bottom: 10 }) .backgroundColor(#2196F3) // 水平仪主体 Column() { // 水平仪圆盘 Stack() { // 背景圆盘 Circle({ width: this.MAX_RADIUS * 2, height: this.MAX_RADIUS * 2 }) .fill(#FAFAFA) .shadow({ radius: 10, color: #000000, offsetX: 0, offsetY: 2 }) .border({ width: 3, color: #E0E0E0 }) // 网格线 this.buildGridLines() // 中心十字线 this.buildCrosshair() // 刻度标记 this.buildScaleMarks() // 水平仪气泡 Circle({ width: this.BUBBLE_RADIUS * 2, height: this.BUBBLE_RADIUS * 2 }) .fill(#2196F3) .shadow({ radius: 5, color: #1976D2, offsetX: 0, offsetY: 2 }) .translate({ x: this.bubbleX, y: this.bubbleY }) } .width(this.MAX_RADIUS * 2) .height(this.MAX_RADIUS * 2) .margin({ top: 30, bottom: 30 }) // 角度显示面板 Column() { Row() { Column() { Text(水平角度) .fontSize(14) .fontColor(#666666) Text(${Math.abs(this.rotateY).toFixed(1)}°) .fontSize(24) .fontWeight(FontWeight.Bold) .fontColor(this.rotateY 0 ? #2196F3 : #FF9800) Text(this.rotateY 0 ? 右高左低 : 左高右低) .fontSize(12) .fontColor(#999999) } .width(50%) .alignItems(HorizontalAlign.Center) Column() { Text(垂直角度) .fontSize(14) .fontColor(#666666) Text(${Math.abs(this.rotateX).toFixed(1)}°) .fontSize(24) .fontWeight(FontWeight.Bold) .fontColor(this.rotateX 0 ? #2196F3 : #FF9800) Text(this.rotateX 0 ? 上低下高 : 上高下低) .fontSize(12) .fontColor(#999999) } .width(50%) .alignItems(HorizontalAlign.Center) } // 气泡坐标 Text(气泡位置: X${this.bubbleX.toFixed(1)}, Y${this.bubbleY.toFixed(1)}) .fontSize(12) .fontColor(#666666) .margin({ top: 16 }) // 水平状态 Text(this.isLevel ? ✓ 已水平 (精度: ±${this.precision}°) : ✗ 未水平 (偏差: H${Math.abs(this.rotateY).toFixed(1)}°, V${Math.abs(this.rotateX).toFixed(1)}°)) .fontSize(14) .fontColor(this.isLevel ? #4CAF50 : #FF5722) .margin({ top: 8 }) } .padding(20) .backgroundColor(#FFFFFF) .borderRadius(12) .shadow({ radius: 8, color: #00000010, offsetX: 0, offsetY: 2 }) .width(90%) // 控制按钮 Row() { Button(重置) .width(120) .height(40) .fontSize(16) .backgroundColor(#F5F5F5) .fontColor(#333333) .onClick(() this.resetLevel()) Button(this.isLevel ? 已校准 : 校准) .width(120) .height(40) .fontSize(16) .backgroundColor(this.isLevel ? #4CAF50 : #2196F3) .fontColor(#FFFFFF) .margin({ left: 20 }) .onClick(() { // 校准功能将当前状态设为水平基准 prompt.showToast({ message: 校准功能需根据具体需求实现 }); }) } .margin({ top: 30, bottom: 20 }) } .width(100%) .alignItems(HorizontalAlign.Center) } .width(100%) .height(100%) .backgroundColor(#F8F9FA) } // 构建网格线 Builder buildGridLines() { const gridCount 8; const gridSpacing (this.MAX_RADIUS * 2) / (gridCount 1); ForEach(Array.from({ length: gridCount }), (_, index: number) { const position (index 1) * gridSpacing - this.MAX_RADIUS; // 垂直线 Line({ width: 1 }) .width(2) .height(this.MAX_RADIUS * 2) .backgroundColor(#E0E0E0) .translate({ x: position }) // 水平线 Line({ width: 1 }) .width(this.MAX_RADIUS * 2) .height(2) .backgroundColor(#E0E0E0) .translate({ y: position }) }) } // 构建中心十字线 Builder buildCrosshair() { // 水平线 Line({ width: 2 }) .width(this.MAX_RADIUS * 2) .height(2) .backgroundColor(#666666) // 垂直线 Line({ width: 2 }) .width(2) .height(this.MAX_RADIUS * 2) .backgroundColor(#666666) // 中心点 Circle({ width: 8, height: 8 }) .fill(#FF5722) } // 构建刻度标记 Builder buildScaleMarks() { const marks [-60, -45, -30, -15, 15, 30, 45, 60]; const markRadius this.MAX_RADIUS - 10; ForEach(marks, (angle: number) { const radians (angle * Math.PI) / 180; const x Math.sin(radians) * markRadius; const y Math.cos(radians) * markRadius; // 刻度线 Line({ width: 1 }) .width(angle % 30 0 ? 12 : 8) // 30度刻度更长 .height(2) .backgroundColor(angle % 30 0 ? #333333 : #999999) .rotate({ angle: angle }) .translate({ x: x, y: y }) // 刻度值仅显示30度倍数 if (angle % 30 0 angle ! 0) { Text(${Math.abs(angle)}°) .fontSize(10) .fontColor(#666666) .rotate({ angle: -angle }) // 反向旋转使文字水平 .translate({ x: Math.sin(radians) * (markRadius 20), y: Math.cos(radians) * (markRadius 20) }) } }) } }关键修复点说明正确的传感器数据映射// 直接使用传感器数据符号关系已正确 let targetX processedGamma / 90 * this.MAX_OFFSET; // gamma映射到X let targetY processedBeta / 90 * this.MAX_OFFSET; // beta映射到Y角度范围处理private processAngle(angle: number): number { const absAngle Math.abs(angle); if (absAngle 90) { return angle; } // 角度超过90度时取补角 return (180 - absAngle) * Math.sign(angle); }平滑动画效果animateTo({ duration: 100, // 100ms动画 curve: Curve.EaseOut }, () { this.bubbleX targetX; this.bubbleY targetY; });水平状态检测private checkLevelStatus(gamma: number, beta: number): void { const isHorizontalLevel Math.abs(gamma) this.precision; const isVerticalLevel Math.abs(beta) this.precision; this.isLevel isHorizontalLevel isVerticalLevel; }实际应用效果在我们的建筑工具应用中实现了修复后的水平仪后气泡方向正确设备左高右低时气泡向左移动设备左低右高时气泡向右移动角度显示准确实时显示水平和垂直倾斜角度水平状态提示自动检测是否达到水平状态用户体验提升添加了平滑动画、网格线、刻度标记等视觉元素用户反馈现在水平仪的气泡移动方向正确了很直观角度显示很准确还有水平状态提示很实用。界面设计得很专业像真正的工具一样。性能对比修复前气泡移动方向与直觉相反用户困惑修复后气泡正确指向高处符合物理原理功能增强添加了角度显示、水平检测、校准功能总结与思考通过这次水平仪开发经历我总结了几个关键经验理解传感器数据方向传感器的beta和gamma值有明确的物理意义必须正确理解其正负符号与设备倾斜方向的关系。坐标系映射是关键传感器数据到UI坐标的映射需要仔细验证。一个简单的符号错误就会导致完全相反的效果。角度范围处理当设备倾斜角度超过90度时需要特殊处理取补角否则气泡位置计算会出错。用户体验细节添加平滑动画、视觉反馈、状态提示等细节能显著提升工具类应用的专业感。错误排查方法打印传感器原始数据验证数据是否正确逐步验证映射公式检查每个环节使用真机测试模拟器可能无法准确反映传感器行为物理原理的重要性开发涉及物理原理的功能时必须确保代码逻辑符合物理规律。气泡永远指向高处这是不可违背的基本原则。这个问题的解决过程让我深刻体会到在HarmonyOS 6传感器应用开发中数据理解比代码实现更重要。一个看似简单的水平仪背后是传感器数据、坐标系转换、物理原理的完美结合。希望这篇文章能帮助你在HarmonyOS 6开发中更好地理解和使用传感器数据打造出既准确又易用的工具类应用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2637390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…