1确虱、Nano I2C 硬件
Nano 七組硬件I2C 總線及對應(yīng)關(guān)系: (分別有1.8V和3.3V)
2、Jetson Nano + IMU (MPU6050)
慣性測量單元(IMU)是一種電子設(shè)備,它使用加速度計(jì)和陀螺儀(有些搭配磁場傳感器件)組合來測量和報(bào)告當(dāng)前設(shè)備的速度涝开、方向和重力信息踊谋。
硬件連接 (Nano+MPU6050)
1.VCC ---接Nano引腳第17腳; (接 5V 非3.3V)
2.GND ---接Nano 引腳第25腳;
3.SCL ---接Nano 引腳第5腳(GEN2_I2C_SCL),電平已轉(zhuǎn)換成3.3V電平;
4.SDA ---接Nano 引腳第3腳(GEN2_I2C_SDA),電平已轉(zhuǎn)換成3.3V電平;
軟件配置
默認(rèn)Nano L4T 的內(nèi)核Kernel Image已包含了MPU6050 I2C Driver筝家,不需要修改Kernel 代碼轧钓, 但需要修改DTS 以支持MPU6050對應(yīng)I2C和寄存器配置序厉!
hardware\nvidia\platform\t210\porg\kernel-dts\tegra210-porg-p3448-common.dtsi
根據(jù)硬件連接修改如下:
1、去掉/*#include "porg-platforms/tegra210-porg-super-module-e2614.dtsi"*/
2毕箍、添加
i2c@7000c400 { /*bus1 */
tw_icm20628: icm20628@68 {
compatible = "invensense,mpu6xxx";
reg = <0x68>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(Z, 0) 0x01>;
accelerometer_matrix= [01 00 00 00 01 00 00 00 01];
gyroscope_matrix = [01 00 00 00 01 00 00 00 01];
geomagnetic_rotation_vector_disable = <1>;
gyroscope_uncalibrated_disable = <1>;
quaternion_disable = <1>;
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
vcc-supply = <&p3448_vdd_3v3_sys>;
vcc-pullup-supply = <&p3448_vdd_3v3_sys>;
};
};
3弛房、燒錄dtb 文件
sudo ./flash.sh -r -k DTB jetson-nano-qspi-sd mmcblk0p1
4、檢查I2C 設(shè)備 (可查看dmesg log), 若顯示UU而柑,則參考附錄中的說明文捶,檢查I2C 的DTS 配置是否有地址相同設(shè)備!
nvidia@tw-nano:~$ sudo i2cdetect -y -r 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
5媒咳、i2c-tools 讀寫是否成功以驗(yàn)證設(shè)備連接
sudo i2cdump -f -y 1 0x86
sudo i2cget -y 1 0x68 0x41 (TEMPERATURE-OUT0)
PS: MPU6050 特性及應(yīng)用
- MPU-6000(6050)的角速度測量范圍為±250粹排、±500、±1000與±2000°/sec (dps)涩澡,可準(zhǔn)確追蹤快速與慢速動作顽耳;
- MPU-6000(6050)的加速器測量范圍為±2g、±4g±8g與±16g妙同;
- 以數(shù)字輸出6軸或9軸的旋轉(zhuǎn)矩陣射富、四元數(shù)(quaternion)、歐拉角格式(Euler Angle forma)的融合演算數(shù)據(jù)
- 數(shù)字運(yùn)動處理(DMP: Digital Motion Processing)引擎可減少復(fù)雜的融合演算數(shù)據(jù)粥帚、感測器同步化胰耗、姿勢感應(yīng)等的負(fù)荷
- 通訊采用400kHz的IIC或最高達(dá)20MHz的SPI(MPU-6050沒有SPI);
- MPU-6000(6050)可在不同電壓下工作茎辐,VDD供電為2.5V±5%宪郊、3.0V±5%或3.3V±5%,邏輯接口VDDIO供電為1.8V± 5%(MPU6000僅用VDD);
- 應(yīng)用場景:姿勢識別拖陆、遙控拍攝弛槐、畫面放大縮小、滾動依啰、快速下降中斷乎串、high-G中斷、零動作感應(yīng)速警、觸擊感應(yīng)叹誉、搖動感應(yīng)功能等等
3、 Python + I2C 讀取陀螺儀數(shù)據(jù)
Step1. 獲取用戶對I2C總線操作權(quán)限 (ex. nvidia as the login name)
$sudo usermod -aG i2c $USER
sudo usermod -aG i2c nvidia
--- 重啟系統(tǒng)確保更改I2C等有效 ---
Step2. MPU6050 運(yùn)行結(jié)果如下:
jetbot@jetbot:~/work/mpu-6050-Python$ python3 example.py
Accelerometer data
x: -7.570465649414062
y: 6.232106921386718
z: 0.7589619262695312
Gyroscope data
x: 1.5801526717557253
y: 3.2900763358778624
z: 0.6793893129770993
Temp: 44.906470588235294oC
Accelerometer data
x: -7.615955480957031
y: 6.241683728027343
z: 0.6344634399414062
Gyroscope data
x: 1.6870229007633588
y: 3.3969465648854964
z: 1.1984732824427482
Temp: 45.00058823529412oC
Step3. Python example案例代碼
"""This program handles the communication over I2C
between a Jetson Nano and a MPU-6050 Gyroscope / Accelerometer combo.
Made by: Dennis/TW
Released under the MIT License
Copyright 2019
"""
import smbus
class mpu6050:
# Global Variables
GRAVITIY_MS2 = 9.80665
address = None
bus = smbus.SMBus(1)
# Scale Modifiers
ACCEL_SCALE_MODIFIER_2G = 16384.0
ACCEL_SCALE_MODIFIER_4G = 8192.0
ACCEL_SCALE_MODIFIER_8G = 4096.0
ACCEL_SCALE_MODIFIER_16G = 2048.0
GYRO_SCALE_MODIFIER_250DEG = 131.0
GYRO_SCALE_MODIFIER_500DEG = 65.5
GYRO_SCALE_MODIFIER_1000DEG = 32.8
GYRO_SCALE_MODIFIER_2000DEG = 16.4
# Pre-defined ranges
ACCEL_RANGE_2G = 0x00
ACCEL_RANGE_4G = 0x08
ACCEL_RANGE_8G = 0x10
ACCEL_RANGE_16G = 0x18
GYRO_RANGE_250DEG = 0x00
GYRO_RANGE_500DEG = 0x08
GYRO_RANGE_1000DEG = 0x10
GYRO_RANGE_2000DEG = 0x18
# MPU-6050 Registers
PWR_MGMT_1 = 0x6B
PWR_MGMT_2 = 0x6C
SELF_TEST_X = 0x0D
SELF_TEST_Y = 0x0E
SELF_TEST_Z = 0x0F
SELF_TEST_A = 0x10
ACCEL_XOUT0 = 0x3B
ACCEL_XOUT1 = 0x3C
ACCEL_YOUT0 = 0x3D
ACCEL_YOUT1 = 0x3E
ACCEL_ZOUT0 = 0x3F
ACCEL_ZOUT1 = 0x40
TEMP_OUT0 = 0x41
TEMP_OUT1 = 0x42
GYRO_XOUT0 = 0x43
GYRO_XOUT1 = 0x44
GYRO_YOUT0 = 0x45
GYRO_YOUT1 = 0x46
GYRO_ZOUT0 = 0x47
GYRO_ZOUT1 = 0x48
ACCEL_CONFIG = 0x1C
GYRO_CONFIG = 0x1B
def __init__(self, address):
self.address = address
# Wake up the MPU-6050 since it starts in sleep mode
self.bus.write_byte_data(self.address, self.PWR_MGMT_1, 0x00)
# I2C communication methods
def read_i2c_word(self, register):
"""Read two i2c registers and combine them.
register -- the first register to read from.
Returns the combined read results.
"""
# Read the data from the registers
high = self.bus.read_byte_data(self.address, register)
low = self.bus.read_byte_data(self.address, register + 1)
value = (high << 8) + low
if (value >= 0x8000):
return -((65535 - value) + 1)
else:
return value
# MPU-6050 Methods
def get_temp(self):
"""Reads the temperature from the onboard temperature sensor of the MPU-6050.
Returns the temperature in degrees Celcius.
"""
# Get the raw data
raw_temp = self.read_i2c_word(self.TEMP_OUT0)
# Get the actual temperature using the formule given in the
# MPU-6050 Register Map and Descriptions revision 4.2, page 30
actual_temp = (raw_temp / 340) + 36.53
# Return the temperature
return actual_temp
def set_accel_range(self, accel_range):
"""Sets the range of the accelerometer to range.
accel_range -- the range to set the accelerometer to. Using a
pre-defined range is advised.
"""
# First change it to 0x00 to make sure we write the correct value later
self.bus.write_byte_data(self.address, self.ACCEL_CONFIG, 0x00)
# Write the new range to the ACCEL_CONFIG register
self.bus.write_byte_data(self.address, self.ACCEL_CONFIG, accel_range)
def read_accel_range(self, raw = False):
"""Reads the range the accelerometer is set to.
If raw is True, it will return the raw value from the ACCEL_CONFIG
register
If raw is False, it will return an integer: -1, 2, 4, 8 or 16. When it
returns -1 something went wrong.
"""
# Get the raw value
raw_data = self.bus.read_byte_data(self.address, self.ACCEL_CONFIG)
if raw is True:
return raw_data
elif raw is False:
if raw_data == self.ACCEL_RANGE_2G:
return 2
elif raw_data == self.ACCEL_RANGE_4G:
return 4
elif raw_data == self.ACCEL_RANGE_8G:
return 8
elif raw_data == self.ACCEL_RANGE_16G:
return 16
else:
return -1
def get_accel_data(self, g = False):
"""Gets and returns the X, Y and Z values from the accelerometer.
If g is True, it will return the data in g
If g is False, it will return the data in m/s^2
Returns a dictionary with the measurement results.
"""
# Read the data from the MPU-6050
x = self.read_i2c_word(self.ACCEL_XOUT0)
y = self.read_i2c_word(self.ACCEL_YOUT0)
z = self.read_i2c_word(self.ACCEL_ZOUT0)
accel_scale_modifier = None
accel_range = self.read_accel_range(True)
if accel_range == self.ACCEL_RANGE_2G:
accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_2G
elif accel_range == self.ACCEL_RANGE_4G:
accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_4G
elif accel_range == self.ACCEL_RANGE_8G:
accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_8G
elif accel_range == self.ACCEL_RANGE_16G:
accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_16G
else:
print("Unkown range - accel_scale_modifier set to self.ACCEL_SCALE_MODIFIER_2G")
accel_scale_modifier = self.ACCEL_SCALE_MODIFIER_2G
x = x / accel_scale_modifier
y = y / accel_scale_modifier
z = z / accel_scale_modifier
if g is True:
return {'x': x, 'y': y, 'z': z}
elif g is False:
x = x * self.GRAVITIY_MS2
y = y * self.GRAVITIY_MS2
z = z * self.GRAVITIY_MS2
return {'x': x, 'y': y, 'z': z}
def set_gyro_range(self, gyro_range):
"""Sets the range of the gyroscope to range.
gyro_range -- the range to set the gyroscope to. Using a pre-defined
range is advised.
"""
# First change it to 0x00 to make sure we write the correct value later
self.bus.write_byte_data(self.address, self.GYRO_CONFIG, 0x00)
# Write the new range to the ACCEL_CONFIG register
self.bus.write_byte_data(self.address, self.GYRO_CONFIG, gyro_range)
def read_gyro_range(self, raw = False):
"""Reads the range the gyroscope is set to.
If raw is True, it will return the raw value from the GYRO_CONFIG
register.
If raw is False, it will return 250, 500, 1000, 2000 or -1. If the
returned value is equal to -1 something went wrong.
"""
# Get the raw value
raw_data = self.bus.read_byte_data(self.address, self.GYRO_CONFIG)
if raw is True:
return raw_data
elif raw is False:
if raw_data == self.GYRO_RANGE_250DEG:
return 250
elif raw_data == self.GYRO_RANGE_500DEG:
return 500
elif raw_data == self.GYRO_RANGE_1000DEG:
return 1000
elif raw_data == self.GYRO_RANGE_2000DEG:
return 2000
else:
return -1
def get_gyro_data(self):
"""Gets and returns the X, Y and Z values from the gyroscope.
Returns the read values in a dictionary.
"""
# Read the raw data from the MPU-6050
x = self.read_i2c_word(self.GYRO_XOUT0)
y = self.read_i2c_word(self.GYRO_YOUT0)
z = self.read_i2c_word(self.GYRO_ZOUT0)
gyro_scale_modifier = None
gyro_range = self.read_gyro_range(True)
if gyro_range == self.GYRO_RANGE_250DEG:
gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_250DEG
elif gyro_range == self.GYRO_RANGE_500DEG:
gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_500DEG
elif gyro_range == self.GYRO_RANGE_1000DEG:
gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_1000DEG
elif gyro_range == self.GYRO_RANGE_2000DEG:
gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_2000DEG
else:
print("Unkown range - gyro_scale_modifier set to self.GYRO_SCALE_MODIFIER_250DEG")
gyro_scale_modifier = self.GYRO_SCALE_MODIFIER_250DEG
x = x / gyro_scale_modifier
y = y / gyro_scale_modifier
z = z / gyro_scale_modifier
return {'x': x, 'y': y, 'z': z}
def get_all_data(self):
"""Reads and returns all the available data."""
temp = get_temp()
accel = get_accel_data()
gyro = get_gyro_data()
return [accel, gyro, temp]
if __name__ == "__main__":
mpu = mpu6050(0x68)
print(mpu.get_temp())
accel_data = mpu.get_accel_data()
print(accel_data['x'])
print(accel_data['y'])
print(accel_data['z'])
gyro_data = mpu.get_gyro_data()
print(gyro_data['x'])
print(gyro_data['y'])
print(gyro_data['z'])
I2C Python 方法可以參考:
MPU-6050-Python
Raspberry-Pi-I2C-Python
NV Forum TX2-MPU6050
附錄:
- I2C 相關(guān)
nvidia@tw-nano:~$ sudo i2cdetect -F 2
Functionalities implemented by /dev/i2c-2:
I2C yes
SMBus Quick Command no
SMBus Send Byte yes
SMBus Receive Byte yes
SMBus Write Byte yes
SMBus Read Byte yes
SMBus Write Word yes
SMBus Read Word yes
SMBus Process Call yes
SMBus Block Write yes
SMBus Block Read no
SMBus Block Process Call no
SMBus PEC yes
I2C Block Write yes
案例:
GEN3_I2C_SDA/SCL (PIN232/234) 連接的是EEPROM(AT24C02D)
nvidia@tw-nano:~$ sudo i2cdetect -y -r 2
Warning: Can't use SMBus Quick Write command, will skip some addresses
0 1 2 3 4 5 6 7 8 9 a b c d e f
00:
10:
20:
30: -- -- -- -- -- -- -- --
40:
50: 50 -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60:
70:
From the i2cdetect man page:
INTERPRETING THE OUTPUT
Each cell in the output table will contain one of the following
symbols:
· "--". The address was probed but no chip answered.
· "UU". Probing was skipped, because this address is currently in use
by a driver. This strongly suggests that there is a chip at this
address.
· An address number in hexadecimal, e.g. "2d" or "4e". A chip was found
at this address.
nvidia@tw-nano:~$ cat /sys/bus/i2c/devices/i2c-0/name
7000c000.i2c
nvidia@tw-nano:~$ cat /sys/bus/i2c/devices/i2c-1/name
7000c400.i2c
nvidia@tw-nano:~$ cat /sys/bus/i2c/devices/i2c-2/name
7000c500.i2c
nvidia@tw-nano:~$ cat /sys/bus/i2c/devices/i2c-3/name
7000c700.i2c
nvidia@tw-nano:~$ cat /sys/bus/i2c/devices/i2c-4/name
7000d000.i2c
nvidia@tw-nano:~$ cat /sys/bus/i2c/devices/i2c-5/name
7000d100.i2c
nvidia@tw-nano:~$ cat /sys/bus/i2c/devices/i2c-6/name
Tegra I2C adapter
nvidia@tw-nano:~$ ls /sys/firmware/devicetree/base/i2c@7000*
/sys/firmware/devicetree/base/i2c@7000c000:
'#address-cells' clock-names compatible dmas iommus name reg resets status
clock-frequency clocks dma-names interrupts linux,phandle phandle reset-names '#size-cells' temp-sensor@4c
/sys/firmware/devicetree/base/i2c@7000c400:
'#address-cells' clock-frequency clocks compatible dmas i2cmux@70 interrupts iqs263@44 name reg resets '#size-cells'
ak8963@0d clock-names cm32180@48 dma-names gpio@20 icm20628@68 iommus linux,phandle phandle reset-names rt5659.1-001a@1a status
/sys/firmware/devicetree/base/i2c@7000c500:
'#address-cells' battery-gauge@55 clock-names compatible dmas iommus name reg resets status
battery-charger@6b clock-frequency clocks dma-names interrupts linux,phandle phandle reset-names '#size-cells'
/sys/firmware/devicetree/base/i2c@7000c700:
'#address-cells' clock-names compatible dmas iommus name phandle reg resets status
clock-frequency clocks dma-names interrupts linux,phandle nvidia,restrict-clk-change print-rate-limit reset-names '#size-cells'
/sys/firmware/devicetree/base/i2c@7000d000:
'#address-cells' clocks dmas linux,phandle max77621@1c nvidia,require-cldvfs-clock reset-names sda-gpio
clock-frequency compatible interrupts max77620@3c name phandle resets '#size-cells'
clock-names dma-names iommus max77621@1b nvidia,bit-bang-after-shutdown reg scl-gpio status
/sys/firmware/devicetree/base/i2c@7000d100:
'#address-cells' clock-names compatible dmas iommus name reg resets status
clock-frequency clocks dma-names interrupts linux,phandle phandle reset-names '#size-cells'
root@jetbot:~/work/mpu-6050-Python# i2cdump -y 1 0x68
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 83 01 00 4d d4 e1 02 ce 0d 61 04 0c 28 52 52 b7 ??.M?????a??(RR?
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
30: 00 00 00 00 00 00 00 00 00 00 01 f1 0c 1c cc c6 ..........??????
40: 74 f5 50 00 00 00 00 00 00 00 00 00 00 00 00 00 t?P.............
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 3f 00 00 72 ............?..r
70: 00 00 00 00 00 68 00 00 00 00 00 00 00 00 00 00 .....h..........
80: 83 01 00 4d d4 e1 02 ce 0d 61 04 0c 28 52 52 b7 ??.M?????a??(RR?
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
b0: 00 00 00 00 00 00 00 00 00 00 01 f1 0c 1c cc c6 ..........??????
c0: 74 f5 60 00 00 00 00 00 00 00 00 00 00 00 00 00 t?`.............
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 3f 00 03 df ............?.??
f0: 00 00 00 00 00 68 00 00 00 00 00 00 00 00 00 00 .....h..........