[译]机器人操作系统简介:终极机器人应用框架(上)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

[译]机器人操作系统简介:终极机器人应用框架

/*** 原文出处:https://www.toptal.com/robotics/introduction-to-robot-operating-system* @author dogstar.huang <chanzonghuang@gmail.com> 2016-03-05*/

机器人操作系统(ROS)不是一个真实的操作系统,而是一个框架以及一系列为运行在异质计算机集群的操作系统提供基础功能的工具。 它的用处不局限于机器人,还包括大量关注与外设一起工作的工具。

ROS 分成2000多个包,每个包提供特定的功能。连续框架的工具数量可能是它的最大功率。

为什么我应该用ROS?

ROS提供了硬件抽象,设备驱动,多机器进程间的通信,测试和可视化的工具等功能。
06001310_j2t7.jpg

ROS的关键特性是软件运行和沟通的方式,使得你可以设计复杂的软件而不需要知道相关的硬件如何工作。ROS提供了一种利用中央枢纽连接进程(节点)网络的方式。 节点可以运行在众多设备上,并且可以通过各种途径与中央枢纽进行连接。

创建网络的主要方式有提供可请求的服务,或者定义与其他节点的发布/订阅者连接。这两种方法都是通过指定消息类型来通信的。 一些类型由核心包提供,而消息类型则可由用户包来定义。

对于小型问题,开发人员可以通过连接已存在的解决方案来集成一个复杂的系统。这种方式的系统已经实现,它允许我们:

  • 在fly上用熟悉的接口替换组件,以便为各种变化移除停止系统的需要

  • 为另一个组件把众多组件的输出混合成一个输出,以便并行解各类问题

  • 只要实现消息系统对应的合适连接器就可以连接各种各样编程语言创造的组件,使得通过连接来自大量开发人员已存在的模块进行软件开发很容易

  • 创建基于设备网络的节点,而不用关心代码在哪里运行以及实现进程通信(IPC)和远程过程调用(RPC)系统

  • 根据远程硬件的需要,通过部署前两个要点即可直接连接馈送,而不用编写任何额外的代码

我们在计划演示通过迭代开发一个简单方案是多么地有用。相比于其他方式,这里有几个关键的好处。ROS有多平台支持以及允许通过隐藏于表面的点对点连接进行多设备的进程连接。 此设计允许支持任何包装了C++通信类的任何语言,或者手动为语言接口开发类。

ROS由我们的社区创建,意味着它也回归于社区。多亏于这个系统架构,经过若干年后,这种氛围导致了大量可重用并易于集成的包的涌现。

一些变种如:http://www.mrpt.org/,http://carmen.sourceforge.net/intro.html, http://lcm-proj.github.io/,http://playerstage.sourceforge.net/,https://msdn.microsoft.com/en-us/library/bb648760.aspx 等提供了其中一些特性,但不是全部。 大多数时候,设计的衰落在于语言支持的局限,未优化进程通信,或者按理说是最难修复的问题 -- 缺少对大量设备的支持。

我们准备构建什么?

既然我们的关注点是框架而不是针对特定问题的具体算法,所以给定的问题是相当简单的。我们的目标就是为一个车载的计算机构建通过Wi-Fi连接的软件, 从而可以通过使用电脑上的游戏把柄和安装在机器人上的摄像机来远程控制和监控机器人。

首先,为了示范ROS的基本原则,我们将会创建一个简单的程序来连接一个简单的模拟。我们会把游戏手柄绑定到电脑上并且尝试为能把游戏手柄输入转换成机器人控制信息而设计一个好的控制方案。

编写ROS代码的只要语言是C++和Python,首选C++是因为它的性能。由于代码中更少的样板和不需要明确的构建,我们将会通过Python来解释示例。

安装与配置

ROS版本由名称来组成。如现在这个日期,最新的发布版本是_Jade Turtle_,而最新的LTS版本是_Indigo Igloo_。最好是使用LTS版本,因为ROS不保证向前兼容性,所以全部的示例将使用_Indigo_这个版本来编写。

ROS可用于大量的*NIX平台,官方支持的版本运行于Ubuntu。OS X,Arch Linux,Debian,Raapbain 和Android版本则由社区支持。

我们将经历在Ubuntu 14.04桌面的安装过程。全部支持的版本和平台的过程都可在官网获得。带ROS的虚拟机也有。

安装是平台依赖性的(大部分平台都有自己提供的包),而工作区间的配置对于全部平台来说都是一样的。

在Ubuntu上安装

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://pool.sks-keyservers.net --recv-key 0xB01FA116
sudo apt-get update

然后会有针对你的Ubuntu版本的全部ROS的全部托管包。例如,Ubuntu 14.04支持indeigo和jade。

在桌面上安装基本的包可以三选一:

  • 最小化安装:sudo apt-get install ros-indigo-ros-base

  • 带基本额外GUI工具的:sudo apt-get install ros-indigo-desktop

  • 全量安装,即有全部官方特性的,包含了大量模拟器以及导航和知觉类库:sudo apt-get install ros-indigo-desktop-full

为了获得最好的工作体验,推荐全量安装。对于仅仅是用于运行节点的设备安装,基本版本则足够了。不和你选择的是哪个选项,你都可以安装任何需要的package_name包通过执行:

sudo apt-get install ros-indigo-<package-name>

最终的名字将会把下划线替换成横线,所以stage_ros在这个包里

ros-indigo-stage-ros

下一步是安装rosdep。在ROS的包可以声明他们依赖的包。rosdep允许你编译这些包而不用过多地人工维护依赖处理。为了安装它,调用:

sudo rosdep init
rosdep update

ROS有几个被它的工具使用的环境变量。默认的安装,bash脚本在/opt/ros/indigo/setup.bash初始化他们。在每个bash的会话中都需要初始化这些变量,所以最好的解决方案是把他们添加到~/.bashrc。

echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc
source ~/.bashrc

一些包通过rosinstall来安装扩展的依赖,rosinstall可作为一个包来获得并可通过sudo apt-get install python-rosinstall安装。

这里到了在Ubuntu上安装的最后。接下来是安装工作区间的简短介绍。

配置

自从_Groovy Galapagos后_,ROS工作区间通过catkin来管理。我们需要为全部托管的负定义一个目录。在这个目录里创建一个src目录,并在里面调用catkin_init_workspace。 这将会创建大量的链接到当前ROS版本源的符号。下一步是把这个工作音区也添加到环境变量。

为了演示整个工作区间的配置,选择一个空的目录并执行以下命令:

mkdir src
cd src
catkin_init_workspace
cd ..
catkin_make
echo "source $(pwd)/devel/setup.bash" >> ~/.bashrc
source ~/.bashrc

现在你已经创建了一个可以在里面创建自己ROS包的工作区间。

熟悉工具

马上创建代码是一个很大的跨越。让我们先来熟悉一些运行在屏幕后的系统。第一步是运行基本的GUI并看下它生成了什么消息。

为了在ROS中运行一些东西,需要加载一个核心的进程。这一点很简单,只要在一个新的终端窗口并输入:

roscore

在你的整个连接设备网络中,roscore仅需要在为通信分发托管中央枢纽的设备上加载一次。

roscore的主要角色是告诉节点他们应该连接哪个节点,以及通过哪种方式(不管是通过网络端口还是共享内存)。这样的目的是为了在最小化时间和运行全部通信所需要的带宽时, 让节点只关心他们想知道的数据,而不是他们想要连接的节点。

rqt

运行roscore后,可以为ROS加载主要的GUI工具:rqt。我们会看到很一般的东西 -- 一个空白的窗口。rqt托管了非常大量的可以在可视化配置中进行配置的插件 以及任何数量的预定义视图。
06001311_5LNy.jpg

为了能够开始,先运行插件_Robot Steering_,可以通过Plugins > Robot Tools > Robot Steering来选择它。我们会看到有两个滑块,代表着我们的机器人将会拥有的线性和旋转运动。 在插件的顶部可以看到一个有/cmd_vel的输入框。我们可以任意进行重命名。它代表了此操舵发布的主题。终端工具是看到在后台运行了什么的最好地方。
06001311_mZo2.jpg

终端工具

