这个开源平台为 DIY 开发者、学生和爱好者提供了创建各种基于 AI 的应用程序所需的一切。JetBot 套件以小型但功能强大的 NVIDIA Jetson Nano 计算机为基础工作,该计算机提供多个传感器和神经网络的并行操作,用于对象识别、避免碰撞和其他任务。原始 NVIDIA JetBot AI 机器人的所有组装文件和完整组件列表可在 GitHub ( https://github.com/NVIDIA-AI-IOT/jetbot ) 上获得。
可以从第三方制造商处购买现成的套装。这些套件以各种配置呈现,使您能够创建绝对独特的解决方案。我有一套 Waveshare 提供的。Waveshare 的 JetBot 配备了高品质的底盘、前置摄像头和所有必要的工具,可确保快速轻松地组装。
不幸的是,我们不得不改变平台,原来的平台是不稳定和弱引擎
我将它安装在另一个平台上——来自拆解的 iRobot Create 吸尘器。
考虑在 jetbot 上安装用于管理和导航的 ROS 包。
机器人操作系统(ROS)是用于开发机器人软件的灵活平台(框架)。这是一组各种工具、库和一定的规则,其目的是简化开发机器人软件的任务。
我们使用 64 GB 的 SD 卡来记录 NVIDIA JetPack 图像。NVIDIA JetPack 映像基于 Ubuntu 18.04 操作系统。我们将安装 ROS Melodic 版本(http://wiki.ros.org/melodic )。
# 添加所有 Ubuntu 存储库:
sudo apt-add-repository universe
sudo apt-add-repository multiverse
sudo apt-add-repository restricted
# 添加ROS仓库
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
# 安装 ROS 基础
sudo apt-get update
sudo apt-get install ros-melodic-ros-base
# 添加ROS路径
sudo sh -c ' echo "source /opt/ros/melodic/setup.bash" >> ~ / .bashrc '
我们将安装 Adafruit 库以支持 TB6612/PCA9685 引擎驱动程序和 SSD1306 调试 OLED 显示器:
# 安装点子
sudo apt-get install python-pip
# 安装 Adafruit 库
pip install Adafruit-MotorHAT
pip install Adafruit-SSD1306
我们将为用户提供对 i2c 总线的访问权限:
sudo usermod -aG i2c $USER
我们将重新启动系统以使更改生效。
创建一个 ROS Catkin 工作区来存储 ROS 包:
# 创建工作区 catkin mkdir -p ~/workspace/catkin_ws/src
cd ~/workspace/catkin_ws
catkin_make
# add the catkin_ws path to bashrc sudo sh -c ' echo "source ~/workspace/catkin_ws/devel/setup.bash" >> ~/.bashrc'
我们关闭并重新打开一个新的终端窗口以确保 catkin_ws 对 ROS 可见:
echo $ROS_PACKAGE_PATH
我们克隆并构建了 jetson-inference 包。该软件包使用 NVIDIA TensorRT 在内置 Jetson 平台上高效部署神经网络。
# 安装 git 和 cmake
sudo apt-get install git cmake
# 克隆存储库和 cd 子模块 ~/workspace
git clone https://github.com/dusty-nv/jetson-inference
cd jetson-inference
git submodule update --init
# 从源代码构建
mkdir build
cd build
cmake ../
make
# 安装库
sudo make install
克隆和构建 ROS 包 ros_deep_learning
# 安装依赖
sudo apt-get install ros-melodic-vision-msgs ros-melodic-image-transport ros-melodic-image-publisher
# 克隆 cd 存储库 ~/workspace/catkin_ws/src
git clone https://github.com/dusty-nv/ros_deep_learning
# 构建catkin
cd ~/workspace/catkin_ws
catkin_make
# 检查ROS是否找到了包,包是ros_deep_learning
rospack find ros_deep_learning
克隆和构建 jetbot_ros ROS 包
# 克隆存储库
cd ~/workspace/catkin_ws/src
git clone https://github.com/dusty-nv/jetbot_ros
# 构建包
cd ~/workspace/catkin_ws
catkin_make
# 检查 ROS 是否找到了 jetbot_ros 包的包
$ rospack find jetbot_ros
测试 ros_jetbot
打开终端并启动
roscore
在第二个终端中,我们启动 jetbot_motors 节点
rosrun jetbot_ros jetbot_motors.py
然后问题是导入错误:没有名为 Adafruit_MotorHAT 的模块,尽管该库已经安装(见上文)。
但是该库是安装在python3中的,而ROS使用的是python2。7
为 python2 安装 Adafruit_MotorHAT 库。7
python2. 7-m pip install Adafruit_MotorHAT
现在启动正常,在下一个终端中我们检查相应的节点和主题是否在 ROS 中运行
这是主题列表
但是,不幸的是,在 jetbot_motors.py 中注册了从主题 /jetbot_motors/cmd_str 接收到的消息的处理
我们尝试从终端发送它们(这些是向前、向后、向左、向右和停止的移动)
rostopic pub /jetbot_motors/cmd_str std_msgs/String --once "forward"
rostopic pub /jetbot_motors/cmd_str std_msgs/String --once "backward"
rostopic pub /jetbot_motors/cmd_str std_msgs/String --once "left"
rostopic pub /jetbot_motors/cmd_str std_msgs/String --once "right"
rostopic pub /jetbot_motors/cmd_str std_msgs/String --once "stop"
又是问题!!!没有动静。您需要更改文件 jetbot_motors.py,更改 set_speed() 和 all_stop() 函数。
我创建了一个新文件 jetbot_motors_1.py 并进行了以下更改
# sets motor speed between [-1.0, 1.0]
def set_speed(motor_ID, value):
max_pwm = 200.0
speed = int(min(max(abs(value * max_pwm), 0), max_pwm))
a = b = 0
if motor_ID == 1:
motor = motor_left
a=1
b=0
elif motor_ID == 2:
motor = motor_right
a=2
b=3
else:
rospy.logerror('set_speed(%d, %f) -> invalid motor_ID=%d', motor_ID, value, motor_ID)
return
motor.setSpeed(speed)
if value < 0:
motor.run(Adafruit_MotorHAT.FORWARD)
motor.MC._pwm.setPWM(a,0,0)
motor.MC._pwm.setPWM(b,0,speed*16)
elif value > 0:
motor.run(Adafruit_MotorHAT.BACKWARD)
motor.MC._pwm.setPWM(a,0,speed*16)
motor.MC._pwm.setPWM(b,0,0)
else:
motor.run(Adafruit_MotorHAT.RELEASE)
motor.MC._pwm.setPWM(a,0,0)
motor.MC._pwm.setPWM(b,0,0)
# stops all motors
def all_stop():
set_speed(motor_left_ID, 0.0)
set_speed(motor_right_ID, 0.0)
现在jetbot响应发送消息,可以向前、向后、向左、向右和停止。但这都是一个速度,由这个值调节
max_pwm = 200.0
有必要记录以不同速度执行的运动。现在,我们将做最简单的,我们将使用发送 std_msgs/String 消息到主题 /jetbot_motors/cmd_raw
# raw L/R motor commands (speed, speed)
def on_cmd_raw(msg):
rospy.loginfo(rospy.get_caller_id() + ' cmd_raw=%s', msg.data)
speeds=msg. data. split(',')
set_speed(motor_left_ID, float( speeds[0]))
set_speed(motor_right_ID, float (speeds[1]))
检查一下,我发送了类似的命令
rostopic pub /jetbot_motors/cmd_raw std_msgs/String --once " 0.9,-0.7"
。
并且还必须更改从主题 /jetbot_motors/cmd_raw 发送的消息。即geometry_msgs/Twist上的消息类型,在ROS中被广泛使用。
我创建了一个新文件 jetbot_motors_2.py 并进行了以下更改
#!/usr/bin/env python
import rospy
import time
import math
from Adafruit_MotorHAT import Adafruit_MotorHAT
from std_msgs.msg import String
from geometry_msgs.msg import Twist
PWM_MIN=0.5
PWM_MAX=1.0
# sets motor speed between [-1.0, 1.0]
def set_speed(motor_ID, value):
max_pwm = 200.0
speed = int(min(max(abs(value * max_pwm), 0), max_pwm))
a = b = 0
if motor_ID == 1:
motor = motor_left
a=1
b=0
elif motor_ID == 2:
motor = motor_right
a=2
b=3
else:
rospy.logerror('set_speed(%d, %f) -> invalid motor_ID=%d', motor_ID, value, motor_ID)
return
def motor.setSpeed(speed)
if value < 0:
motor.run(Adafruit_MotorHAT.FORWARD)
motor.MC._pwm.setPWM(a,0,0)
motor.MC._pwm.setPWM(b,0,speed*16)
elif value > 0:
motor.run(Adafruit_MotorHAT.BACKWARD)
motor.MC._pwm.setPWM(a,0,speed*16)
motor.MC._pwm.setPWM(b,0,0)
else:
motor.run(Adafruit_MotorHAT.RELEASE)
motor.MC._pwm.setPWM(a,0,0)
motor.MC._pwm.setPWM(b,0,0)
# stops all motors
def all_stop():
set_speed(motor_left_ID, 0.0)
set_speed(motor_right_ID, 0.0)
# directional commands (degree, speed)
def on_cmd_dir(msg):
rospy.loginfo(rospy.get_caller_id() + ' cmd_dir=%s', msg.data)
# raw L/R motor commands (speed, speed)
def on_cmd_raw(msg):
rospy.loginfo("msg cmd_raw")
rospy.loginfo(msg)
x=max(min(msg.linear.x,1.0),-1.0)
z=max(min(msg.angular.z,1.0),-1.0)
l=(x-z)/2
r=(x+z)/2
#rospy.loginfo(x)
#rospy.loginfo(z)
#rospy.loginfo(l)
#rospy.loginfo(r)
lpwm= PWM_MIN+math.fabs(l)*(PWM_MAX-PWM_MIN)
rpwm= PWM_MIN+math.fabs(r)*(PWM_MAX-PWM_MIN)
#rospy.loginfo(lpwm)
#rospy.loginfo(rpwm)
kl=1 if l>0 else -1
kr=1 if r>0 else -1
if l==0 : kl=0
if r==0 : kr=0
set_speed(motor_left_ID, kl*lpwm )
set_speed(motor_right_ID, kr*rpwm)
# simple string commands (left/right/forward/backward/stop)
def on_cmd_str(msg):
rospy.loginfo(rospy.get_caller_id() + ' cmd_str=%s', msg.data)
if msg.data.lower() == "left":
set_speed(motor_left_ID, -1.0)
set_speed(motor_right_ID, 1.0)
elif msg.data.lower() == "right":
set_speed(motor_left_ID, 1.0)
set_speed(motor_right_ID, -1.0)
elif msg.data.lower() == "forward":
set_speed(motor_left_ID, 1.0)
set_speed(motor_right_ID, 1.0)
elif msg.data.lower() == "backward":
set_speed(motor_left_ID, -1.0)
set_speed(motor_right_ID, -1.0)
elif msg.data.lower() == "stop":
all_stop()
else:
rospy.logerror(rospy.get_caller_id() + ' invalid cmd_str=%s', msg.data)
# initialization
if __name__ == '__main__':
# setup motor controller
motor_driver = Adafruit_MotorHAT(i2c_bus=1)
motor_left_ID = 1
motor_right_ID = 2
motor_left = motor_driver.getMotor(motor_left_ID)
motor_right = motor_driver.getMotor(motor_right_ID)
# stop the motors as precaution
all_stop()
# setup ros node
rospy.init_node('jetbot_motors')
rospy.Subscriber('~cmd_dir', String, on_cmd_dir)
rospy.Subscriber('~cmd_raw', Twist, on_cmd_raw)
rospy.Subscriber('~cmd_str', String, on_cmd_str)
# start running
rospy.spin()
# stop motors before exiting
all_stop() And
当然,通过启动启动命令文件来启动所有节点。我们将launch01.launch文件放在catkin_ws/src/jetbot_ros/launch
<launch>
<node name="jetbot_motors" pkg="jetbot_ros" type="jetbot_motors_2.py">
node>
<node name="jetbot_camera" pkg="jetbot_ros" type="jetbot_camera">
node>
<node name="jetbot_oled" pkg="jetbot_ros" type="jetbot_oled.py">
node>
launch>
运行批处理文件
roslaunch jetbot_ros launch01.launch
让我们从远程计算机控制机器人。我们将使用 rosbridge 包。Rosbridge 允许外部客户端(在我们的例子中是浏览器)访问 ROS 主题和服务(从主题发布和接收,调用服务)。Rosbridge 是 rosbridge_suite 元包的一部分,其中包括用于实现 rosbridge 协议的各种附加包。
rosbridge_suite 包是一组实现 rosbridge 协议并提供 WebSocket 传输层的包。
套餐包括:
rosbridge_library - 基本的 rosbridge 包。Rosbridge_library 负责接收 JSON 字符串并向 ROS 发送命令,反之亦然。
rosapi-通过通常为 ROS 客户端库保留的服务调用使某些 ROS 操作可用。这包括获取和设置参数、获取主题列表等等。
rosbridge_server-通过 WebSocket 提供连接,以便浏览器可以“与 rosbridge 对话”。Roslibjs 是一个用于浏览器的 JavaScript 库,可以通过 rosbridge_server 与 ROS 进行交互。
安装包
sudo apt-get install ros-melodic-rosbridge-suite
在launch文件夹中的项目文件夹jetbot_ros中创建命令文件launch02.launch
<launch>
<include file="$(find rosbridge_server)/launch/rosbridge_websocket.launch"/>
<node name="jetbot_motors" pkg="jetbot_ros" type="jetbot_motors_2.py">
node>
<node name="jetbot_oled" pkg="jetbot_ros" type="jetbot_oled.py">
node>
launch>
并运行命令文件
1个终端
roscore
2个终端
roslaunch jetbot_ros launch02.launch
要组织 Web 界面,您需要安装 Web 服务器。
sudo apt-get install apache2
现在我们的 html 页面将位于 /var/www/html 文件夹中。Library roslib.min.js 我们将其放在 js 文件夹中。
创建一个 html 文件 index01.html,我们将通过 websocket 9090 连接到 ROS,并将表单中的消息发送到 ROS /pub_txt_msg 主题,并在页面上接收和显示来自 ROS /sub_txt_msg 主题的消息
html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="js/roslib.min.js">script>
<script type="text/javascript" type="text/javascript">
var ros = new ROSLIB.Ros({
url : 'ws://192.168.0.111:9090'
});
ros.on('connection', function() {
document.getElementById("status").innerHTML = "Connected";
});
ros.on('error', function(error) {
document.getElementById("status").innerHTML = "Error";
});
ros.on('close', function() {
document.getElementById("status").innerHTML = "Closed";
});
var txt_listener = new ROSLIB.Topic({
ros : ros,
name : '/sub_txt_msg',
messageType : 'std_msgs/String'
});
txt_listener.subscribe(function(m) {
document.getElementById("msg").innerHTML = m.data;
});
var pub1=new ROSLIB.Topic ({
ros: ros,
name : '/pub_txt_msg',
messageType : 'std_msgs/String'
});
function send_ros() {
var msg=new ROSLIB.Message ({"data" : document.getElementById("putdata").value});
pub1.publish(msg);
}
script>
head>
<body>
<h1>Simple ROS User Interfaceh1>
<p>Connection status: <span id="status">span>p>
<p>Last /txt_msg received: <span id="msg">span>p>
<p><form id=formoptions name=formoptions action="javascript:void();" onsubmit="feturn false;">
send to /pub_txt_msg <br>
<input name=putdata id=putdata>
<button id='button1' value='send' onclick='send_ros();'>Sendbutton>
form>
p>
body>
html>
在浏览器中启动页面index01.html
。
创建一个文件 index02.html 来控制机器人的运动并从摄像头查看图像。我们使用 nipplejs library.js
html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="js/roslib.min.js">script>
<script type="text/javascript" src="js/nipplejs.js">script>
<script type="text/javascript" type="text/javascript">
var ros = new ROSLIB.Ros({
url : 'ws://192.168.0.111:9090'
});
ros.on('connection', function() {
document.getElementById("status").innerHTML = "Connected";
});
ros.on('error', function(error) {
document.getElementById("status").innerHTML = "Error";
});
ros.on('close', function() {
document.getElementById("status").innerHTML = "Closed";
});
var txt_listener = new ROSLIB.Topic({
ros : ros,
name : '/txt_msg',
messageType : 'std_msgs/String'
});
txt_listener.subscribe(function(m) {
document.getElementById("msg").innerHTML = m.data;
});
cmd_vel_listener = new ROSLIB.Topic({
ros : ros,
name : "/cmd_vel",
messageType : 'geometry_msgs/Twist'
});
move = function (linear, angular) {
var twist = new ROSLIB.Message({
linear: {
x: linear,
y: 0,
z: 0
},
angular: {
x: 0,
y: 0,
z: angular
}
});
cmd_vel_listener.publish(twist);
}
createJoystick = function () {
var options = {
zone: document.getElementById('zone_joystick'),
threshold: 0.1,
position: { left: 50 + '%' },
mode: 'static',
size: 150,
color: '#000000',
};
manager = nipplejs.create(options);
linear_speed = 0;
angular_speed = 0;
manager.on('start', function (event, nipple) {
timer = setInterval(function () {
move(linear_speed, angular_speed);
}, 25);
});
manager.on('move', function (event, nipple) {
max_linear = 1.0; // m/s
max_angular = 1.0; // rad/s
max_distance = 75.0; // pixels;
linear_speed = Math.sin(nipple.angle.radian) * max_linear * nipple.distance/max_distance;
angular_speed = -Math.cos(nipple.angle.radian) * max_angular * nipple.distance/max_distance;
});
manager.on('end', function () {
if (timer) {
clearInterval(timer);
}
self.move(0, 0);
});
}
window.onload = function () {
createJoystick();
}
script>
head>
<body>
<h1>Simple ROS User Interfaceh1>
<p>Connection status: <span id="status">span>p>
<p>Last /txt_msg received: <span id="msg">span>p>
<div id="zone_joystick" style="position: relative;">div>
body>
html>
启动页面后,我们可以控制机器人的运动。页面预览
。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !