本文为Exbot Robotics relayZhang博士原创文章,转载请注明,谢谢...
张博士为志愿服务者,热心困境儿童教育,为小朋友讲授机器人课程
(上海久牵志愿者服务社、2017中国困境儿童关注日)
使用Scratch2和ROS进行机器人编程学习(适用于中小学机器人编程Scratch和ROS)
Scratch是一款由麻省理工学院(MIT)设计开发的少儿编程工具,Python是近年来非常流行的机器人和人工智能编程语言,ROS是机器人操作系统。
参考JdeRobot的一篇详细介绍,就可以实现上述的功能,需要安装Scratch2、ROS Kinetic、Gazebo 7、JdeRobot、Python2.7等。
通过将Scratch2图形化编程语言转为Python,然后通过ROS消息机制控制Gazebo或实际机器人。
(上海久牵志愿者服务社、2017中国困境儿童关注日)
~~信息化智能化时代下平等受教育的权利~~
1 先看如下一个简单的示例1.1 新建hiros.bz2,如下:
1.2 通过下面命令将其转为Python:
[python]view plaincopyprint?
$ python scratch2python.py hiros.sb2
Stringify:
when @greenFlag clicked
repeat10
say'Hello,ROS Kinetic!'
end
[WARN] Block notincluded yet
-------------------
#!/usr/bin/env python
# -*- coding: utf-8 -*-
importtime
importconfig
importsys
importcomm
importos
importyaml
fromdroneimportDrone
fromrobotimportRobot
defexecute(robot):
try:
foriinrange(10):
print('Hello,ROS Kinetic!')
exceptKeyboardInterrupt:
raise
if__name__ =='__main__':
iflen(sys.argv) ==2:
path = os.getcwd()
open_path = path[:path.rfind('src')] +'cfg/'
filename = sys.argv[1]
else:
sys.exit("ERROR: Example:python my_generated_script.py cfgfile.yml")
# loading the ICE and ROS parameters
cfg = config.load(open_path + filename)
stream = open(open_path + filename,"r")
yml_file = yaml.load(stream)
forsectioninyml_file:
ifsection =='drone':
#starting comm
jdrc = comm.init(cfg,'drone')
# creating the object
robot = Drone(jdrc)
break
elifsection =='robot':
#starting comm
jdrc = comm.init(cfg,'robot')
# creating the object
robot = Robot(jdrc)
break
# executing the scratch program
execute(robot)
-------------------
2 控制机器人示例
是不是比较有趣,在不需购买任何设备的情况下,就可以用Scratch2进行ROS机器人编程。小学用Scratch2学习简单编程,中学用Python学习简单编程,大学用Python和C++学习复杂机器人编程,无缝衔接。
3 scratch2python.py
[python]view plaincopyprint?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ ="Raul Perula-Martinez"
__copyright__ ="JdeRobot project"
__credits__ = ["Raul Perula-Martinez"]
__license__ ="GPL v3"
__version__ ="0.0.0"
__maintainer__ ="Raul Perula-Martinez"
__email__ ="raules@gmail.com"
__status__ ="Development"
importkurt
importos
importsys
fromdifflibimportSequenceMatcher
fromparseimportparse, compile
fromtermcolorimportcprint
GENERAL = [
['end',''],
['forever','while True:'],
['if {} then','if %s:'],
['else','else:'],
['repeat {}','for i in range(%s):'],
['say {}','print(%s)'],
['set {} to {}','%s = %s'],
['wait {} secs','time.sleep(%s)'],
]
ROBOTICS = [
['move robot {}','robot.move("%s")'],
['move drone {}','robot.move("%s")'],
['move robot {} speed {}','robot.move("%s", %s)'],
['stop robot-drone','robot.stop()'],
['turn robot-drone {}','robot.turn("%s")'],
['turn robot {} speed {}','robot.turn("%s", %s)'],
['take off drone','robot.take_off()'],
['land drone','robot.land()'],
['frontal laser distance','robot.get_laser_distance()'],
]
defis_conditional(sentence):
"""
Returns if a sentence is conditional or not.
@param sentence: The sentence to check.
@return: True if it has a conditional, False otherwise.
"""
if"if"insentence:
returnTrue
returnFalse
defsimilar(a, b):
"""
Returns the ratio value comparing two sentences.
@param a: First sentence.
@param b: Second sentence.
@return: The ratio of the similarity.
"""
returnSequenceMatcher(None, a, b).ratio()
defsentence_mapping(sentence, threshold=None):
"""
Maps a sentence and returns the original and the mapped.
@param sentence: The sentence to map.
@return: The original sentence and the mapped sentence.
"""
found =False
options = []
original =None
translation =None
# first look for general blocks
foreleminGENERAL:
ifelem[][:3] == sentence.replace(' ','')[:3]:
options.append(elem)
found =True
# then look for robotics blocks
foreleminROBOTICS:
ifelem[][:3] == sentence.replace(' ','').replace('(','')[:3]:
options.append(elem)
found =True
iffound:
# select the option that better fits
l = [(m[], m[1], similar(sentence, m[]))forminoptions]
original, translation, score = max(l, key=lambdaitem: item[2])
ifthresholdandscore < threshold:
returnNone,None
# extract arguments
p = compile(original)
args = p.parse(sentence.replace(' ',''))
ifargs:
args_aux = list(args)
# look for more blocks
foridxinrange(len(args_aux)):
new_ori, new_trans = sentence_mapping(args_aux[idx])#sentence_mapping(args_aux[idx],0.8) --old
ifnew_trans !=None:
args_aux[idx] = args_aux[idx].replace(new_ori, new_trans)#replace(args_aux[idx], new_trans)
translation = translation % tuple(args_aux)
returnoriginal, translation
if__name__ =="__main__":
# get current working directory
path = os.getcwd()
open_path = path[:path.rfind('scripts')] +'data/'
save_path = path[:path.rfind('scripts')] +'src/scratch2jderobot/'
iflen(sys.argv) ==2:
# template creation
template = "\
#!/usr/bin/env python\n\
# -*- coding: utf-8 -*-\n\n\
importtime\n\
importconfig\n\
importsys\n\
importcomm\n\
importos\n\
importyaml\n\n\
fromdroneimportDrone\n\
fromrobotimportRobot\n\n\
defexecute(robot):\n\
\ttry:\n\
\t%s\
exceptKeyboardInterrupt:\n\
\t\traise\n\n\
if__name__ =='__main__':\n\
\tif len(sys.argv) ==2:\n\
\t\tpath = os.getcwd()\n\
\t\topen_path = path[:path.rfind('src')] +'cfg/'\n\
\t\tfilename = sys.argv[1]\n\n\
\telse:\n\
\t\tsys.exit(\"ERROR: Example:python my_generated_script.py cfgfile.yml\")\n\n\
\t# loading the ICE and ROS parameters\n\
\tcfg = config.load(open_path + filename)\n\
\tstream = open(open_path + filename, \"r\")\n\
\tyml_file = yaml.load(stream)\n\n\
\tfor sectioninyml_file:\n\
\t\tif section =='drone':\n\
\t\t\t#starting comm\n\
\t\t\tjdrc = comm.init(cfg,'drone')\n\n\
\t\t\t# creating the object\n\
\t\t\trobot = Drone(jdrc)\n\n\
\t\t\tbreak\n\
\t\telif section =='robot':\n\
\t\t\t#starting comm\n\
\t\t\tjdrc = comm.init(cfg,'robot')\n\n\
\t\t\t# creating the object\n\
\t\t\trobot = Robot(jdrc)\n\n\
\t\t\tbreak\n\
\t# executing the scratch program\n\
\texecute(robot)\n\n\
"
# load the scratch project
p = kurt.Project.load(open_path + sys.argv[1])
# show the blocks included
forscriptableinp.sprites + [p.stage]:
forscriptinscriptable.scripts:
# exclude definition scripts
if"define"notinscript.blocks[].stringify():
s = script
print("Stringify:")
sentences = []
forbins.blocks:
print(b.stringify())
sentences += b.stringify().split('\n')
tab_seq ="\t"
python_program = ""
forsinsentences:
# count number of tabs
num_tabs = s.replace(' ', tab_seq).count(tab_seq)
python_program += tab_seq * (num_tabs +1)
# pre-processing if there is a condition (operators and types)
ifis_conditional(s):
s = s.replace("'", "").replace("=", "==")
# mapping
original, translation = sentence_mapping(s)
# set the code
iftranslation !=None:
python_program += translation
else:
cprint("[WARN] Block not included yet"% s,'yellow')
python_program +="\n"+ tab_seq
# join the template with the code and replace the tabs
file_text = template % python_program
file_text = file_text.replace(tab_seq,' '*4)
print("\n-------------------")
cprint(file_text,'green')
print("-------------------\n")
# save the code in a python file with the same name as sb2 file
file_name = sys.argv[1].replace('.sb2','.py')
f = open(save_path + file_name,"w")
f.write(file_text)
f.close()
else:
print(
"ERROR: Number of parameters incorrect. Example:\n\tpython scratch2python.py hello_world.sb2")
领取专属 10元无门槛券
私享最新 技术干货