小朋友學ROS機器人——使用Scratch2和ROS進行機器人圖形化編程學習
01-28
版權聲明:本文為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 plain copy print?
- $ python scratch2python.py hiros.sb2
- Stringify:
- when @greenFlag clicked
- repeat 10
- say Hello,ROS Kinetic!
- end
- [WARN] Block <when @greenFlag clicked> 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)
- -------------------
2 控制機器人示例
是不是比較有趣,在不需購買任何設備的情況下,就可以用Scratch2進行ROS機器人編程。小學用Scratch2學習簡單編程,中學用Python學習簡單編程,大學用Python和C++學習複雜機器人編程,無縫銜接。
3 scratch2python.py
[python] view plain copy print?
- #!/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"
- 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 pythonn
- # -*- coding: utf-8 -*-nn
- import timen
- import confign
- import sysn
- import commn
- import osn
- import yamlnn
- from drone import Dronen
- from robot import Robotnn
- def execute(robot):n
- ttry:n
- t%s
- except KeyboardInterrupt:n
- ttraisenn
- if __name__ == __main__:n
- tif len(sys.argv) == 2:n
- ttpath = os.getcwd()n
- ttopen_path = path[:path.rfind(src)] + cfg/n
- ttfilename = sys.argv[1]nn
- telse:n
- ttsys.exit("ERROR: Example:python my_generated_script.py cfgfile.yml")nn
- t# loading the ICE and ROS parametersn
- tcfg = config.load(open_path + filename)n
- tstream = open(open_path + filename, "r")n
- tyml_file = yaml.load(stream)nn
- tfor section in yml_file:n
- ttif section == drone:n
- ttt#starting commn
- tttjdrc = comm.init(cfg,drone)nn
- ttt# creating the objectn
- tttrobot = Drone(jdrc)nn
- tttbreakn
- ttelif section == robot:n
- ttt#starting commn
- tttjdrc = comm.init(cfg,robot)nn
- ttt# creating the objectn
- tttrobot = Robot(jdrc)nn
- tttbreakn
- t# executing the scratch programn
- texecute(robot)nn
- "
- # 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:ntpython scratch2python.py hello_world.sb2")
推薦閱讀:
※【ROS教程 007】3D建模與模擬
※怎樣用ROS打造機器人建圖導航
※ROS和ROS2.0現在到底該學習哪個呢?
※基於ROS的自主導航小車Plantbot--SLAM
※ROS機器人操作系統相關書籍、資料和學習路徑
TAG:机器人操作平台ROS |