小朋友學ROS機器人——使用Scratch2和ROS進行機器人圖形化編程學習

版權聲明:本文為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?

  1. $ python scratch2python.py hiros.sb2
  2. Stringify:
  3. when @greenFlag clicked
  4. repeat 10
  5. say Hello,ROS Kinetic!
  6. end
  7. [WARN] Block <when @greenFlag clicked> not included yet
  8. -------------------
  9. #!/usr/bin/env python
  10. # -*- coding: utf-8 -*-
  11. import time
  12. import config
  13. import sys
  14. import comm
  15. import os
  16. import yaml
  17. from drone import Drone
  18. from robot import Robot
  19. def execute(robot):
  20. try:
  21. for i in range(10):
  22. print(Hello,ROS Kinetic!)
  23. except KeyboardInterrupt:
  24. raise
  25. if __name__ == __main__:
  26. if len(sys.argv) == 2:
  27. path = os.getcwd()
  28. open_path = path[:path.rfind(src)] + cfg/
  29. filename = sys.argv[1]
  30. else:
  31. sys.exit("ERROR: Example:python my_generated_script.py cfgfile.yml")
  32. # loading the ICE and ROS parameters
  33. cfg = config.load(open_path + filename)
  34. stream = open(open_path + filename, "r")
  35. yml_file = yaml.load(stream)
  36. for section in yml_file:
  37. if section == drone:
  38. #starting comm
  39. jdrc = comm.init(cfg,drone)
  40. # creating the object
  41. robot = Drone(jdrc)
  42. break
  43. elif section == robot:
  44. #starting comm
  45. jdrc = comm.init(cfg,robot)
  46. # creating the object
  47. robot = Robot(jdrc)
  48. break
  49. # executing the scratch program
  50. execute(robot)
  51. -------------------

2 控制機器人示例

是不是比較有趣,在不需購買任何設備的情況下,就可以用Scratch2進行ROS機器人編程。小學用Scratch2學習簡單編程,中學用Python學習簡單編程,大學用Python和C++學習複雜機器人編程,無縫銜接。

3 scratch2python.py

