☰
树莓派倾斜传感器实战:从滚珠开关到MPU6050倾角模块
2026/10/6 4:57:35 网站建设 项目流程

1. 倾斜传感器到底是个什么东西

第一次接触倾斜传感器是在一个云台项目里,当时需要让摄像头跟着臂架的俯仰角度自动调整姿态,一开始想用编码器算角度,但臂架本身有形变,编码器只能测电机转了多少圈,测不了真实的空间姿态。后来换用倾斜传感器,问题一下就简单了。从那时候起,我陆续在树莓派、STM32、Arduino几个平台上都折腾过倾斜传感器,踩了不少坑,也积累了一些实际经验,这里一并整理出来。

倾斜传感器,英文叫 Tilt Sensor 或者 Inclinometer,本质上是一种测量物体相对于水平面或重力方向倾斜角度的器件。它输出的可以是开关量(比如滚珠式倾斜开关,倾斜到一定角度就导通或断开),也可以是模拟量或数字量(比如基于加速度计原理的倾角模块,能读出具体的角度值)。前者便宜、简单,适合做倾倒报警、姿态检测这种“有或没有”的判断;后者精度高、能读数值,适合做云台调平、平台姿态监测、太阳能板追光这类需要连续角度反馈的场景。

这篇文章适合谁看?如果你正在做传感器课程设计、物联系统设计,或者单纯想在树莓派上接一个倾斜传感器玩玩,那这篇内容基本能覆盖你从选型、接线、写代码到调试排错的全部流程。我默认你手上有树莓派 4B 或者树莓派 5,系统是 Ubuntu 22.04 或者 Raspberry Pi OS,会基本的 Python 和 Linux 命令行操作。不会也没关系,关键步骤我都会写清楚。

先说一下我自己的硬件配置,方便你对照:树莓派 4B(4GB 版本),系统是 Ubuntu 22.04 LTS,倾斜传感器用的是常见的滚珠式倾斜开关模块(SW-520D)和基于加速度计的模拟倾角模块两种,后面会分别讲。滚珠式那个几块钱,模拟倾角模块二十来块,都很便宜,适合入门。

2. 倾斜传感器的核心原理与选型思路

2.1 滚珠式倾斜开关:最便宜的倾斜检测方案

滚珠式倾斜开关的结构特别简单,一个金属滚珠放在一个金属管内,管子一端或两端有触点。当传感器水平放置时,滚珠停在管子中间,不接触触点,电路断开;当传感器倾斜到一定角度,滚珠滚到一端,碰到触点,电路导通。就这么简单。

这种传感器的优点是便宜、皮实、不需要任何驱动电路,直接接树莓派的 GPIO 就能读。缺点是只能判断“倾斜超过某个角度”和“没超过”,读不出具体角度值,而且那个触发角度跟安装方向、滚珠大小都有关系,一致性一般。我实测过一批 SW-520D,标称触发角度是 10 度到 45 度之间,但实际每个的触发点都有差异,有的 15 度就触发,有的要 30 度。所以如果你要做精确角度测量,这个方案不合适;但如果只是做“倒了没倒”的判断,比如设备倾倒报警、箱子被翻动检测,那它完全够用,而且成本极低。

选型的时候注意一点:滚珠式倾斜开关有常开和常闭两种。常开的意思是平时断开、倾斜时导通;常闭反过来。买的时候看清楚,不然代码逻辑要反过来写。我一般用常开的,因为接树莓派 GPIO 的时候,平时是高电平(通过上拉电阻),倾斜时被拉到低电平,逻辑比较直观。

2.2 基于加速度计的倾角模块:能读具体角度

如果你需要读出具体的倾斜角度,那就得用加速度计原理的倾角模块。常见的有基于 MPU6050、ADXL345、MMA7361 这些芯片的模块。它们内部是三轴加速度计,通过测量重力加速度在三个轴上的分量,反算出物体相对于水平面的倾斜角度。