ROS有几个非常有用的工具来检查系统中正在发生什么。第一个我们将会介绍的工具是rostopic。 它允许我们检查节点可以评阅和发布的主题。运行```rostopic list···将会产生:

/cmd_vel
/rosout
/rosout_agg

后两个主题通常都会运行并且与中央ROS系统相关。/cmd_vel主题则由我们的操舵发布。在操舵中重命名这个主题也会在这里重全名。现在,我们对于在这个主题里面发生的东西感兴趣。 运行rostopic echo /cmd_vel将看不到什么东西(除非你对滑块作了调整)。这个进程会一直执行,直到我们取消它。让我们把垂直滑块移到20 m/s。看着输出,我们会看到以下一次又一次重复的内容:

linear:x: 0.2y: 0.0z: 0.0
angular:x: 0.0y: 0.0z: 0.0

这个消息重复的频率是多少?rostopic hz /cmd_vel说平均频率是10Hz。好吧,通过我很慢的Wi-Fi连接可以运行多少像这样的主题?rostopic bw /cmd_vel表明平均是480B/s。

到目前为止一切运行良好,但我们将要讨论消息类型。这种数据对于人类是友好的,但应用需要raw格式的数据,并且需要知道消息类型以便它能解析数据。 类型可以通过rostopic type /cmd_vel来决定,告诉我们这是一个geometry_msgs/Twist。任何ROS终端的工具无参数调用时都会返回一个标准的帮助消息。

ROS的wiki非常赞,在网页搜索这个字符串会找到一系列的解释,从它包括了什么到它的结构是怎样的应有尽有。但是我们不用依赖于它。rosmsg是针对消息类型的通用工具。 运行rosmsg show geometry_msgs/Twist会返回:

geometry_msgs/Vector3 linearfloat64 xfloat64 yfloat64 z
geometry_msgs/Vector3 angularfloat64 xfloat64 yfloat64 z

这个消息包含了两个3D向量,表示在三维空间中的线性和旋转速度。

如果我们想知道一个节点连接了什么主题,rosnode info <node-name>会给出关于节点的详细数据。rostopic,rosmsg和rosnode是检查raw ROS功能的主要工具。 ROS有大量的GUI和终端工具,但这些已超出了这次简介的范畴。

运行ROS节点的主要工具是rosrun和roslaunch。rosrun通过rosrun <package_name> <node_name>来运行节点,而roslaunch则基于加载 由于是ROS自动化中最为复杂的元素所以我们知之甚少的文件来运行节点。

我们可以关闭运行的全部东西以开启我们最初的代码。在下文中,我们将省略说明运行任何和ROS相关的东西都需要一个活跃的roscore实例。你遇到的很多问题都可以通过关闭 运行roscore对应的窗口来解决,并且新开一个窗口重新加载。这样的话会更新全部需要重新加载的依赖,包括在bash和在roscore中。

创建游戏柄遥

我们第一个目标是通过创建一个发布geometry_msgs/Twist数据给基于游戏柄输入的/cmd_vel来模拟Robot Steering的功能。第一步的产出是joy包。

joy包

这个joy包为操纵杆和游戏柄提供了通用的ROS驱动。它没有包含在默认的安装,所以需要这样进行安装:

sudo apt-get install ros-indigo-joy

安装完成后,可以运行rosrun joy joy_node。这会把我们和默认的操纵杆或者游戏连接起来。运行rostopic list可以看到有一个叫/joy的主题。通过rostopic echo可以 看到以下格式的消息(请注意你需要使用游戏柄或操纵杆解析待发布的消息)。

header:seq: 4156stamp:secs: 1450707466nsecs: 204517084frame_id: ''
axes: [0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0, 0.0]
buttons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

现在你可以忽略头部。除此之外,axes和buttons恰到好处地解析了他们代表什么。移动轴和按下在控制器上的按钮会导致这些数字发生变化。使用我们的工具,可以决定这个消息类型 是sensor_msgs/Joy并且对应的格式是:

std_msgs/Header headeruint32 seqtime stampstring frame_id
float32[] axes
int32[] buttons

创建我们的遥

编写代码的第一步是创建一个包。在工作区间的src目录里,运行:

catkin_create_pkg toptal_tutorial rospy joy geometry_msgs sensor_msgs

在这里我们声明了将要创建的包名,紧跟随后的是所要依赖的包。无须担心,依赖可以稍候手动更新。

现在我们有了toptal_tutorial目录。在这个目录里,创建一个将会放置全部Python脚本的scripts目录。

现在来创建一个teleop.py文件,并在里面放置:

#!/usr/bin/env python import rospy from sensor_msgs.msg import Joy def joy_callback(data): print data def main(): rospy.init_node('teleop') rospy.Subscriber('joy', Joy, joy_callback) while not rospy.is_shutdown(): pass if __name__ == '__main__': main()

我们还需要设置chmod +x teleop.py以便脚本能被执行。在某个终端上运行rosrun joy joy_node并有另一个终端上运行rosrun toptal_tutorial teleop.py将会导致运行teleop.py的终端被输出的Joy消息填充。

让我们来检查一下代码做了什么。

首先,导入托管了与ROS框架交互的类库的rospy。每一个定义了消息的包都有一个带消息定义的msg子包。我们导入了Joy以便可以处理输入。 这里不需要导入嵌入式的消息类型(如来自在Joy消息中的std_msgs.msg的Header),除非我们想明确地提及他们。

第一步是初始化一个指定名字的节点(在这里,我们把它叫作“teleop”)。然后创建一个订阅者来订阅sensor_msgs.msg.Joy类型的“joy”主题,并且通过 回调joy_callback函数来处理每一个消息。回调接收一个参数,即来自消息的数据。访问这个数据的成员非常简单。如果想打印第一个轴的状态,或者想 重新调用这个消息类型,可以调用print data.axes[0],并且是一个浮点类型。在最后的循环会一直循环直到ROS关闭。

下一步是处理未知的数据。我们会创建一个根据输入而改变的Twist消息,然后会把它发布到cmd_vel主题。

#!/usr/bin/env python import rospy from sensor_msgs.msg import Joy from geometry_msgs.msg import Twist # new from functools import partial # new def joy_callback(pub, data): # modified cmd_vel = Twist() # new cmd_vel.linear.x = data.axes[1] # new cmd_vel.angular.z = data.axes[0] # new pub.publish(cmd_vel) # new def main(): rospy.init_node('teleop') pub = rospy.Publisher('cmd_vel', Twist, queue_size=1000) # new rospy.Subscriber('joy', Joy, partial(joy_callback, pub)) # modified while not rospy.is_shutdown(): pass if __name__ == '__main__': main()

首先,添加Twist消息,并且为通过functools.partial绑定函数参数添加支持。然后创建一个发布者,pub,来把一个Twist消息类型发布给cmd_vel。我们把这个发布者和回调函数进行绑定,并使它为每一个由前两个轴代表的速度的输入都发布一个Twist消息。 这些代码做了我们期望的它做的事情,而且可以通过rostopic echo /cmd_vel看到结果的输出。

但我们还有一个问题。joy主题发布的速度会很大。如果监控rostopic hz /cmd_vel并在圆圈中移动模拟遥杆,可以看到超级大量的消息。 这不仅仅导致了大量的通信,还导致了接收这些消息的进程需要一个个地处理他们。其实并不需要如此频繁地发布这些数据,最好是以一个稳定的速率如10Hz来发布。 可以通过以下代码来实现。

#!/usr/bin/env python import rospy from sensor_msgs.msg import Joy from geometry_msgs.msg import Twist from functools import partial def joy_callback(cmd_vel, data): # modified cmd_vel.linear.x = data.axes[1] cmd_vel.angular.z = data.axes[0] # moved pub.publish(cmd_vel) to main loop def main(): rospy.init_node('teleop') cmd_vel = Twist() # new pub = rospy.Publisher('cmd_vel', Twist, queue_size=1000) rospy.Subscriber('joy', Joy, partial(joy_callback, cmd_vel)) # modified rate = rospy.Rate(10) # new while not rospy.is_shutdown(): pub.publish(cmd_vel) # new rate.sleep() # new if __name__ == '__main__': main()

我们修改了回调函数以便接收可变的Twist对象并且在循环中作了修改。来自rospy.Rate的sleep函数维护了一个稳定的输出频率。

最后的代码将会导致/cmd_vel主题以10Hz来获得速度命令,以模拟_Robot Steering_ ···rqt```插件的输出。


