From 69305ae1ed6da084b6ee65dba3ce44f0d6cbe2d1 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Thu, 30 Apr 2009 09:53:44 +0200 Subject: * host/simu, digital/io/tools: - new simulation infrastructure. --- digital/io/tools/test_simu.py | 35 +++++--- host/simu/inter/drawable.py | 10 +++ host/simu/inter/inter.py | 127 ++++++++++++++++++++++++++++ host/simu/inter/inter_node.py | 110 ++++++++++++++++++++++++ host/simu/model/__init__.py | 0 host/simu/model/position.py | 39 +++++++++ host/simu/model/servo.py | 38 +++++++++ host/simu/model/switch.py | 39 +++++++++ host/simu/robots/__init__.py | 0 host/simu/robots/giboulee/__init__.py | 0 host/simu/robots/giboulee/link/__init__.py | 0 host/simu/robots/giboulee/link/bag.py | 33 ++++++++ host/simu/robots/giboulee/model/__init__.py | 0 host/simu/robots/giboulee/model/arm.py | 38 +++++++++ host/simu/robots/giboulee/model/bag.py | 38 +++++++++ host/simu/robots/giboulee/model/sorter.py | 32 +++++++ host/simu/robots/giboulee/view/__init__.py | 0 host/simu/robots/giboulee/view/arm.py | 60 +++++++++++++ host/simu/robots/giboulee/view/bag.py | 41 +++++++++ host/simu/robots/giboulee/view/robot.py | 64 ++++++++++++++ host/simu/robots/giboulee/view/sorter.py | 61 +++++++++++++ host/simu/view/__init__.py | 0 host/simu/view/servo.py | 54 ++++++++++++ host/simu/view/switch.py | 40 +++++++++ host/simu/view/table_eurobot2008.py | 98 +++++++++++++++++++++ 25 files changed, 946 insertions(+), 11 deletions(-) create mode 100644 host/simu/inter/inter.py create mode 100644 host/simu/inter/inter_node.py create mode 100644 host/simu/model/__init__.py create mode 100644 host/simu/model/position.py create mode 100644 host/simu/model/servo.py create mode 100644 host/simu/model/switch.py create mode 100644 host/simu/robots/__init__.py create mode 100644 host/simu/robots/giboulee/__init__.py create mode 100644 host/simu/robots/giboulee/link/__init__.py create mode 100644 host/simu/robots/giboulee/link/bag.py create mode 100644 host/simu/robots/giboulee/model/__init__.py create mode 100644 host/simu/robots/giboulee/model/arm.py create mode 100644 host/simu/robots/giboulee/model/bag.py create mode 100644 host/simu/robots/giboulee/model/sorter.py create mode 100644 host/simu/robots/giboulee/view/__init__.py create mode 100644 host/simu/robots/giboulee/view/arm.py create mode 100644 host/simu/robots/giboulee/view/bag.py create mode 100644 host/simu/robots/giboulee/view/robot.py create mode 100644 host/simu/robots/giboulee/view/sorter.py create mode 100644 host/simu/view/__init__.py create mode 100644 host/simu/view/servo.py create mode 100644 host/simu/view/switch.py create mode 100644 host/simu/view/table_eurobot2008.py diff --git a/digital/io/tools/test_simu.py b/digital/io/tools/test_simu.py index 943d6935..158b006e 100644 --- a/digital/io/tools/test_simu.py +++ b/digital/io/tools/test_simu.py @@ -32,14 +32,21 @@ import io import io.init from proto.popen_io import PopenIO -from inter.inter_node import InterNode +import simu.view.table_eurobot2008 as table +import simu.robots.giboulee.link.bag as robot_link +import simu.robots.giboulee.model.bag as robot_model +import simu.robots.giboulee.view.bag as robot_view + +from simu.inter.inter_node import InterNode from Tkinter import * class TestSimu (InterNode): - """Inter, with simulated programs.""" + """Interface, with simulated programs.""" - robot_start_pos = ((200, 2100 - 70, math.radians (-90)), - (3000 - 200, 2100 - 70, math.radians (-90))) + robot_start_pos = { + False: (200, 2100 - 70, math.radians (-90)), + True: (3000 - 200, 2100 - 70, math.radians (-90)) + } def __init__ (self, asserv_cmd, io_cmd): # Hub. @@ -48,7 +55,7 @@ class TestSimu (InterNode): # InterNode. InterNode.__init__ (self) def time (): - return self.node.date / self.TICK + return self.node.date / self.node.tick # Asserv. self.asserv = asserv.Proto (PopenIO (asserv_cmd), time, **asserv.init.host) @@ -58,9 +65,18 @@ class TestSimu (InterNode): self.io = io.Proto (PopenIO (io_cmd), time, **io.init.host) self.io.async = True self.tk.createfilehandler (self.io, READABLE, self.io_read) + # Add table. + self.table = table.Table (self.table_view) + # Add robot. + self.robot_link = robot_link.Bag (self.node) + self.robot_model = robot_model.Bag (self.robot_link) + self.robot_view = robot_view.Bag (self.table, self.actuator_view, + self.sensor_frame, self.robot_model) + for adc in self.robot_link.io.adc: + adc.value = 0 # Color switch. + self.robot_model.color_switch.register (self.change_color) self.change_color () - self.colorVar.trace_variable ('w', self.change_color) def close (self): self.forked_hub.kill () @@ -85,13 +101,10 @@ class TestSimu (InterNode): self.io.proto.sync () def change_color (self, *dummy): - i = self.colorVar.get () + i = self.robot_model.color_switch.state self.asserv.set_simu_pos (*self.robot_start_pos[i]); if __name__ == '__main__': app = TestSimu (('../../asserv/src/asserv/asserv.host', '-m', 'giboulee'), ('../src/io.host')) - try: - app.mainloop () - finally: - app.close () + app.mainloop () diff --git a/host/simu/inter/drawable.py b/host/simu/inter/drawable.py index d11ad9d6..bcf1823f 100644 --- a/host/simu/inter/drawable.py +++ b/host/simu/inter/drawable.py @@ -140,6 +140,16 @@ class DrawableCanvas(Tkinter.Canvas): self.__updated = [ ] self._Drawable__children = [ ] + def resize (self, width, height, xorigin = None, yorigin = None): + """Change size given at initialisation. Will be used on next + configure event.""" + self.__width = width + self.__height = height + if xorigin is not None: + self.__xorigin = xorigin + if yorigin is not None: + self.__yorigin = yorigin + def __resize (self, ev): # Compute new scale. w, h = float (ev.width), float (ev.height) diff --git a/host/simu/inter/inter.py b/host/simu/inter/inter.py new file mode 100644 index 00000000..b8a889e5 --- /dev/null +++ b/host/simu/inter/inter.py @@ -0,0 +1,127 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Simulation interface.""" +from simu.inter.drawable import * +from Tkinter import * + +class TableView (DrawableCanvas): + """This class handle the view of the table and every items inside it.""" + + TABLE_WIDTH = 3000 + TABLE_HEIGHT = 2100 + MARGIN = 150 + + def __init__ (self, master = None, + width = TABLE_WIDTH, height = TABLE_HEIGHT): + DrawableCanvas.__init__ (self, + width + 2 * self.MARGIN, height + 2 * self.MARGIN, + -width / 2, -height / 2, + master, borderwidth = 1, relief = 'sunken', + background = 'white') + +class ActuatorView (DrawableCanvas): + """This class handle the view of the actuators inside the robot.""" + + UNIT = 120 + + def __init__ (self, master = None): + DrawableCanvas.__init__ (self, 1, 1, 0, 0, master, + borderwidth = 1, relief = 'sunken', background = 'white') + self.configure (width = self.UNIT, height = self.UNIT) + self.size = 0.0 + + def add_view (self, width = 1.0, height = 1.0): + """Return a drawable suitable for an actuator view.""" + ratio = float (height) / float (width) + self.size += ratio + self.resize (1, self.size, 0, self.size / 2) + self.configure (width = self.UNIT, height = self.UNIT * self.size) + d = Drawable (self) + d.trans_scale (1.0 / width) + d.trans_translate ((0, - self.size + ratio / 2)) + return d + +class Inter (Frame): + """Robot simulation interface.""" + + def __init__ (self, master = None): + Frame.__init__ (self, master) + self.pack (expand = True, fill = 'both') + self.create_widgets () + + def create_widgets (self): + # Main layout. + self.right_frame = Frame (self) + self.right_frame.pack (side = 'right', fill = 'y') + self.quit_button = Button (self.right_frame, text = 'Quit', + command = self.quit) + self.quit_button.pack (side = 'top') + # Actuator view. + self.actuator_view = ActuatorView (self.right_frame) + self.actuator_view.pack (side = 'bottom', fill = 'x') + # Sensor frame. + self.sensor_frame = Frame (self.right_frame, borderwidth = 1, + relief = 'sunken') + self.sensor_frame.pack (side = 'bottom', fill = 'x') + # Table view. + self.table_view = TableView (self) + self.table_view.pack (expand = True, fill = 'both') + + def update (self, *args): + self.table_view.update () + self.actuator_view.update () + +if __name__ == '__main__': + class TestTable (Drawable): + def __init__ (self, onto, w, h): + Drawable.__init__ (self, onto) + self.w, self.h = w, h + def draw (self): + self.reset () + w, h = self.w, self.h + self.draw_rectangle ((0, 0), (w, h), fill = 'blue') + Drawable.draw (self) + class TestRectangle (Drawable): + def __init__ (self, onto, w, h, c1, c2): + Drawable.__init__ (self, onto) + self.w, self.h = 0.9 * w, 0.9 * h + self.c1, self.c2 = c1, c2 + def draw (self): + self.reset () + w, h = self.w, self.h + self.draw_rectangle ((-w/2, -h/2), (w/2, h/2), fill = self.c1) + self.draw_rectangle ((0, 0), (w/2, h/2), fill = self.c2) + Drawable.draw (self) + class TestSensor: + def __init__ (self, master): + self.button = Checkbutton (master, text = 'Sensor', + indicatoron = False) + self.button.pack (side = 'top') + app = Inter () + TestTable (app.table_view, 3000, 2100) + TestRectangle (app.actuator_view.add_view (1, 1), 1, 1, 'red', 'green') + TestRectangle (app.actuator_view.add_view (2, 1), 2, 1, 'green', 'blue') + TestRectangle (app.actuator_view.add_view (1, 2), 1, 2, 'blue', 'red') + TestSensor (app.sensor_frame) + app.mainloop () diff --git a/host/simu/inter/inter_node.py b/host/simu/inter/inter_node.py new file mode 100644 index 00000000..ab1b5acf --- /dev/null +++ b/host/simu/inter/inter_node.py @@ -0,0 +1,110 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Simulation interface coupled with a mex node.""" +from simu.inter.inter import Inter +from mex.node import Node +from Tkinter import * +import time + +class InterNode (Inter): + + def __init__ (self): + Inter.__init__ (self) + # Create node and bind to Tk. + self.node = Node () + self.node.tick = 900 # tick/s + self.tk.createfilehandler (self.node, READABLE, self.read) + # Animation attributes. + self.date = 0 + self.synced = True + self.step_after = None + self.step_time = None + + def create_widgets (self): + Inter.create_widgets (self) + self.now_label = Label (self.right_frame, text = 'Now: 0 s') + self.now_label.pack () + self.step_button = Button (self.right_frame, text = 'Step', + command = self.step) + self.step_button.pack () + self.step_size_scale = Scale (self.right_frame, orient = HORIZONTAL, + from_ = 0.05, to = 1.0, resolution = 0.05) + self.step_size_scale.pack () + self.play_var = IntVar () + self.play_button = Checkbutton (self.right_frame, + variable = self.play_var, text = 'Play', command = self.play) + self.play_button.pack () + + def step (self): + """Do a step. Signal to the Hub we are ready to wait to the next step + date.""" + self.node.wait_async (self.date + + int (self.step_size_scale.get () * self.node.tick)) + self.synced = False + self.step_after = None + self.step_time = time.time () + + def play (self): + """Activate auto-steping.""" + if self.play_var.get (): + if self.step_after is None and self.synced: + self.step () + self.step_button.configure (state = DISABLED) + else: + if self.step_after is not None: + self.after_cancel (self.step_after) + self.step_after = None + self.step_button.configure (state = NORMAL) + + def read (self, file, mask): + """Handle event on the Node.""" + self.node.read () + if not self.synced and self.node.sync (): + self.synced = True + self.date = self.node.date + self.now_label.configure (text = 'Now: %.2f s' + % (float (self.date) / self.node.tick)) + self.update () + if self.play_var.get (): + assert self.step_after is None + next = self.step_time + self.step_size_scale.get () + delay = next - time.time () + if delay > 0: + self.step_after = self.after (int (delay * 1000), + self.step) + else: + self.step () + +if __name__ == '__main__': + import mex.hub + import utils.forked + h = mex.hub.Hub (min_clients = 1) + fh = utils.forked.Forked (h.wait) + try: + app = InterNode () + app.mainloop() + finally: + fh.kill () + import time + time.sleep (1) diff --git a/host/simu/model/__init__.py b/host/simu/model/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/host/simu/model/position.py b/host/simu/model/position.py new file mode 100644 index 00000000..eec395e7 --- /dev/null +++ b/host/simu/model/position.py @@ -0,0 +1,39 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Robot position model.""" +from utils.observable import Observable + +class Position (Observable): + + def __init__ (self, link): + Observable.__init__ (self) + self.link = link + self.link.register (self.__notified) + self.__notified () + + def __notified (self): + self.pos = self.link.pos + self.angle = self.link.angle + self.notify () + diff --git a/host/simu/model/servo.py b/host/simu/model/servo.py new file mode 100644 index 00000000..7c83d4b3 --- /dev/null +++ b/host/simu/model/servo.py @@ -0,0 +1,38 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Servo motor model.""" +from utils.observable import Observable + +class Servo (Observable): + + def __init__ (self, link): + Observable.__init__ (self) + self.link = link + self.link.register (self.__notified) + self.__notified () + + def __notified (self): + self.value = self.link.value + self.notify () + diff --git a/host/simu/model/switch.py b/host/simu/model/switch.py new file mode 100644 index 00000000..617a22ff --- /dev/null +++ b/host/simu/model/switch.py @@ -0,0 +1,39 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Switch model.""" +from utils.observable import Observable + +class Switch (Observable): + + def __init__ (self, link): + Observable.__init__ (self) + self.link = link + self.state = None + self.register (self.__update) + self.__update () + + def __update (self): + self.link.state = self.state + self.link.notify () + diff --git a/host/simu/robots/__init__.py b/host/simu/robots/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/host/simu/robots/giboulee/__init__.py b/host/simu/robots/giboulee/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/host/simu/robots/giboulee/link/__init__.py b/host/simu/robots/giboulee/link/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/host/simu/robots/giboulee/link/bag.py b/host/simu/robots/giboulee/link/bag.py new file mode 100644 index 00000000..c8c1b285 --- /dev/null +++ b/host/simu/robots/giboulee/link/bag.py @@ -0,0 +1,33 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Giboulee bag of links.""" +import io.mex +import asserv.mex + +class Bag: + + def __init__ (self, node): + self.asserv = asserv.mex.Mex (node) + self.io = io.mex.Mex (node) + diff --git a/host/simu/robots/giboulee/model/__init__.py b/host/simu/robots/giboulee/model/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/host/simu/robots/giboulee/model/arm.py b/host/simu/robots/giboulee/model/arm.py new file mode 100644 index 00000000..cfefd11b --- /dev/null +++ b/host/simu/robots/giboulee/model/arm.py @@ -0,0 +1,38 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Giboulee arm.""" +from utils.observable import Observable + +class Arm (Observable): + + def __init__ (self, motor_link): + Observable.__init__ (self) + self.motor_link = motor_link + self.motor_link.register (self.__motor_notified) + self.__motor_notified () + + def __motor_notified (self): + self.angle = self.motor_link.angle + self.notify () + diff --git a/host/simu/robots/giboulee/model/bag.py b/host/simu/robots/giboulee/model/bag.py new file mode 100644 index 00000000..fadccabe --- /dev/null +++ b/host/simu/robots/giboulee/model/bag.py @@ -0,0 +1,38 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Giboulee bag of models.""" +from simu.model.switch import Switch +from simu.model.position import Position +from simu.robots.giboulee.model.arm import Arm +from simu.robots.giboulee.model.sorter import Sorter + +class Bag: + + def __init__ (self, link_bag): + self.jack = Switch (link_bag.io.jack) + self.color_switch = Switch (link_bag.io.color_switch) + self.position = Position (link_bag.asserv.position) + self.arm = Arm (link_bag.asserv.aux[0]) + self.sorter = Sorter (link_bag.io.servo[0:5], link_bag.io.servo[5]) + diff --git a/host/simu/robots/giboulee/model/sorter.py b/host/simu/robots/giboulee/model/sorter.py new file mode 100644 index 00000000..042b0717 --- /dev/null +++ b/host/simu/robots/giboulee/model/sorter.py @@ -0,0 +1,32 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Giboulee balls sorter.""" +from simu.model.servo import Servo + +class Sorter: + + def __init__ (self, trap_servo_links, door_servo_link): + self.traps = [ Servo (link) for link in trap_servo_links ] + self.door = Servo (door_servo_link) + diff --git a/host/simu/robots/giboulee/view/__init__.py b/host/simu/robots/giboulee/view/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/host/simu/robots/giboulee/view/arm.py b/host/simu/robots/giboulee/view/arm.py new file mode 100644 index 00000000..205857a2 --- /dev/null +++ b/host/simu/robots/giboulee/view/arm.py @@ -0,0 +1,60 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Giboulee arm.""" +from simu.inter.drawable import Drawable +from math import pi, cos, sin + +class Arm (Drawable): + """Giboulee arm.""" + + width = 1 + height = 1 + + def __init__ (self, onto, model): + Drawable.__init__ (self, onto) + self.model = model + self.model.register (self.__notified) + self.__notified () + + def __notified (self): + self.angle = self.model.angle + self.update () + + def draw (self): + self.reset () + self.draw_arc ((0, 0), 0.45, start = 7 * pi / 12, extent = 10 * pi / 12, + style = 'arc', outline = '#808080') + self.draw_arc ((0, 0), 0.45, start = -5 * pi / 12, extent = 10 * pi / 12, + style = 'arc', outline = '#808080') + self.draw_arc ((0, 0), 0.25, start = -7 * pi / 12, extent = 14 * pi / 12, + style = 'arc', outline = '#808080') + if self.angle is not None: + self.trans_scale (0.4) + self.trans_rotate (-self.angle) + self.draw_line ((0, 0), (0, 1)) + self.draw_line ((0, 1), (0.3, 1), arrow = 'last', fill = '#808080') + self.draw_line ((0, 0), (cos (pi / 6), -sin (pi / 6))) + self.draw_line ((0, 0), (-cos (pi / 6), -sin (pi / 6))) + Drawable.draw (self) + diff --git a/host/simu/robots/giboulee/view/bag.py b/host/simu/robots/giboulee/view/bag.py new file mode 100644 index 00000000..709d775f --- /dev/null +++ b/host/simu/robots/giboulee/view/bag.py @@ -0,0 +1,41 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Giboulee bag of views.""" +from simu.view.switch import Switch +from simu.robots.giboulee.view.robot import Robot +from simu.robots.giboulee.view.arm import Arm +from simu.robots.giboulee.view.sorter import Sorter + +class Bag: + + def __init__ (self, table, actuator_view, sensor_frame, model_bag): + self.jack = Switch (sensor_frame, model_bag.jack, 'Jack') + self.color_switch = Switch (sensor_frame, model_bag.color_switch, + 'Color') + self.robot = Robot (table, model_bag.position) + self.arm = Arm (actuator_view.add_view (Arm.width, Arm.height), + model_bag.arm) + self.sorter = Sorter (actuator_view.add_view (Sorter.width, + Sorter.height), model_bag.sorter) + diff --git a/host/simu/robots/giboulee/view/robot.py b/host/simu/robots/giboulee/view/robot.py new file mode 100644 index 00000000..2ffcacb2 --- /dev/null +++ b/host/simu/robots/giboulee/view/robot.py @@ -0,0 +1,64 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2008 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Giboulee robot view.""" +import simu.inter.drawable + +class Robot (simu.inter.drawable.Drawable): + + def __init__ (self, onto, position_model): + """Construct and make connections.""" + simu.inter.drawable.Drawable.__init__ (self, onto) + self.position_model = position_model + self.position_model.register (self.__position_notified) + self.__position_notified () + + def __position_notified (self): + """Called on position modifications.""" + self.pos = self.position_model.pos + self.angle = self.position_model.angle + self.update () + + def draw (self): + """Draw the robot.""" + self.reset () + if self.pos is not None: + self.trans_rotate (self.angle) + self.trans_translate (self.pos) + # Draw robot body. + self.draw_polygon ((115, 30), (170, 85), (150, 127), (130, 145), + (-25, 200), (-70, 200), (-70, -200), (-25, -200), + (130, -145), (150, -127), (170, -85), (115, -30)) + # Draw Robot axis. + axes_fill = '#404040' + self.draw_line ((-70, 0), (170, 0), fill = axes_fill, + arrow = 'last') + # Draw Robot wheels. + f = 142 + 2 * 31.5 - 13.5 # Wheel spacing + wr = 63 / 2 # Wheel diameter + self.draw_line ((0, +f / 2), (0, -f / 2), fill = axes_fill) + self.draw_line ((-wr, f / 2), (+wr, f / 2), fill = axes_fill) + self.draw_line ((-wr, -f / 2), (+wr, -f / 2), fill = axes_fill) + # Extends. + simu.inter.drawable.Drawable.draw (self) + diff --git a/host/simu/robots/giboulee/view/sorter.py b/host/simu/robots/giboulee/view/sorter.py new file mode 100644 index 00000000..a0e09197 --- /dev/null +++ b/host/simu/robots/giboulee/view/sorter.py @@ -0,0 +1,61 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Giboulee balls sorter.""" +from simu.inter.drawable import Drawable +from simu.view.servo import Servo +from math import pi + +class Sorter (Drawable): + + width = 1 + height = 1 + + def __init__ (self, onto, sorter_model): + Drawable.__init__ (self, onto) + self.traps = [ + Servo (self, sorter_model.traps[0], + (-2.5, -1), 0.8, 0, pi/2), + Servo (self, sorter_model.traps[1], + (-1.5, -0.9), 0.8, 0, pi/2), + Servo (self, sorter_model.traps[2], + (-0.5, -0.8), 0.8, 0, pi/2), + Servo (self, sorter_model.traps[3], + (0.5, -0.8), 0.8, pi, -pi/2), + Servo (self, sorter_model.traps[4], + (1.5, -0.9), 0.8, pi, -pi/2), + ] + self.door = Servo (self, sorter_model.door, + (-2.5, 1.3), 0.8, -pi/6, pi/3), + + def draw (self): + self.reset () + self.trans_scale (0.9/5) + self.draw_line ((-0.5, 1.5), (-0.5, 0.5), (-2.5, 0.2), + fill = '#808080') + self.draw_line ((-2.5, -1.2), (-2.5, -2.3), (2.5, -2.3), (2.5, 0.2), + (0.5, 0.5), (0.5, 1.5), fill = '#808080') + for i in (-1.5, -0.5, 0.5, 1.5): + self.draw_line ((i, -2.3), (i, -2), fill = '#808080') + Drawable.draw (self) + diff --git a/host/simu/view/__init__.py b/host/simu/view/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/host/simu/view/servo.py b/host/simu/view/servo.py new file mode 100644 index 00000000..7c67df09 --- /dev/null +++ b/host/simu/view/servo.py @@ -0,0 +1,54 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Generic servo motor.""" +from simu.inter.drawable import Drawable +from math import pi, sin, cos + +class Servo (Drawable): + + def __init__ (self, onto, model, coord = (0, 0), l = 1, start = 0, + extent = pi / 2): + Drawable.__init__ (self, onto) + self.model = model + self.coord = coord + self.l = l + self.start = start + self.extent = extent + self.model.register (self.__notified) + self.__notified () + + def __notified (self): + self.value = self.model.value + self.update () + + def draw (self): + self.reset () + if self.value is not None: + self.draw_arc (self.coord, self.l, start = self.start, + extent = self.extent, style = 'arc', outline = '#808080') + a = self.start + self.value * self.extent + self.draw_line (self.coord, (self.coord[0] + self.l * cos (a), + self.coord[1] + self.l * sin (a))) + Drawable.draw (self) + diff --git a/host/simu/view/switch.py b/host/simu/view/switch.py new file mode 100644 index 00000000..c0ec2d58 --- /dev/null +++ b/host/simu/view/switch.py @@ -0,0 +1,40 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2009 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Generic switch.""" +from Tkinter import * + +class Switch: + + def __init__ (self, frame, model, text): + self.var = IntVar () + self.button = Checkbutton (frame, variable = self.var, + command = self.__update, text = text, indicatoron = False) + self.button.pack () + self.model = model + self.__update () + + def __update (self): + self.model.state = self.var.get () != 0 + self.model.notify () + diff --git a/host/simu/view/table_eurobot2008.py b/host/simu/view/table_eurobot2008.py new file mode 100644 index 00000000..b956101a --- /dev/null +++ b/host/simu/view/table_eurobot2008.py @@ -0,0 +1,98 @@ +# simu - Robot simulation. {{{ +# +# Copyright (C) 2008 Nicolas Schodet +# +# APBTeam: +# Web: http://apbteam.org/ +# Email: team AT apbteam DOT org +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# }}} +"""Eurobot 2008 table.""" +from simu.inter.drawable import Drawable + +class Table (Drawable): + """The table and its elements.""" + + def draw (self): + # Redraw. + self.reset () + # Table. + self.draw_rectangle ((-22, -22 - 80), (3000 / 2, 2100 + 22), fill = '#ff1f1f') + self.draw_rectangle ((3000 / 2, -22 - 80), (3000 + 22, 2100 + 22), fill = '#201fff') + self.draw_rectangle ((0, 0), (3000, 2100), fill = '#a49d8b') + self.draw_rectangle ((0, -22 - 80), (3000, -22), fill = '#a49d8b') + self.draw_rectangle ((0, 2100 - 500), (500, 2100), fill = '#201fff') + self.draw_rectangle ((3000 - 500, 2100 - 500), (3000, 2100), fill = '#ff1f1f') + self.draw_line ((3000 / 2, -22 - 80), (3000 / 2, 2100 + 22)) + # Axes. + self.draw_line ((0, 200), (0, 0), (200, 0), arrow = 'both') + # Beacons and baskets. + self.draw_rectangle ((-22, 2100), (-22 - 80, 2100 + 80), fill = '#5b5b5d') + self.draw_rectangle ((-22, 1050 - 40), (-22 - 80, 1050 + 40), fill = '#5b5b5d') + self.draw_rectangle ((-22, 500), (-22 - 80, 500 + 80), fill = '#5b5b5d') + self.draw_rectangle ((-22, -80), (-22 - 80, 0), fill = '#5b5b5d') + self.draw_rectangle ((-22, 0), (-22 - 80, 500), fill = '#5b5b5d') + self.draw_rectangle ((-22 - 80 - 250, 0), (-22 - 80, 500), fill = '#6d6dad', stipple = 'gray75') + self.draw_rectangle ((3000 + 22, 2100), (3000 + 22 + 80, 2100 + 80), fill = '#5b5b5d') + self.draw_rectangle ((3000 + 22, 1050 - 40), (3000 + 22 + 80, 1050 + 40), fill = '#5b5b5d') + self.draw_rectangle ((3000 + 22, 500), (3000 + 22 + 80, 500 + 80), fill = '#5b5b5d') + self.draw_rectangle ((3000 + 22, -80), (3000 + 22 + 80, 0), fill = '#5b5b5d') + self.draw_rectangle ((3000 + 22, 0), (3000 + 22 + 80, 500), fill = '#5b5b5d') + self.draw_rectangle ((3000 + 22 + 80 + 250, 0), (3000 + 22 + 80, 500), fill = '#6d6dad', stipple = 'gray75') + # Vertical dispensers. + self.draw_rectangle ((-22, 2100 - 750 - 85 / 2), (0, 2100 - 750 + 85 / 2), fill = '#5b5b5b') + self.draw_circle ((40, 2100 - 750), 40) + self.draw_rectangle ((700 - 85 / 2, 2100), (700 + 85 / 2, 2100 + 22), fill = '#5b5b5b') + self.draw_circle ((700, 2100 - 40), 40) + self.draw_rectangle ((3000 + 22, 2100 - 750 - 85 / 2), (3000, 2100 - 750 + 85 / 2), fill = '#5b5b5b') + self.draw_circle ((3000 - 40, 2100 - 750), 40) + self.draw_rectangle ((3000 - 700 + 85 / 2, 2100), (3000 - 700 - 85 / 2, 2100 + 22), fill = '#5b5b5b') + self.draw_circle ((3000 - 700, 2100 - 40), 40) + # Horizontal dispenser. + self.draw_rectangle ((3000 / 2 - 924 / 2, 2100 + 22), (3000 / 2 + 924 / 2, 2100 + 22 + 80 + 22), fill = '#5b5b5b') + self.draw_rectangle ((3000 / 2 - 924 / 2 + 22, 2100 + 22), (3000 / 2 + 924 / 2 - 22, 2100 + 22 + 80), fill = '#5b5b5b') + self.draw_rectangle ((3000 / 2 - 880 / 2 - 35 - 60, 2100), (3000 / 2 - 880 / 2 - 35, 2100 + 44), fill = '#5b5b5b') + self.draw_rectangle ((3000 / 2 + 880 / 2 + 35 + 60, 2100), (3000 / 2 + 880 / 2 + 35, 2100 + 44), fill = '#5b5b5b') + # Balls. + balls = [ (800, 200, 'rb'), (800, 400, 'RB'), (800, 600, 'ww'), + (1300, 200, 'rb'), (1300, 400, 'rb'), (1300, 600, 'ww'), + (520, 800, 'WW'), (700, 40, 'RB'), (40, 750, 'WW'), + (450, 1120, 'ww'), (750, 1070, 'ww'), (1050, 1020, 'ww'), + (1500 - 72 / 2, -22 - 80 / 2, 'BR'), + (1500 - 72 / 2 - 1 * 73, -22 - 80 / 2, 'RB'), + (1500 - 72 / 2 - 2 * 73, -22 - 80 / 2, 'BR'), + (1500 - 72 / 2 - 3 * 73, -22 - 80 / 2, 'RB'), + (1500 - 72 / 2 - 4 * 73, -22 - 80 / 2, 'BR'), + (1500 - 72 / 2 - 5 * 73, -22 - 80 / 2, 'RB'), + (1500, 1000, 'W'), + ] + balls_config = { 'r': { 'outline': '#bf4141' }, 'R': { 'fill': '#bf4141' }, + 'b': { 'outline': '#4241bf' }, 'B': { 'fill': '#4241bf' }, + 'w': { 'outline': '#bfbfbf' }, 'W': { 'fill': '#bfbfbf' } } + for b in balls: + self.draw_circle ((3000 - b[0], 2100 - b[1]), 72 / 2, + **balls_config[b[2][0]]) + if len (b[2]) > 1: + self.draw_circle ((b[0], 2100 - b[1]), 72 / 2, + **balls_config[b[2][1]]) + Drawable.draw (self) + +if __name__ == '__main__': + from simu.inter.inter import Inter + app = Inter () + Table (app.table_view) + app.mainloop () -- cgit v1.2.3