原理其实不难理解。想象你手里拿一个球放在一个平面上,平面水平时,球受到的重力全部垂直于平面,水平方向没有分量;平面倾斜时,重力在水平方向就有了分量,倾斜角度越大,水平分量越大。加速度计就是测这个分量的。具体计算的时候,如果是单轴倾斜,角度 θ = arcsin(ax / g),其中 ax 是加速度计在倾斜方向上的读数,g 是重力加速度(约 9.8 m/s²)。如果是双轴倾斜,可以用 θ = arctan(ax / sqrt(ay² + az²)) 这样的公式来算。

这里有个细节要注意:加速度计测倾角,在静态或低速运动时很准,但如果物体本身在加速运动,加速度计会把运动加速度和重力加速度混在一起,算出来的角度就不准了。所以如果你的应用场景里物体本身有较大的加速度(比如车载、机械臂快速运动),要么用陀螺仪做融合(这就是 MPU6050 这类六轴传感器的价值),要么就得接受一定的误差。我那个云台项目里,臂架运动比较慢,所以直接用加速度计算倾角就够了,没上融合算法。

2.3 树莓派上怎么选:GPIO 直读还是 I2C 读取

在树莓派上接倾斜传感器,有两条路。一条是滚珠式开关直接接 GPIO,用 Python 的 RPi.GPIO 或者 gpiozero 库读引脚电平,简单直接。另一条是加速度计模块通过 I2C 或 SPI 接树莓派,用 Python 的 smbus 或者专门库(比如 mpu6050-raspberrypi)读原始数据再换算角度。

我建议新手先从滚珠式开关入手,因为接线简单、代码短、不需要装额外库,十分钟就能跑通。等把 GPIO 读写、中断、去抖动这些基本操作搞明白了,再上加速度计模块。这样学习曲线比较平缓,不容易一上来就被 I2C 地址、寄存器配置这些东西劝退。

树莓派 4B 和树莓派 5 的 GPIO 引脚定义基本兼容,40 针的排针布局一样。但树莓派 5 的 GPIO 底层驱动换了新的芯片,如果你用 gpiozero 库,大部分情况下代码不用改;如果用 RPi.GPIO,树莓派 5 上可能要用 rpi-lgpio 这个兼容层。我实测下来,gpiozero 在树莓派 4B 和 5 上都能正常工作,推荐优先用它。

3. 硬件接线与实操步骤

3.1 滚珠式倾斜开关接树莓派 GPIO

先说滚珠式开关的接线。SW-520D 模块一般有三个引脚:VCC、GND、DO(数字输出)。有的模块还有 AO(模拟输出),但滚珠式开关本身是开关量,AO 其实也是通过分压得到的,意义不大。接线很简单:

  • 模块 VCC 接树莓派 3.3V(物理引脚 1 或 17)
  • 模块 GND 接树莓派 GND(物理引脚 6、9、14、20、25、30、34、39 任意一个)
  • 模块 DO 接树莓派任意一个 GPIO,比如 GPIO17(物理引脚 11)

这里有个坑要注意:树莓派的 GPIO 是 3.3V 电平,绝对不能接 5V,否则可能烧掉 GPIO 甚至整块板子。有些倾斜开关模块标称工作电压 3.3V 到 5V,接 3.3V 完全没问题。但如果你买的是裸的滚珠开关(不是模块),那就需要自己加一个上拉或下拉电阻。我一般用 10kΩ 上拉电阻接 3.3V,开关另一端接 GND,这样平时 GPIO 读到高电平,倾斜时读到低电平。

接线的时候,树莓派一定要断电。我见过有人带电插拔杜邦线,结果不小心碰到旁边引脚,直接把 GPIO 烧了。虽然树莓派 GPIO 有一定的保护,但别赌这个概率。断电接线、检查无误再上电,这是基本习惯。

3.2 加速度计倾角模块接树莓派 I2C

加速度计模块以 MPU6050 为例,接线稍微多一点,但也不复杂。MPU6050 模块一般有 8 个引脚:VCC、GND、SCL、SDA、XDA、XCL、AD0、INT。我们只需要用前四个:

  • VCC 接树莓派 3.3V
  • GND 接树莓派 GND
  • SCL 接树莓派 GPIO3(物理引脚 5,I2C1 SCL)
  • SDA 接树莓派 GPIO2(物理引脚 3,I2C1 SDA)

AD0 引脚决定 I2C 地址:接 GND 时地址是 0x68,接 VCC 时是 0x69。如果你只接一个 MPU6050,AD0 接 GND 就行。INT 引脚是中断输出,一般不用接,除非你要做中断触发读取。

接好线之后,需要在树莓派上启用 I2C。在 Raspberry Pi OS 里,用 raspi-config 命令,进 Interface Options,把 I2C 打开。在 Ubuntu 22.04 里,I2C 默认可能是关的,需要手动改配置。具体操作是编辑 /boot/firmware/config.txt(树莓派 4B 的 Ubuntu 22.04 是这个路径,老版本可能是 /boot/config.txt),加上一行 dtparam=i2c_arm=on,然后重启。重启后用 ls /dev/i2c* 看看有没有 i2c-1 设备,再用 i2cdetect -y 1 扫描一下,如果看到 0x68 就说明模块被识别了。

这里有个常见问题:i2cdetect 扫不到设备。原因通常是接线松了、SDA 和 SCL 接反了、或者模块供电不对。我遇到过好几次都是杜邦线接触不良,尤其是那种便宜的杜邦线,插上去看着挺紧,其实里面没接触上。换一根线或者用万用表量一下通断,基本能解决。

3.3 树莓派系统准备与依赖安装

不管你用哪种传感器,树莓派上的软件环境都要先准备好。我习惯用 Ubuntu 22.04,因为跟服务器环境一致,后面部署方便。树莓派 4B 装 Ubuntu 22.04 的流程这里不展开,网上教程很多,注意选对镜像(raspi 版本,不是 desktop 版本,除非你要图形界面)。

系统装好后,先更新一下源。Ubuntu 22.04 在树莓派上的默认源速度一般,可以换成国内源,这个网上也有现成脚本。更新命令:

sudo apt update sudo apt upgrade -y

然后装 Python 相关的依赖。如果你用 gpiozero:

sudo apt install python3-gpiozero python3-pigpio -y

如果你用 smbus 读 I2C:

sudo apt install python3-smbus i2c-tools -y

如果你用 MPU6050 的专用库,可以用 pip 装:

pip3 install mpu6050-raspberrypi

注意,Ubuntu 22.04 默认的 Python 是 3.10,pip 装包的时候如果提示 externally-managed-environment,需要加 --break-system-packages 参数,或者用 apt 装对应的 python3-xxx 包。我一般优先用 apt,实在没有再 pip。

4. 代码实现与调试

4.1 滚珠式倾斜开关的 Python 读取代码

先上滚珠式开关的代码,用 gpiozero 库,简洁明了:

from gpiozero import Button from time import sleep # 倾斜开关接在 GPIO17,上拉电阻启用 tilt_sensor = Button(17, pull_up=True, bounce_time=0.1) def tilted(): print("检测到倾斜!") def level(): print("恢复水平") tilt_sensor.when_pressed = tilted tilt_sensor.when_released = level print("倾斜传感器监测中,按 Ctrl+C 退出") try: while True: sleep(1) except KeyboardInterrupt: print("退出")

这段代码里,Button 类默认是上拉,所以开关一端接 GPIO17,另一端接 GND。bounce_time=0.1 是去抖动时间,因为滚珠开关在临界角度时可能会快速通断,产生抖动。0.1 秒的去抖在实际测试中效果不错,既能滤掉抖动,又不会太迟钝。