下一篇:[译]机器人操作系统简介:终极机器人应用框架(下)


------------------------    

  • 知识共享许可协议本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。

  • 本文翻译作者为:dogstar,发表于艾翻译(itran.cc);欢迎转载,但请注明出处,谢谢!


转载于:https://my.oschina.net/dogstar/blog/631616

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

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

相关文章

AIKit v4.11.0 – WordPress AI 自动编写器、聊天机器人、写作助手和内容重定向器 / OpenAI GPT 插件

AIKit v4.11.0&#xff1a;WordPress的AI革命 一、引言 AIKit v4.11.0是一款为WordPress用户精心设计的强大插件&#xff0c;该插件集成了OpenAI的GPT-3技术&#xff0c;为用户提供了前所未有的AI写作和聊天机器人功能。此版本的推出&#xff0c;将WordPress的功能扩展到了全新…

精华阅读第6期|程序猿的世界,你不懂!

上周&#xff0c;微信圈被一篇文章刷屏了&#xff01;那就是西乔出品的《你为什么总招不到程序员&#xff1f;》&#xff0c;西乔的漫画之所以这么火&#xff0c;很重要的原因就是她懂程序猿的生活&#xff0c;同时作品也能够引起大家的共鸣。其实&#xff0c;移动开发精英俱乐…