[python] view plain copy print?

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. __author__ = "Raul Perula-Martinez"
  4. __copyright__ = "JdeRobot project"
  5. __credits__ = ["Raul Perula-Martinez"]
  6. __license__ = "GPL v3"
  7. __version__ = "0.0.0"
  8. __maintainer__ = "Raul Perula-Martinez"
  9. __email__ = "raules@gmail.com"
  10. __status__ = "Development"
  11. import kurt
  12. import os
  13. import sys
  14. from difflib import SequenceMatcher
  15. from parse import parse, compile
  16. from termcolor import cprint
  17. GENERAL = [
  18. [end, ],
  19. [forever, while True:],
  20. [if {} then, if %s:],
  21. [else, else:],
  22. [repeat {}, for i in range(%s):],
  23. [say {}, print(%s)],
  24. [set {} to {}, %s = %s],
  25. [wait {} secs, time.sleep(%s)],
  26. ]
  27. ROBOTICS = [
  28. [move robot {}, robot.move("%s")],
  29. [move drone {}, robot.move("%s")],
  30. [move robot {} speed {}, robot.move("%s", %s)],
  31. [stop robot-drone, robot.stop()],
  32. [turn robot-drone {}, robot.turn("%s")],
  33. [turn robot {} speed {}, robot.turn("%s", %s)],
  34. [take off drone, robot.take_off()],
  35. [land drone, robot.land()],
  36. [frontal laser distance, robot.get_laser_distance()],
  37. ]
  38. def is_conditional(sentence):
  39. """
  40. Returns if a sentence is conditional or not.
  41. @param sentence: The sentence to check.
  42. @return: True if it has a conditional, False otherwise.
  43. """
  44. if "if" in sentence:
  45. return True
  46. return False
  47. def similar(a, b):
  48. """
  49. Returns the ratio value comparing two sentences.
  50. @param a: First sentence.
  51. @param b: Second sentence.
  52. @return: The ratio of the similarity.
  53. """
  54. return SequenceMatcher(None, a, b).ratio()
  55. def sentence_mapping(sentence, threshold=None):
  56. """
  57. Maps a sentence and returns the original and the mapped.
  58. @param sentence: The sentence to map.
  59. @return: The original sentence and the mapped sentence.
  60. """
  61. found = False
  62. options = []
  63. original = None
  64. translation = None
  65. # first look for general blocks
  66. for elem in GENERAL:
  67. if elem[0][:3] == sentence.replace( , )[:3]:
  68. options.append(elem)
  69. found = True
  70. # then look for robotics blocks
  71. for elem in ROBOTICS:
  72. if elem[0][:3] == sentence.replace( , ).replace((, )[:3]:
  73. options.append(elem)
  74. found = True
  75. if found:
  76. # select the option that better fits
  77. l = [(m[0], m[1], similar(sentence, m[0])) for m in options]
  78. original, translation, score = max(l, key=lambda item: item[2])
  79. if threshold and score < threshold:
  80. return None, None
  81. # extract arguments
  82. p = compile(original)
  83. args = p.parse(sentence.replace( , ))
  84. if args:
  85. args_aux = list(args)
  86. # look for more blocks
  87. for idx in range(len(args_aux)):
  88. new_ori, new_trans = sentence_mapping(args_aux[idx]) #sentence_mapping(args_aux[idx],0.8) --old
  89. if new_trans != None:
  90. args_aux[idx] = args_aux[idx].replace(new_ori, new_trans) #replace(args_aux[idx], new_trans)
  91. translation = translation % tuple(args_aux)
  92. return original, translation
  93. if __name__ == "__main__":
  94. # get current working directory
  95. path = os.getcwd()
  96. open_path = path[:path.rfind(scripts)] + data/
  97. save_path = path[:path.rfind(scripts)] + src/scratch2jderobot/
  98. if len(sys.argv) == 2:
  99. # template creation
  100. template = "
  101. #!/usr/bin/env pythonn
  102. # -*- coding: utf-8 -*-nn
  103. import timen
  104. import confign
  105. import sysn
  106. import commn
  107. import osn
  108. import yamlnn
  109. from drone import Dronen
  110. from robot import Robotnn
  111. def execute(robot):n
  112. ttry:n
  113. t%s
  114. except KeyboardInterrupt:n
  115. ttraisenn
  116. if __name__ == __main__:n
  117. tif len(sys.argv) == 2:n
  118. ttpath = os.getcwd()n
  119. ttopen_path = path[:path.rfind(src)] + cfg/n
  120. ttfilename = sys.argv[1]nn
  121. telse:n
  122. ttsys.exit("ERROR: Example:python my_generated_script.py cfgfile.yml")nn
  123. t# loading the ICE and ROS parametersn
  124. tcfg = config.load(open_path + filename)n
  125. tstream = open(open_path + filename, "r")n
  126. tyml_file = yaml.load(stream)nn
  127. tfor section in yml_file:n
  128. ttif section == drone:n
  129. ttt#starting commn
  130. tttjdrc = comm.init(cfg,drone)nn
  131. ttt# creating the objectn
  132. tttrobot = Drone(jdrc)nn
  133. tttbreakn
  134. ttelif section == robot:n
  135. ttt#starting commn
  136. tttjdrc = comm.init(cfg,robot)nn
  137. ttt# creating the objectn
  138. tttrobot = Robot(jdrc)nn
  139. tttbreakn
  140. t# executing the scratch programn
  141. texecute(robot)nn
  142. "
  143. # load the scratch project
  144. p = kurt.Project.load(open_path + sys.argv[1])
  145. # show the blocks included
  146. for scriptable in p.sprites + [p.stage]:
  147. for script in scriptable.scripts:
  148. # exclude definition scripts
  149. if "define" not in script.blocks[0].stringify():
  150. s = script
  151. print("Stringify:")
  152. sentences = []
  153. for b in s.blocks:
  154. print(b.stringify())
  155. sentences += b.stringify().split(n)
  156. tab_seq = "t"
  157. python_program = ""
  158. for s in sentences:
  159. # count number of tabs
  160. num_tabs = s.replace( , tab_seq).count(tab_seq)
  161. python_program += tab_seq * (num_tabs + 1)
  162. # pre-processing if there is a condition (operators and types)
  163. if is_conditional(s):
  164. s = s.replace("", "").replace("=", "==")
  165. # mapping
  166. original, translation = sentence_mapping(s)
  167. # set the code
  168. if translation != None:
  169. python_program += translation
  170. else:
  171. cprint("[WARN] Block <%s> not included yet" % s, yellow)
  172. python_program += "n" + tab_seq
  173. # join the template with the code and replace the tabs
  174. file_text = template % python_program
  175. file_text = file_text.replace(tab_seq, * 4)
  176. print("n-------------------")
  177. cprint(file_text, green)
  178. print("-------------------n")
  179. # save the code in a python file with the same name as sb2 file
  180. file_name = sys.argv[1].replace(.sb2,.py)
  181. f = open(save_path + file_name, "w")
  182. f.write(file_text)
  183. f.close()
  184. else:
  185. print(
  186. "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 |