Scratch是一款由麻省理工学院(MIT)设计开发的少儿编程工具,Python是近年来非常流行的机器人和人工智能编程语言,ROS是机器人操作系统。
参考JdeRobot的一篇详细介绍,就可以实现上述的功能,需要安装Scratch2、ROS Kinetic、Gazebo 7、JdeRobot、Python2.7等。
通过将Scratch2图形化编程语言转为Python,然后通过ROS消息机制控制Gazebo或实际机器人。
codelab-adapter-docs.codelab.club + github.com/wwj718 +
(上海久牵志愿者服务社、2017中国困境儿童关注日)
~~信息化智能化时代下平等受教育的权利~~
$ python scratch2python.py hiros.sb2
Stringify:
when @greenFlag clicked
repeat 10
say 'Hello,ROS Kinetic!'
end
[WARN] Block not included yet
-------------------
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import config
import sys
import comm
import os
import yaml
from drone import Drone
from robot import Robot
def execute(robot):
try:
for i in range(10):
print('Hello,ROS Kinetic!')
except KeyboardInterrupt:
raise
if __name__ == '__main__':
if len(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)
for section in yml_file:
if section == 'drone':
#starting comm
jdrc = comm.init(cfg,'drone')
# creating the object
robot = Drone(jdrc)
break
elif section == 'robot':
#starting comm
jdrc = comm.init(cfg,'robot')
# creating the object
robot = Robot(jdrc)
break
# executing the scratch program
execute(robot)
-------------------
是不是比较有趣,在不需购买任何设备的情况下,就可以用Scratch2进行ROS机器人编程。小学用Scratch2学习简单编程,中学用Python学习简单编程,大学用Python和C++学习复杂机器人编程,无缝衔接。
#!/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__ = "[email protected]"
__status__ = "Development"
import kurt
import os
import sys
from difflib import SequenceMatcher
from parse import parse, compile
from termcolor import cprint
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()'],
]
def is_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" in sentence:
return True
return False
def similar(a, b):
"""
Returns the ratio value comparing two sentences.
@param a: First sentence.
@param b: Second sentence.
@return: The ratio of the similarity.
"""
return SequenceMatcher(None, a, b).ratio()
def sentence_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
for elem in GENERAL:
if elem[0][:3] == sentence.replace(' ', '')[:3]:
options.append(elem)
found = True
# then look for robotics blocks
for elem in ROBOTICS:
if elem[0][:3] == sentence.replace(' ', '').replace('(', '')[:3]:
options.append(elem)
found = True
if found:
# select the option that better fits
l = [(m[0], m[1], similar(sentence, m[0])) for m in options]
original, translation, score = max(l, key=lambda item: item[2])
if threshold and score < threshold:
return None, None
# extract arguments
p = compile(original)
args = p.parse(sentence.replace(' ', ''))
if args:
args_aux = list(args)
# look for more blocks
for idx in range(len(args_aux)):
new_ori, new_trans = sentence_mapping(args_aux[idx]) #sentence_mapping(args_aux[idx],0.8) --old
if new_trans != None:
args_aux[idx] = args_aux[idx].replace(new_ori, new_trans) #replace(args_aux[idx], new_trans)
translation = translation % tuple(args_aux)
return original, 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/'
if len(sys.argv) == 2:
# template creation
template = "\
#!/usr/bin/env python\n\
# -*- coding: utf-8 -*-\n\n\
import time\n\
import config\n\
import sys\n\
import comm\n\
import os\n\
import yaml\n\n\
from drone import Drone\n\
from robot import Robot\n\n\
def execute(robot):\n\
\ttry:\n\
\t%s\
except KeyboardInterrupt:\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 section in yml_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
for scriptable in p.sprites + [p.stage]:
for script in scriptable.scripts:
# exclude definition scripts
if "define" not in script.blocks[0].stringify():
s = script
print("Stringify:")
sentences = []
for b in s.blocks:
print(b.stringify())
sentences += b.stringify().split('\n')
tab_seq = "\t"
python_program = ""
for s in sentences:
# 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)
if is_conditional(s):
s = s.replace("'", "").replace("=", "==")
# mapping
original, translation = sentence_mapping(s)
# set the code
if translation != None:
python_program += translation
else:
cprint("[WARN] Block <%s> 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")
----