恒生估值系统_恒生指数和恒生国企指数投资价值分析

恒生指数和恒生国企指数都是港股的大蓝筹指数。恒生指数是从香港股票市场挑选出50只优质蓝筹股票组成的指数。恒生国企指数又称为H股指数。H股指注册地在内地&#xff0c;但是上市地在香港的外资股票。恒生国企指数的成分股数目是没有限制的&#xff0c;但是必须为市值最大&…

java程序练习

数组求和作业 开发环境&#xff1a;java 工具&#xff1a;eclipse 两种数据类型excel和csv 在同学建议下&#xff0c;我选择用csv文件打开&#xff0c;这就引来了第一个问题&#xff0c;在java中如何调用csv文件。以下是我百度的结果 http://www.educity.cn/java/627496.html &…

hwd是长宽高吗_五菱皮卡要来了,五种形态任你选,颜值是你期待的吗?

近日&#xff0c;网友上传了五菱皮卡的渲染图&#xff0c;引起了大家对五菱皮卡的热烈讨论。在刚过去的2020年&#xff0c;五菱凭借性价比超高的宏光MINI EV成为了新能源领域的领头羊&#xff0c;而后推出的‘大四座’家用车五菱凯捷也取得了五万台的预定量&#xff0c;五菱一时…

原创 通过PEB获得进程路径 (附完整工程)

完整工程&#xff1a;http://files.cnblogs.com/files/Gotogoo/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E5%99%A8%28x86%26%26x64%29.zip PEB&#xff08;Process Environment Block&#xff0c;进程环境块&#xff09;存放进程信息&#xff0c;每个进程都有自己的PEB信息。位于…

Windbg SOS and CLR版本不一致的解决方案

由于测试服务环境与Windbg运行环境的差异&#xff0c;这就可能出现Windbg在分析dump文件时.net sos.dll和mscordacwks.dll版本不一致问题&#xff0c;从而导致windbg调试器的扩展命令无法正常使用&#xff0c;具体的解决方法如下&#xff1a;1.首先定义Windgb symbols路径&…

[DIV/CSS] 【译】60个有用CSS代码片段

2019独角兽企业重金招聘Python工程师标准>>> 1、垂直对齐 如果你用CSS&#xff0c;则你会有困惑&#xff1a;我该怎么垂直对齐容器中的元素&#xff1f;现在&#xff0c;利用CSS3的Transform&#xff0c;可以很优雅的解决这个困惑&#xff1a; .verticalcenter{posi…

java 类数组_Java常用类-字符串、日期类、算法及数组工具类等

大家好&#xff0c;乐字节的小乐又和大家见面了。这次要给大家讲述的是Java常用类。主要有以下知识点&#xff1a; 字符串相关类&#xff08;String 、StringBuffer、StringBuilder&#xff09; 算法及数组工具类(Arrays) 日期类 基本数据类型包装类 Math类 File类 枚举类一、 …

IOS之Foundation之探究学习Swift实用基础整理一

