2020-5-10 0:23 风雨敲窗棂
在*鱼上入手了一个二手jetson nano,这篇的故事就开始了。
sudo sh -c 'echo 255 > /sys/devices/pwm-fan/target_pwm'
sudo sh -c 'echo 20 > /sys/devices/pwm-fan/target_pwm'
注意:以下程序的条件可根据需要自行更改。
# 源地址:https://blog.csdn.net/bornfree5511/article/details/103076414
#!/usr/bin/python
#~/fan_control.py
import time
while True:
fo = open("/sys/class/thermal/thermal_zone0/temp","r")
#thermal_zone1是cpu的温度,thermal_zone2是gpu的温度,thermal_zone0的温度一直是最高的,可能
#是封装的温度,可用jtop查看具体的信息
thermal = int(fo.read(10))
fo.close()
thermal = thermal / 1000
if thermal < 30:
thermal = 0
elif thermal >= 30 and thermal < 70:
thermal = thermal - 30
else:
thermal = thermal
thermal = str(thermal)
print thermal
fw=open("/sys/devices/pwm-fan/target_pwm","w")
fw.write(thermal)
fw.close()
time.sleep(60)
设置jupyter开机自启动请参照:让Jupyter Lab在Jetson Nano上自动启动
参照ubuntu实现python脚本后台运行+开机自启
1.建立rc-local.service文件
sudo gedit /etc/systemd/system/rc-local.service
2.将下列内容替换rc-local.service文件
[Unit]
Description=/etc/rc.local Compatibility
ConditionPathExists=/etc/rc.local
[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99
[Install]
WantedBy=multi-user.target
3.创建文件rc.local
sudo gedit /etc/rc.local
4.将下列内容复制进rc.local文件
#!/bin/sh -e
# rc.local
nohup sudo python ~/fan_control.py > /usr/local/out.log 2>&1 &
exit 0
5.Ubuntu系统 sudo指令免密码
sudo gedit /etc/sudoers
将 %sudo ALL=(ALL:ALL) ALL
修改为%sudo ALL=(ALL) NOPASSWD:ALL
请仔细操作!
6.给rc.local加上权限
sudo chmod +x /etc/rc.local
7.启用服务
sudo systemctl enable rc-local
8.启动服务并检查状态
sudo systemctl start rc-local.service
sudo systemctl status rc-local.service
9.重启并检查是否成功
reboot
如果风扇自动转了起来,说明成功。
在某宝上找到基于jetson nano的小车,有两款:1)jetbot;2)jetracer。jetbot利用差速驱动转向,jetracer则是迷你版的无人车(几何运动学模型为阿克曼轮转向模型)。后者是我想要的。jetracer很好,唯一不足的是,电机不带编码器,在之后的功能上有所缺失(无法得到较准确的里程计信息)。于是:我只购买了jetracer扩展板、锂电池组。
jetson nano总共有2组I2C总线,分别为(I2C BUS 1: 3,5)(I2C BUS 2: 27,28)。I2C总线的引脚在J41,也即那两排密集的引脚区。
查看总线1的设备
sudo i2cdetect -y -r 1
由于jetracer扩展板上使用的是SSD1306的0.91inch OLED屏幕,所以需要先安装Adafruit_SSD1306
sudo pip3 install Adafruit_SSD1306
由于OLED显示的示例程序在jetbot上,所以先安装jetbot.
git clone https://github.com/NVIDIA-AI-IOT/jetbot.git
cd jetbot
python3 setup.py build
sudo python3 setup.py install --record jetbot.uninstall.txt
如果需要卸载jetbot,可以在jetbot根目录下执行:
sudo cat jetbot.uninstall.txt | sudo xargs rm -rf
所以,最好保留jetbot.uninstall.txt
文件。
运行程序:
cd jetbot/jetbot/apps/
sudo python3 stats.py
由于jetracer与jetbot可扩展性很差,(不带mpu,不带电机编码)。jetbot是用差速控制,是用简单的TT马达,不带编码器。jetracer是用转向舵机控制方向,但是后面两个电机也不带编码器。因此,不考虑jetbot与jetracer的底盘。
在另一家店里挑了一款不带控制器的迷你小车(带编码的电机,舵机)。那家店里,也有带控制器的(买来直接能用游戏手柄控制运动的那种)。由于,车本来就很小,211 x 191 x 65mm。如果系统用两个计算板子,车体肯定很臃肿。我想把所有的全集中在jetson nano上,就像jetracer一样。
底层与ROS串口通讯协议
位数 | 十六进制 | ASCII码 |
---|---|---|
1 | 0x7B | { |
2 | 0x2D或0x2B | -或+ |
3 | 0x30~0x39 | 0~9 |
4 | 0x30~0x39 | 0~9 |
5 | 0x30~0x39 | 0~9 |
6 | 0x30~0x39 | 0~9 |
7 | 0x2D或0x2B | -或+ |
8 | 0x30~0x39 | 0~9 |
9 | 0x30~0x39 | 0~9 |
10 | 0x30~0x39 | 0~9 |
11 | 0x30~0x39 | 0~9 |
12 | 0x7D | } |
例如,我发送{+3000-0100},表示速度期望值为3000/100,角度期望值为-100/100。
jetracer扩展板上的PCA9686只引出两个通道,其中一个通道用于控制转向舵机,而后面两个电机则共用一个通道。在实际测试中,即使用同一个信号控制,两个电机的转速是不一样的,这次上电是左边的快些,下次上电可能就是右边的快些。
如果左右两个电机速度无法可控的保持一致,那么实际运行中,我们无法很好的控制小车按预定的轨迹行驶。更多讨论请参看2个直流电机速度不一样,小车走直线总是偏,怎么解决?。
唯一的解决方法就是:左右电机单独控制,利用PID调速到相同转速。然而,但是,但是,然而。。。jetracer扩展板上的左右电机共用一个控制通道。问了客服,除非更改硬件电路。。。
于是各种查找方案,找到下图所示的DC Motor+Stepper FeatherWing。
管脚说明
凑巧的是,它就是jetbot官方版本(非微雪版)采用的马达控制板(也可以驱动其他型号的电机)。下面的图更直接明了。
连线方式:
MPU6050 jetson nano
VCC — 5v
GND — GND
SCL — 28
SDL — 27
(28, 27)表示I2C bus0
MPU6050的设备地址为0x68
程序代码:
import atexit
from Adafruit_MotorHAT import Adafruit_MotorHAT
import traitlets
from traitlets.config.configurable import Configurable
class Motor(Configurable):
value = traitlets.Float()
# config
alpha = traitlets.Float(default_value=1.0).tag(config=True)
beta = traitlets.Float(default_value=0.0).tag(config=True)
def __init__(self, driver, channel, *args, **kwargs):
super(Motor, self).__init__(*args, **kwargs) # initializes traitlets
self._driver = driver
self._motor = self._driver.getMotor(channel)
if(channel == 1):
self._ina = 1
self._inb = 0
else:
self._ina = 2
self._inb = 3
atexit.register(self._release)
@traitlets.observe('value')
def _observe_value(self, change):
self._write_value(change['new'])
def _write_value(self, value):
"""Sets motor value between [-1, 1]"""
mapped_value = int(255.0 * (self.alpha * value + self.beta))
speed = min(max(abs(mapped_value), 0), 255)
self._motor.setSpeed(speed)
if mapped_value < 0:
self._motor.run(Adafruit_MotorHAT.FORWARD)
self._driver._pwm.setPWM(self._ina,0,0)
self._driver._pwm.setPWM(self._inb,0,speed*16)
else:
self._motor.run(Adafruit_MotorHAT.BACKWARD)
self._driver._pwm.setPWM(self._ina,0,speed*16)
self._driver._pwm.setPWM(self._inb,0,0)
def _release(self):
"""Stops motor by releasing control"""
self._motor.run(Adafruit_MotorHAT.RELEASE)
self._driver._pwm.setPWM(self._ina,0,0)
self._driver._pwm.setPWM(self._inb,0,0)
import time
import traitlets
from traitlets.config.configurable import SingletonConfigurable
from Adafruit_MotorHAT import Adafruit_MotorHAT
class Robot(SingletonConfigurable):
left_motor = traitlets.Instance(Motor)
right_motor = traitlets.Instance(Motor)
# config
i2c_bus = traitlets.Integer(default_value=0).tag(config=True)
left_motor_channel = traitlets.Integer(default_value=1).tag(config=True)
left_motor_alpha = traitlets.Float(default_value=1.0).tag(config=True)
right_motor_channel = traitlets.Integer(default_value=2).tag(config=True)
right_motor_alpha = traitlets.Float(default_value=1.0).tag(config=True)
def __init__(self, *args, **kwargs):
super(Robot, self).__init__(*args, **kwargs)
self.motor_driver = Adafruit_MotorHAT(i2c_bus=self.i2c_bus, addr=0x68)
self.left_motor = Motor(self.motor_driver, channel=self.left_motor_channel, alpha=self.left_motor_alpha)
self.right_motor = Motor(self.motor_driver, channel=self.right_motor_channel, alpha=self.right_motor_alpha)
def set_motors(self, left_speed, right_speed):
self.left_motor.value = left_speed
self.right_motor.value = right_speed
def forward(self, speed=1.0, duration=None):
self.left_motor.value = speed
self.right_motor.value = speed
def backward(self, speed=1.0):
self.left_motor.value = -speed
self.right_motor.value = -speed
def left(self, speed=1.0):
self.left_motor.value = -speed
self.right_motor.value = speed
def right(self, speed=1.0):
self.left_motor.value = speed
self.right_motor.value = -speed
def stop(self):
self.left_motor.value = 0
self.right_motor.value = 0
robot = Robot()
robot.set_motors(2.0, 1.0)
如果左右两个电机转速不一样,说明成功。
某宝上买的,这玩意这么便宜。不过当时是和DC Motor+Stepper FeatherWing一起下的单。具体也不懂GY-521是代表啥,反正知道jetson nano通过I2C从这玩意中读取IMU数据。
首先,安装py_imu_mpu6050
github地址:https://github.com/romybompart/py_imu_mpu6050
sudo pip3 install py-imu-mpu6050
连线方式:
MPU6050 jetson nano
VCC — 5v
GND — GND
SCL — 28
SDL — 27
(28, 27)表示I2C bus0
MPU6050的设备地址为0x68
连接后,执行以下命令,会出现mpu6050的设备地址。
Jetson Nano I2C说明及Python案例:MPU6050