如果你不用中断,也可以用轮询的方式:

from gpiozero import Button from time import sleep tilt_sensor = Button(17, pull_up=True, bounce_time=0.1) while True: if tilt_sensor.is_pressed: print("倾斜") else: print("水平") sleep(0.5)

轮询方式简单,但会占用 CPU 时间,而且响应没那么及时。中断方式更优雅,推荐用中断。

4.2 加速度计倾角模块的角度计算代码

MPU6050 的代码稍微复杂一点。如果你用 mpu6050-raspberrypi 库,读取原始数据很简单:

from mpu6050 import mpu6050 import math import time sensor = mpu6050(0x68) def read_angle(): accel = sensor.get_accel_data() ax = accel['x'] ay = accel['y'] az = accel['z'] # 计算绕 Y 轴和 X 轴的倾角 angle_x = math.atan2(ay, math.sqrt(ax**2 + az**2)) * 180 / math.pi angle_y = math.atan2(ax, math.sqrt(ay**2 + az**2)) * 180 / math.pi return angle_x, angle_y while True: ax_angle, ay_angle = read_angle() print(f"X轴倾角: {ax_angle:.2f} 度, Y轴倾角: {ay_angle:.2f} 度") time.sleep(0.5)

这里用的是 atan2 加 sqrt 的公式,比单纯的 arcsin 更稳定,因为当某个轴接近 ±90 度时,arcsin 会出现数值问题。atan2 的好处是能处理所有象限,输出范围是 -180 到 180 度。

实际测试的时候,模块平放,读出来的角度应该在 0 度附近,可能有 ±1 到 ±2 度的偏差,这是正常的,因为模块本身有零偏,而且手工焊接的模块不一定完全水平。如果要更准,可以做零偏校准:平放时读一组数据取平均,作为零点偏移,后面读数都减去这个偏移。

4.3 数据滤波:让角度读数更稳定

加速度计原始数据会有噪声,读出来的角度会跳。我实测 MPU6050 静止时,角度波动大概在 ±0.5 度左右,如果对稳定性要求高,需要做滤波。最简单的是一阶低通滤波:

alpha = 0.8 filtered_angle = alpha * filtered_angle + (1 - alpha) * new_angle

alpha 越大,滤波效果越强,但响应越慢。我一般取 0.8 到 0.95 之间,根据实际需求调。如果要做更平滑的效果,可以用滑动平均,取最近 N 次读数的平均值。N 取 10 到 20 比较合适,再多就太迟钝了。

还有一个办法是用 MPU6050 内置的 DMP(数字运动处理器),它内部做了传感器融合,直接输出姿态角,比我们自己算的准。但 DMP 的配置比较麻烦,需要加载固件、配置寄存器,代码量大很多。如果你的项目对角度精度要求很高,比如云台稳定,那值得上 DMP;如果只是做课程设计或者简单监测,自己算就够了。

5. 常见问题与排查技巧

5.1 倾斜开关一直触发或不触发

这是最常见的问题。先检查接线:VCC 和 GND 有没有接反,DO 有没有接对 GPIO。然后用万用表量一下开关两端的通断,倾斜时应该导通,水平时断开。如果开关本身没问题,那就是代码里的上拉/下拉设置不对。gpiozero 的 Button 默认是上拉,如果你的模块是常闭型,那逻辑就反了,需要把 pull_up 改成 False,或者用 Button(17, pull_up=False)。

还有一种情况是触发角度不对。滚珠开关的触发角度跟安装方向有关,如果你把开关横着装,可能永远触发不了。我建议先把开关拿在手里,慢慢倾斜,看什么时候导通,找到触发方向后再固定安装。

5.2 I2C 设备扫描不到