2019独角兽企业重金招聘Python工程师标准>>> 1 import Foundation2 3 //加载网络数据&#xff0c;查找数据的字符串4 let dataurl "http://api.k780.com:88/?appweather.city&&appkey10003&signb59bc3ef6191eb9f747dd4e83c99f2a4&formatjson…

sql 时间 没有日期_SQL-补充:日期和时间戳互转

补充&#xff1a;日期和时间戳互转1. 日期转时间戳-- 转十位select UNIX_TIMESTAMP(2018-12-25 12:25:00);结果&#xff1a;1545711900-- 转十三位SELECT REPLACE(unix_timestamp(current_timestamp(3)),.,);结果&#xff1a;15457119000212. 时间戳转日期 FROM_UNIXTIME(unix_…

vue那个生命周期函数操作dom_vue生命周期实例小结

本文实例分析了vue生命周期。分享给大家供大家参考&#xff0c;具体如下&#xff1a;每个Vue实例都存在完整的生命周期&#xff0c;经历从创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程。如下图所示vue的完整生命周期可分为三个阶段&#xff1a;初…

不求很多,够用就好

Hi&#xff0c;我是一名在校学生&#xff0c;目前大三&#xff0c;希望在前端方向上发展&#xff0c;最好以后是一个真全栈 曾经也会搜索一堆的工具&#xff0c;后面发现 只有正确的使用合理数量的工具&#xff0c;才能加快开发步伐 下面简单推荐几个实用工具&#xff0c;强大并…

java连接mysql2008_在Java中如何使用jdbc连接Sql2008数据库(转)

我们在javaEE的开发中&#xff0c;肯定是要用到数据库的&#xff0c;那么在javaEE的开发中&#xff0c;是如何使用代码实现和SQL2008的连接的呢&#xff1f;在这一篇文章中&#xff0c;我将讲解如何最简单的使用jdbc进行SQL2008的数据库的连接的。首先我们看下我们的数据库的一…

java搭建博客系统_Spring boot 搭建个人博客系统(一)——整体思路

Spring boot 搭建个人博客系统(一)——整体思路一直想用Spring boot 搭建一个属于自己的博客系统&#xff0c;刚好前段时间学习了叶神的牛客项目课受益匪浅&#xff0c;乘热打铁也主要是学习&#xff0c;好让自己熟悉这类项目开发的基本流程。0. 思路博客的基本作用就是博主写文…

在SQL Server中为什么不建议使用Not In子查询

原文:在SQL Server中为什么不建议使用Not In子查询在SQL Server中&#xff0c;子查询可以分为相关子查询和无关子查询&#xff0c;对于无关子查询来说&#xff0c;Not In子句比较常见&#xff0c;但Not In潜在会带来下面两种问题&#xff1a; 结果不准确 查询性能低下 下面我们…

结组项目-四则运算3

团队成员&#xff1a;苗堃&#xff08;http://www.cnblogs.com/brucekun/p/5294368.html&#xff09;、罗毅&#xff08;http://www.cnblogs.com/ly199553/p/5294779.html&#xff09; PSP总结http://www.cnblogs.com/ly199553/p/5295545.html 本次软件工程老师提出了新任务&a…

jsp 嵌入java_关于JSP里的Java语句嵌入问题

是这样的,我用的是Intellij 导入了一个MyEclipse的包(该包已部署在服务器上&#xff0c;所以是没有大错误的)。然后在一个jsp文件出现了个问题&#xff1a;莫名奇妙地println变成了红色&#xff0c;执行的时候就直接抛出异常了。今天刚接触JavaWeb不太懂&#xff0c;到底是怎么…

【three.js】库

2019独角兽企业重金招聘Python工程师标准>>> three.js 一个轻量级的webgl库&#xff0c;但是十分强大。 下载地址https://github.com/mrdoob/three.js OrbitControls.js 控制视口的平移、缩放、旋转。 GridHelper.js 生成视口的网格。 转载于:https://my.oschina.…

域名发散--前端优化(三)

话说天下大势&#xff0c;分久必合&#xff0c;合久必分其实域名也是一样&#xff0c;分分合合&#xff0c; 不管是域名收敛还是域名发散&#xff0c;都有着自己独特的应用场景。目前, 在webs top 30,000 URLS 里面&#xff0c; 平均每个域名承担了50个资源的请求&#xff0c;所…