前面提过,先查接线。SDA 和 SCL 接反是最常见的错误,很多人看引脚图的时候看串行了。树莓派 4B 的物理引脚 3 是 SDA,5 是 SCL,别搞混。然后确认 I2C 有没有启用,用 lsmod | grep i2c 看看 i2c_bcm2835 模块有没有加载。如果没有,说明配置没生效,检查 config.txt 里的 dtparam=i2c_arm=on 有没有写对,写完要重启。

如果接线和配置都没问题,还是扫不到,那可能是模块坏了。我买到过一批便宜的 MPU6050 模块,有一半是坏的,I2C 完全没反应。换一个模块试试,如果换了就好,那就是模块问题。

5.3 角度读数跳动大或不准

先做零偏校准,平放取平均。如果校准后还是跳,检查电源是否稳定。树莓派的 3.3V 输出在带多个传感器时可能会有波动,尤其是用 USB 供电且电流不足的时候。可以试试给树莓派单独供电,或者用外部 3.3V 稳压模块给传感器供电。

另外,MPU6050 对振动很敏感,如果传感器装在振动的平台上,读数会乱跳。这种情况下要么加机械减震(比如用橡胶垫),要么用软件滤波把高频振动滤掉。我那个云台项目里,臂架运动时振动不大,所以软件滤波就够了。

5.4 树莓派 GPIO 被占用或权限不足

用 gpiozero 的时候,如果提示 GPIO 被占用,可能是之前运行的脚本没退出干净。用 ps aux | grep python 看看有没有残留进程,有就 kill 掉。权限方面,gpiozero 默认用 pigpio 后端需要 root 权限,或者把用户加到 gpio 组。Ubuntu 22.04 上,默认用户一般在 gpio 组里,如果没有,用 sudo usermod -aG gpio $USER 加一下,然后重新登录。

还有一个坑是树莓派 5 的 GPIO 兼容性。树莓派 5 换了新的 GPIO 芯片,RPi.GPIO 库在树莓派 5 上不能直接用,需要装 rpi-lgpio 兼容层,或者直接用 gpiozero。我实测 gpiozero 在树莓派 5 上工作正常,所以如果你用树莓派 5,建议直接用 gpiozero,省得折腾。

6. 实际项目中的应用与扩展

6.1 云台自动调平:倾斜传感器加舵机

回到开头提到的云台项目。需求是让摄像头跟着臂架俯仰自动调整角度,保持摄像头始终水平。方案是:倾斜传感器(MPU6050)装在摄像头上,实时读俯仰角;树莓派根据角度偏差,控制舵机反向转动,抵消倾斜。控制逻辑用简单的比例控制就行:

target_angle = 0 # 目标水平 kp = 2.0 # 比例系数 while True: current_angle, _ = read_angle() error = target_angle - current_angle servo_angle = kp * error # 限制舵机角度范围 servo_angle = max(-90, min(90, servo_angle)) set_servo(servo_angle) time.sleep(0.05)

kp 的取值需要实际调试,太大容易震荡,太小响应慢。我一般从 1.0 开始试,慢慢加。舵机用树莓派的 PWM 控制,gpiozero 里有 Servo 类,很方便。树莓派 Pico 控制舵机也很常见,Pico 的 PWM 更稳定,适合做实时控制。

6.2 倾倒报警:倾斜开关加蜂鸣器

另一个简单项目是倾倒报警。设备上装一个滚珠式倾斜开关,一旦倾斜超过阈值,树莓派触发蜂鸣器报警,同时通过 MQTT 发消息到服务器。这个方案成本极低,一个倾斜开关几块钱,一个蜂鸣器几块钱,树莓派用 Zero 或者 4B 都行。

代码逻辑就是前面滚珠开关的代码加一个蜂鸣器控制:

from gpiozero import Button, Buzzer tilt = Button(17, pull_up=True, bounce_time=0.1) buzzer = Buzzer(18) def alarm(): buzzer.on() print("倾倒报警!") def normal(): buzzer.off() tilt.when_pressed = alarm tilt.when_released = normal

这个项目适合做物联系统设计的课程作业,涉及传感器读取、GPIO 控制、网络通信,知识点比较全。

6.3 太阳能板追光:倾角加光敏

太阳能板追光系统里,倾角传感器用来监测板的俯仰角,光敏传感器(或者辐照度传感器)用来判断哪个方向光强最大。两者结合,树莓派控制两个舵机(一个水平旋转,一个俯仰),让太阳能板始终对准光源。这个项目里,倾角传感器的作用是提供俯仰角的闭环反馈,确保舵机转到目标角度后,板子确实到了那个角度,而不是因为机械间隙或负载导致偏差。

光敏传感器可以用光电传感器模块,也可以用 TDS 传感器那种模拟输出的,接树莓派的 ADC(树莓派本身没有 ADC,需要外接 MCP3008 这类芯片)。这个项目复杂度高一些,但做出来很有成就感,适合作为毕业设计或者课程设计的大作业。

6.4 与编码器配合:更精确的姿态控制

如果对角度精度要求极高,比如医疗设备或者精密仪器,单靠倾斜传感器可能不够。这时候可以倾斜传感器加编码器融合。编码器测电机的转动角度,精度高、响应快,但会有累积误差;倾斜传感器测绝对姿态,没有累积误差,但噪声大、响应慢。两者融合,用互补滤波或者卡尔曼滤波,能得到又准又稳的角度。

互补滤波的公式很简单:

angle = 0.98 * (angle + gyro_rate * dt) + 0.02 * accel_angle

这里 gyro_rate 是陀螺仪角速度,accel_angle 是加速度计算的倾角。0.98 和 0.02 是权重,根据实际调试调整。这个方案在云台、平衡车、无人机里都很常见,树莓派算力足够跑。

7. 几个我踩过的坑和实操心得

第一个坑是杜邦线的质量。我一开始图便宜买了一大包杜邦线,结果接 I2C 的时候死活扫不到设备,换了三根线才好。后来我学乖了,关键连接都用万用表量一下通断,或者直接焊死。尤其是 I2C 这种对信号质量敏感的接口,线材和接触电阻影响很大。

第二个坑是电源。树莓派用 USB 供电的时候,如果同时带多个传感器和舵机,3.3V 和 5V 的电压可能会被拉低,导致传感器工作不稳定。我后来给舵机单独供电,树莓派只负责信号,问题就解决了。舵机的电流冲击很大,尤其是堵转的时候,直接从树莓派取电很容易导致树莓派重启。

第三个坑是安装方向。倾斜传感器的安装方向决定了读数的正负和轴对应关系。我一开始没注意,装上去之后发现角度是反的,调了半天代码才发现是安装方向的问题。后来我养成习惯,装之前先在手里转一圈,确认哪个方向对应哪个轴,再固定。

第四个坑是温度漂移。MPU6050 这类 MEMS 传感器对温度比较敏感,长时间工作后零偏会漂。如果项目要求高,要么做温度补偿,要么定期重新校准。我那个云台项目连续跑几个小时,角度会慢慢偏个一两度,后来加了定期校准(每半小时平放一次重新取零偏),才稳定下来。

第五个坑是树莓派 5 的 GPIO 库兼容性。我一开始在树莓派 5 上用 RPi.GPIO,代码跑不起来,报错说找不到模块。后来查了才知道树莓派 5 换了 GPIO 芯片,RPi.GPIO 不兼容,要装 rpi-lgpio 或者用 gpiozero。这个坑花了我一个下午,希望你别再踩。

最后分享一个小技巧:调试倾斜传感器的时候,用 Python 的 matplotlib 实时画角度曲线,比看打印数字直观得多。树莓派上装 matplotlib 稍微麻烦点,但跑起来之后,角度变化一目了然,调滤波参数的时候特别有用。如果树莓派性能不够,可以把数据通过串口或者网络发到电脑上画,效果一样。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询