Applaus für Wikipedia

Wikipedia ist seinem Ruf als technophobe Mitmachenzyklopädie wieder vollumfänglich gerecht geworden. Darunter leiden musste diesmal der Eintrag „Shadow Robot Company“. Für alle, die nicht mit ROS, den Arbeiten von Emo Todorov oder dem Moley Kitchen Robot vertraut sind sei gesagt, dass es nicht irgendein Unternehmen ist, sondern es ist DAS Unternehmen. Aber das weiß Wikipedia selber am allerbesten und genau deshalb gab es pünktlich am 24. Jan 2017 auch den Löschantrag: https://de.wikipedia.org/wiki/Wikipedia:L%C3%B6schkandidaten/24._Januar_2017#Shadow_Robot_Company

Da kann man nur Beifall klatschen für soviel gebündelten Zorn gegenüber Robotik und Künstlicher Intelligenz. Schon Ned Ludd hat gesagt, dass man alles kaputt machen soll, was nach Technik aussieht, das gilt insbesondere für Technik die vergöttert wird, die man selber nicht versteht und die womöglich vom Teufel besessen ist. All das trifft auf die Shadow Dexterous Hand vollumfänglich zu, insofern ist die Entscheidung von Wikipedia stimmig.

Was kommt als nächstes? Gute Kandidaten die man ebenfalls noch aus Wikipedia rauslöschen könnte um das Lexikon von Robotik und Künstlicher Intelligenz zu reinigen wären: ROS, LISP, Rethink Robotics, C++, IBM oder dwave. Es bleibt abzuwarten wo der Hexenhammer als nächstes zuschlägt, es wird mit Sicherheit eines von diesen Tech-Lemmas sein.

Bravo liebe Wikipedia. Immer weiter so mit dem Kreuzzug gegenüber der Moderne. Dass die Themen aus Physik, Mathematik und Informatik schon immer nachlässig recherchiert wurden war bekannt. Das Portal Informatik ist innerhalb von Wikipedia in einem echt üblen Zustand. Aber das man jetzt auch noch aktiv Artikel löscht ist schon etwas besonderes. Wikipedia sammelt damit Pluspunkte bei den Hardcore-Neoludditen welche den Naturwissenschaften skeptisch bis ablehnend gegenüberstehen und sich bei den Geisteswissenschaften, also Literatur, Geschichte, Philosophie und Theologie zu Hause fühlen.

Tutorial zum Schreiben eines Wikipedia Artikels

Die offizielle Hilfe in der Wikipedia ist hoffnungslos veraltet. Sie orientiert sich an der Bedienung der Mediawiki-Installation, was die meisten Benutzer ohnehin kennen dürften. Viel spannender sind jedoch jene Aspekte, die etwas mit dem wissenschaftlichen Arbeiten zu tun haben und die in einen qualitativ hochwertigen Lexikonartikel münden. Dazu ein kleines Tutorial.

Der erste Schritt besteht darin, sofern noch nicht geschehen, Jabref zu installieren und zu starten. Was hat das mit Wikipedia zu tun? Die Antwort lautet, dass man ungefähr 99% der Arbeitszeit auf dem lokalen Desktop verbringt, wo man mit Jabref und weiteren Tools, die noch vorgestellt werden, arbeitet und nur zu 1% der Zeit dann dafür aufwendet die erstellte Textdatei in das Wikisystem hochzuladen. Es geht zwar um das Editieren in der bekannten Online-Enzyklopädie, doch das kommt erst ganz zum Schluss.

wiki1

Nachdem Jabref installiert und arbeitsbereit ist kann man sich die ersten Quellen bei Google Scholar raussuchen. In der deutschen Wikipedia sind das natürlich primär Dokumente die auf Deutsch erstellt wurden, aber in vielen Bereichen der Robotik muss man notfalls auch auf englische Paper zurückgreifen. Das Hinzufügen eines Bibtex Eintrages geht über die Zwischenablage, und manuell ergänzen sollte man dann noch das Feld für die URL, sodass in der Wikipedia Ansicht später einmal das PDF direkt über einen Mausklick erreichbar ist. Nützlich ist noch das Feld „keywords“ in Jabref, was sich im Reiter Allgemein befindet. Dort gibt man das Thema an, an dem man gerade arbeitet. Darüber kann man die Dokumente später dann leichter wiederfinden. Im Screenshot wurden auf diese Weise drei Quellen zu Jabref hinzugefügt.

wiki2

Wie man anhand der Einträge schon sieht, geht es um eine Firma die Roboterhände herstellt. Diesen Artikel gibt es zwar schon bei Wikipedia, er soll aber erweitert werden. Aber das nur als Anmerkung, weiter geht es mit dem Artikel als solchen. Nachdem die Jabref Datenbank mit den ersten Quellen befüllt wurde, kann man sich dem eigentlichen Schreiben zuwenden. Bevor man jedoch einen lesbaren Text erstellt, heißt es zunächst einmal Stichworte anfertigen. Diese Technik wird als Exzerpieren bezeichnet. Dazu öffnet man einen Texteditor und schreibt interessante Fakten, die man in den Quellen gelesen hat heraus und vermerkt dahinter den Bibtexkey.

wiki3

In Jabref kann man den Bibtex-Key über die rechte Maustaste kopieren und diesen dann in die Textdatei einfügen. Wer mag, kann auch noch die Wiki-Markup verwenden um einen „ref-tag“ zu erzeugen, mit dem man später auf die Quelle verweist. In der obigen Abbildung habe ich herausgefunden, welches Gewicht und welche Abmessungen die Roboterhand besitzt.

Jetzt werden die Stichworte umformuliert zu kompletten Sätzen. Wichtig dabei ist, dass man die Referenzen zu den Quellen am Satzende angibt. Damit ergibt sich die typische Wiki-Syntax wo neben den Informationen auch hochgestellte Ziffern mit weiterführenden Informationen eingeblendet sind.

wiki4

Nun ist der Zeitpunkt gekommen, wo man das erste Mal die Wikipedia Spielwiese bemüht. Um sich anzuschauen wie der Text einmal aussehen wird, und welche Markup-Ergänzungen noch nötig sind. Vorher exportiert man die Jabref Einträge in die Wikisyntax. Wie das geht wurde in einem früheren Blogpost bereits erläutert. Trotzdem hier nochmal die Exportvorlage für Jabref:

<ref name="\bibtexkey">{{Literatur
 | Autor = \author
 | Titel = \title
 | Datum = \year
 | Sammelwerk = \journal \booktitle \organization \publisher \school
 | Band = \volume
 | Nummer = \number
 | Seiten = \pages
 | DOI = \doi
 | Online = \url 
}}</ref>

wiki5

Nachdem die Jabref-Einträge an die Textdatei am Ende angehangen sind, kann man sich das Ergebnis in der Wikipedia Spielwiese anschauen. Man sieht einen relativ kurzen Text zu dem vier Quellen angegeben sind. Diese haben dank der Wikipedia-Literatur-Vorlage auch gleich die URL zum Anklicken. Der Text selber ist noch etwas holprig formatiert und man könnte noch 1-2 Interwiki-Links setzen. Beispielsweise haben die Stichworte NASA und „pneumatischer Muskel“ bereits einen Wikipedia Eintrag zu dem man verlinken kann.

Damit ist das kleine Autoren-Tutorial beendet. Es wurde gezeigt, dass die Erstellung von neuen Wikipedia Artikeln in erster Linie offline erfolgt und inhaltlich aus exzerpieren besteht. Der Aufwand, um den simplen Absatz wie er in der Spielwiese gezeigt wurde zu erstellen, ist relativ hoch. Man sollte dafür mehrere Stunden einplanen. Teilweise noch länger, wenn man sich zunächst inhaltich in das Thema einlesen muss. Wenn man den Edit dann in der echten Wikipedia ausführt ist jedoch die Wahrscheinlichkeit hoch, dass der Edit nicht sofort wieder gelöscht wird, sondern als produktive Ergänzung zum Lexikon wahrgenommen wird.

Wird der Text in den Wikipedia Artikel eingepflegt und klickt man auf „Speichern“ sieht das Ergebnis dann so aus:

wiki6

Fermi Paradoxon gelöst

Das Fermi Paradoxon ist zu stark auf die Naturwissenschaft fokussiert. Es unterstellt, dass es keine Zauberei gibt vor allem keine Zauberei im Weltraum. Aber das ist nicht wahr. Der Weltraum ist voll davon. Es gibt sie auf jedem Planeten. Es sind sehr alte Zauberer, in langen Gewändern und mit verrunzelten Gesichtern. Einige haben auch spitz zulaufende Hütte auf und einen Bart der bis zum Fußboden reicht. Ihre Fähigkeiten sind unterschiedlich stark ausgeprägt aber die meisten können zumindest ihre Gestalt verändern. Einige können auch die Zeit beeinflussen.

Das Fermi Paradoxon hingegen sucht nur nach klassischen Außerirdischen, also hochentwickelten Zivilisationen die sehr rational und objektiv agieren. Soetwas gibt es tatsächlich nicht. In einem Märchenfilm ist die Abwesenheit von Magie der Worst-Case. In einem Märchenfilm besteht der Normalfall darin, dass Tiere sprechen können und dass man nur einen Zauberspruch aufsagen muss und es erfüllen sich alle Wünsche. Nach sowas muss man suchen, wenn man den Weltraum erobern will.

Feministische Technikkritik in der Kontroverse

Für alle die den Diskurs seit den 1960’er verschlafen haben zunächst einmal die Kurzfassung was feministische Technikkritik ist. Am besten vorgetragen wurde sie im Film „Terminator II“ von der Protagonistin Sarah Conner welche dem Erfinder von Skynet vorgeworfen hat für die Auslöschung der Menschheit verantwortlich zu sein. Ihre Kritik richtete sich einmal gegen die Erfindung als solche aber auch gegen die Tatsache dass der Erfinder ein Mann war. Feministische Technikkritik hat eine pessimistische Zukunftserwartung. Es wird gesagt, dass Fortschritt erstens von Männern erdacht wird und zweitens für die Gesellschaft ingesamt schädlich ist. Technik wird beschrieben als ein Kommunikationsmittel was Männer untereinander pflegen und das abgeleitet ist aus Ritualen der Jagd. Aus dieser Analyse heraus wird gefordert, Fortschritt zu bremsen um damit die Gesellschaft vor den Männern und ihren Ideen zu schützen.

Ist dieser Diskurs zeitgemäß und friedlich? Zunächst einmal wird eine sehr pessimistische Weltsicht vertreten. Das heißt, es wird grundsätzlich angenommen, dass jeder Fortschritt etwas schlechtes ist. Folglich wird das Automobil dazu eingesetzt um Menschen zu überfahren, der elektrische Strom wird genutzt um die Menschen auch nachts arbeiten zu lassen und die Atomkraft wird zum Bau von Neutronenbomben genutzt. Aber ist diese Ansicht richtig? Hat Technik insgesamt dem Menschen mehr geschadet als genutzt? Vergleicht man einmal ganz objektiv gesellschaftliche Faktoren wie Bildungsgrad, Sterblichkeit oder individuelle Freiheit dann hat sich die Lage der Menschen seit dem Mittelalter dramatisch verbessert. Das heißt, das Leben ist heute besser als früher weil es heute mehr Technik gibt. Die pessimistische Haltung der Technik gegenüber eine Außenseitermeinung.

Das zweite Argument lautet, dass Technik männnlich dominiert sei. Als Beleg wird gesagt, dass alle großen Erfinder und Wissenschaftler Männer waren: Einstein hat die Atombombe erdacht, Turing den Computer erfunden, Tim Berners Lee das WWW programmiert und Michail Kalaschnikow die AK47. Aber ist das wirklich eine Ist-Beschreibung als vielmehr eine subjektive Wahrnehmung der Realität? Richtig ist, wenn man ganz genau nachforscht wird man in der Geschichte auch viele Erfinderinnen und Wissenschaftlerinnen entdecken: Marie Curie, Ada Lovelace, Cynthia Breazeal oder Grace Hopper. Zu unterstellen, dass Frauen grundsätzlich in der steinzeitlichen Höhle bleiben während die Männer auf die Jagd gehen und sich dort neue Werkzeuge ausdenken ist keine Ist-Beschreibung sondern es ist eine frauenfeindliche Forderung.

Frauen, die sich in technischen Berufen engagieren, erhalten den meisten Gegenwind nicht etwa von Männern, die Konkurrenz fürchten sondern der Gegenwind kommt von ihren Müttern und Freundinnnen. Wenn man als Frau an einem Programmierkurs an einer Uni teilnimmt wird man dort wie eine Göttin behandelt. Man braucht nur mit dem Finger zu schnippen und einer von diesen treuen männlichen Hunden kommt angelaufen und macht Kunststücke. Aber wehe man erzählt seiner Mutter was man vorhat, dann ist der Konflikt vorprogrammiert. Anders ausgedrückt, feministische Technikkritik ist ein Herschaftsinstrument, damit Frauen andere Frauen als Hexen verunglimpfen können.

Schauen wir uns dochmal an, wie die Unterrichtssituation von Frauen und Mädchen in Technik-Fächern ist. Es gibt hier zwei Modelle. Einmal der koedukative Unterricht bei dem Frauen zusammen mit Männern unterrichtet werden und zweitens gibt es eine strikte Trennung zwischen Männern und Frauen, das heißt es werden Programmierkurse nur für Frauen angeboten. Warum bevorzugen Frauen letzteres? Nicht etwa, weil sie im koedukativen Unterricht in Konkurrenz zu Männern stehen und von ihnen belästigt werden, sondern weil sie in reinen Frauen-Programmierkursen andere Frauen als Peergroup um sich versammeln können und damit einen Gegenpool bilden zur feminstischen Technikkritik. Sie haben damit die Möglichkeit sich von ihren technikfeindlichen Müttern zu distanzieren und eigene Wege zu gehen. Frauen brauchen andere Frauen um von ihnen Bestätigung zu erhalten, dass ihre Weltsicht korrekt ist. Dass es anständig ist, sich mit Linux zu beschäftigen oder an einem Moped herumzuschrauben.

Medizinische Nanoroboter bringen nichts

Von medizinischen Nanorobotern erwartet sich die Wissenschaft wahre Wunder: Krebs will man damit heilen, Kurzsichtigkeit auch und auch minimalinvasive Operationen sollen endlich möglich werden. Zugegeben, die Vorstellung ist verlockend dass winzig kleine programmierte Roboter in den Körper eindringen und dort Schlachten führen gegen Bakterien und Plaque. Leider sind nüchtern betrachtet die Vorteile nur gering. Selbst mit perfekt programmierten kann man die Lebenserwartung nur geringfügig steigern. 1 Jahr vielleicht, mehr nicht. Anstatt mit 75 stirbt man dann mit 76 Jahren. Der Aufwand um solche Nanoroboter zu bauen und zu programmieren ist jedoch immens. Derzeit ist nicht klar wie es gemacht wird, um hier Erfolge zu erzielen müsste man wenigstens ein 5 Jahres Projekt durchführen. Selbst im besten Fall hat man also 5 Jahre seines eigenen Lebens investiert um dadurch 1 Jahr länger zu leben. In der Summe hat man also an Lebenszeit verloren. Es lohnt sich nicht sich näher mit Nanorobotern zu befassen.

Und diese Prognose ist noch optimitisch. Gut möglich, dass man 5 Jahre vor sich hin forscht und am Ende nur ein sogenanntes Negativ-Scientific Data hervorbringt was man bei ResearchGate oder sonstwo veröffentlicht. Und negative heißt wirkllich negativ, das man also kleinlaut zugibt keine Ahnung zu haben wie es geht und auch keine Möglichkeit sieht in absehbarerer Zukunft die Technologie weiterzuentwickeln. Das heißt dann konkret dass man 5 Jahre investiert hat und am Ende trotzdem noch mit 75 an einer Herzattacke zu sterben. Vermutlich sogar früher weil Wissenschaftler als workaholics einen ungesunden Lebensstil pflegen und für schöne Dinge im Leben nur wenig Zeit haben.

Was also soll das Gerede von der wunderbaren Nanozukunft bei dem alle Krankheiten geheilt sind? Es ist ein leeres Versprechen, was Nachwuchsswissenschaftler rekrutieren soll wohl wissend dass sie bei dem kollektiven Kraftaufwand am Ende als Verlierer daraus hervorgehen werden. Anstatt mit Nanorobotern sollte man seine Zeit sinnvoller verbringen, mit guten Freunden beispielsweise oder mit entspannter Lektüre hier im Weblog.

Update: Robot-Control-System

1

Langsam aber stetig nimmt das Robot-Control-System Gestalt an. Gegenüber der letzten Version hat sich verbessert, dass jetzt Python Threads und nicht mehr ein selbst programmierter Interpreter verwendet werden um die Makros abzuarbeiten. Wenn man das Programm startet kann über die Taste „5“ der Auto-Mode aktiviert werden. Dieser stapelt die Objekte um. Eine Methode um auch seitlich ein Objekt zu greifen ist bereits implementiert, funktioniert aber noch nicht perfekt. Eine Funktion um cluttered grasping zu betreiben fehlt vollständig. Dennoch kann man mit dem System bereits einiges anfangen. Wer ein wenig herumspielen möchte, sollte sich die Klasse „BehaviorTree“ näher anschauen, dort kann man die Abfolge des Systems festlegen.

'''
Robot Control System
Created on 25.01.2017
@author: Manuel Rodrgiuez
'''
import time, sys, pygame, random, math, Box2D, os, numpy, threading
from Box2D.b2 import (world, polygonShape, staticBody, dynamicBody)
from Box2D import (b2CircleShape, b2FixtureDef, b2LoopShape, b2PolygonShape,
                   b2RevoluteJointDef, b2_pi)
from locale import currency
from __builtin__ import True


class Settings(object):
  def __init__(self):
    self.screen = (600, 500)
    self.ppm = 32.0  # pixels per meter
    self.fric = 1.0  # 0.3 friction
    self.torque = 1000
    self.fps = 50  # 60 fps
    self.pause = 100000 / self.fps  # 2000 msec on 50fps
  def box2d_to_pygame_pos(self, box2dpos):
    """ convert coordinates """
    x = int(box2dpos[0] * self.ppm)
    y = int(self.screen[1] - box2dpos[1] * self.ppm)
    return (x, y)
  def calcdistance(self, p1, p2):
    """ Euclidean ordinary distance """
    return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
  def angle_between_two_points(self, p1, p2):
    angle = math.degrees(math.atan2(p1[1] - p2[1], p1[0] - p2[0]))
    angle += 90
    if angle < 0: angle += 360
    return angle
  def polarpoint(self, p1, angle, radius):
    """ polar coordinates for a point on circle """
    angle = (angle - 90) * math.pi / 180
    x = int(p1[0] + radius * math.cos(angle))
    y = int(p1[1] + radius * math.sin(angle))  
    return (x, y)

class Physics(Settings):
  def __init__(self):
    super(Physics, self).__init__()
    self.myworld = world(gravity=(0, -10), doSleep=True)  # 0,-10
    self.groundbody = []
    self.body = []
    self.groundbody.append(self.myworld.CreateStaticBody(position=(15, 0),
        shapes=polygonShape(box=(20, 0.01)), angle=-0))  # ground
    self.groundbody.append(self.myworld.CreateStaticBody(position=(0, 10),
        shapes=polygonShape(box=(0.001, 10)),))  # left
    # self.groundbody.append(self.myworld.CreateStaticBody(position=(18, 10),
    #    shapes=polygonShape(box=(0.001, 10)),))  # right
    self.groundbody.append(self.myworld.CreateStaticBody(position=(15, 1),
        shapes=polygonShape(box=(0.01, 10)),))  # right2
    self.groundbody.append(self.myworld.CreateStaticBody(position=(15, 15),
        shapes=polygonShape(box=(20, 0.001)),))  # top
  def getpos(self, id):
    box2dpos = self.body[id].position
    return self.box2d_to_pygame_pos(box2dpos)
  def getangle(self, id):
    angle = self.body[id].angle
    angle = (math.degrees(-angle) + 90) % 360
    return angle       
  def updatePhysics(self):
    self.adjustgripper()
    timestep = 1.0 * 3.0 / 60  
    self.myworld.Step(timestep, 10000, 10)

class Gripper(Physics):
  def __init__(self):
    super(Gripper, self).__init__()
    self.goalgripper = (100, 100)
    self.gripperangle = 180
    # griper
    self.body.append(self.myworld.CreateDynamicBody(position=(5, 15), angle=0))
    self.body[-1].CreatePolygonFixture(box=(0.5, 0.5), density=1, friction=self.fric)
    self.body.append(self.myworld.CreateDynamicBody(position=(5, 8), angle=0))
    self.body[-1].CreatePolygonFixture(box=(0.5, 0.5), density=1, friction=self.fric)
    self.body.append(self.myworld.CreateDynamicBody(position=(7, 6), angle=0))
    self.body[-1].CreatePolygonFixture(box=(1, 0.2), density=1, friction=self.fric)
    self.body.append(self.myworld.CreateDynamicBody(position=(8, 4), angle=0))
    self.body[-1].CreatePolygonFixture(box=(1, 0.2), density=1, friction=self.fric)
    # box
    self.body.append(self.myworld.CreateDynamicBody(position=(12, 3), angle=0))
    self.body[-1].CreatePolygonFixture(box=(1, 1), density=1, friction=self.fric)
    self.body.append(self.myworld.CreateDynamicBody(position=(4, 3), angle=0))
    self.body[-1].CreatePolygonFixture(box=(1, 1), density=1, friction=self.fric)
    for i in range(1):
      self.body.append(self.myworld.CreateDynamicBody(position=(random.randint(3, 12), 3), angle=0))
      self.body[-1].CreatePolygonFixture(box=(0.2, 0.2), density=1, friction=self.fric)

    self.joint = []
    self.joint.append(self.myworld.CreatePrismaticJoint(# x
        bodyA=self.body[0],
        bodyB=self.groundbody[3],
        anchor=(0, 0),
        axis=(1, 0),
        lowerTranslation=-15.0,
        upperTranslation=20,
        enableLimit=False,
        maxMotorForce=self.torque,
        motorSpeed=0.0,
        enableMotor=True,
    ))    
    self.joint.append(self.myworld.CreatePrismaticJoint(# up/down
        bodyA=self.body[1],
        bodyB=self.body[0],
        anchor=(0, 0),
        axis=(0, 1),
        lowerTranslation=-15.0,
        upperTranslation=15,
        enableLimit=True,
        maxMotorForce=self.torque,
        motorSpeed=0.0,
        enableMotor=True,
    ))   
    self.joint.append(self.myworld.CreateRevoluteJoint(# rotate
        bodyA=self.body[1],
        bodyB=self.body[2],
        localAnchorA=(0, 0),
        localAnchorB=(1, 0),
        enableMotor=True,
        enableLimit=False,
        lowerAngle=math.radians(60),
        upperAngle=math.radians(120),
        maxMotorTorque=50 * self.torque,
        motorSpeed=0,
    ))
    self.joint.append(self.myworld.CreatePrismaticJoint(# gripper
        bodyA=self.body[3],
        bodyB=self.body[2],
        localAnchorA=(0, 0),
        localAnchorB=(0, 0),
        axis=(0, 1),
        lowerTranslation=1,
        upperTranslation=3,
        enableLimit=True,
        maxMotorForce=self.torque,
        motorSpeed=0.0,
        enableMotor=True,
    )) 
  def setspeed(self, id, speed):
    # id=0: left, right
    # id=1, up, down
    # id=3, open,close
    self.joint[id].motorSpeed = speed
  def adjustgripper(self):
    # position
    pos = self.goalgripper
    p1 = self.getpos(1)
    dx = pos[0] - p1[0]
    dy = pos[1] - p1[1]
    if math.fabs(dx) > 10: dx = 5.0 * -dx / math.fabs(dx)  # normal speed
    else: dx = 1.0 * -dx / 50  # slow speed
    if math.fabs(dy) > 10: dy = 5.0 * dy / math.fabs(dy)  # normal speed
    else: dy = 1.0 * dy / 50  # slow speed
    self.setspeed(0, dx)
    self.setspeed(1, dy)
    
    # angle
    a1 = (self.getangle(2) + 180) % 360
    a2 = self.gripperangle
    diff = a2 - a1
    if math.fabs(diff) > 5: da = 0.5 * -diff / math.fabs(diff)
    else: da = 1.0 * -diff / 50  # slow speed
    self.setspeed(2, da)

class Sceneunderstanding(Gripper):
  def __init__(self):
    super(Sceneunderstanding, self).__init__()
    self.grasp = []  # x, y, angle
  def angleobject(self, objectid):
    topangle = []
    for i in range(4):
      temp = (self.getangle(objectid) + i * 90) % 360  # angle for all directions
      # only top angles
      if temp < 90: diff = temp
      elif temp > 270: diff = temp - 360
      else: diff = 360
      topangle.append(diff)
    temp = sorted(topangle, key=abs)
    return temp[0]
  def getgraspoint(self,objectid):
    p = (self.getpos(objectid)[0] - 47, self.getpos(objectid)[1])
    angle = self.angleobject(objectid)
    pregrasp1 = self.polarpoint(p, angle, 150)
    pregrasp2 = self.polarpoint(p, angle, 50)
    pregrasp3 = self.polarpoint(p, angle, 100)
    return (pregrasp1, pregrasp2, pregrasp3, angle)
  def updateScene(self):
    color = (200, 0, 0)
    for i in range(3):
      p = self.getgraspoint(4)
      pygame.draw.circle(self.window, color, p[i], 10, 2)
   
class BehaviorTree(Sceneunderstanding):
  def __init__(self):
    super(BehaviorTree, self).__init__()
  def BTstart(self):
    t = threading.Thread(target=self.taskmain)
    t.daemon = True  # stops, if mainprogram ends
    t.start()
  def BTstop(self):
    print "thread stop"
  def taskpick(self,objectid):
    self.taskrotate(self.getgraspoint(objectid)[3] + 180)
    self.taskmovexy(self.getgraspoint(objectid)[0])
    self.taskopengripper()
    pygame.time.wait(self.pause)
    self.taskmovexy(self.getgraspoint(objectid)[1])
    pygame.time.wait(self.pause)
    self.taskclosegripper()
    pygame.time.wait(self.pause)
    self.taskmovexy(self.getgraspoint(objectid)[0])
    pygame.time.wait(self.pause)
  def taskplace(self,goal,objectid):
    self.taskmovexy((200,200)) # rest position
    pygame.time.wait(self.pause)
    self.taskmovexy(goal) # goal
    pygame.time.wait(self.pause)
    self.taskopengripper()
    pygame.time.wait(self.pause)
    self.taskmovexy(self.getgraspoint(objectid)[1])
    pygame.time.wait(self.pause)
    self.taskmovexy(self.getgraspoint(objectid)[0])
    pygame.time.wait(self.pause)
    self.taskmovexy((200,200)) # rest position
    pygame.time.wait(self.pause)
    
  def taskmain(self):
    self.input = "auto"
    print "start"
    a=(60,400)
    b=(230,400)
    c=(360,400)
    self.taskpick(4)
    self.taskplace(b,4)
    self.taskpick(5)
    self.taskplace(c,5)
    self.taskpick(4)
    self.taskplace(a,4)
    self.taskpick(5)
    self.taskplace(b,5)
    self.taskpick(4)
    self.taskplace(c,4)
    self.taskpick(5)
    self.taskplace(a,5)
    self.taskpick(4)
    self.taskplace(b,4)
    self.taskpick(5)
    self.taskplace(c,5)

    print "end"
    self.input = "manuel"

 

class Motionprimitive(BehaviorTree):
  def taskmovexy(self, p): 
    self.goalgripper = p
  def taskopengripper(self):  
    self.setspeed(3, 5)
  def taskclosegripper(self):
    self.setspeed(3, -5)    
  def taskrotate(self, angle): 
    self.gripperangle = angle

class GUI(Motionprimitive):
  def __init__(self):
    super(GUI, self).__init__()
    pygame.init()
    self.window = pygame.display.set_mode(self.screen)
    self.clock = pygame.time.Clock()
    self.mouse = (0, 0)
    self.input = "manuel"
  def paintobjects(self):
    # Text1
    myfont = pygame.font.SysFont("freesans", 18)
    text = "control: " + str(self.input)
    label = myfont.render(text, 1, (0, 0, 0))
    self.window.blit(label, (40, 20))
    text = "mouse: " + str(self.mouse)
    label = myfont.render(text, 1, (0, 0, 0))
    self.window.blit(label, (40, 40))
    # box2d
    colors = { staticBody: (100, 100, 100),
        dynamicBody: (0, 0, 140),
    }
    for body in (self.myworld.bodies):  
      for fixture in body.fixtures:
        shape = fixture.shape
        if hasattr(shape, 'vertices'):  # rectangle
          vertices = [(body.transform * v) * self.ppm for v in shape.vertices]
          vertices = [((v[0]), (self.screen[1] - v[1])) for v in vertices]
          pygame.draw.polygon(self.window, colors[body.type], vertices, 0)
        else:  # ball
          position = body.transform * shape.pos * self.ppm
          x, y = int(position[0]), int(self.screen[1] - position[1])
          radius = int(shape.radius * self.ppm)
          pygame.draw.circle(self.window, colors[body.type], (x, y), radius, 2)
          x2, y2 = x + radius * math.sin(body.angle), y + radius * math.cos(body.angle)
          pygame.draw.line(self.window, colors[body.type], (x, y), (x2, y2), 2)  # top
  def inputhandling(self):
    for event in pygame.event.get(): 
      if event.type == pygame.QUIT: 
        sys.exit(0) 
      if event.type == pygame.MOUSEMOTION:
        self.mouse = event.pos
        if self.input == "manuel":
          self.goalgripper = self.mouse
      if event.type == pygame.MOUSEBUTTONUP:
        pass
      if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_1: self.setspeed(3, 2)
        if event.key == pygame.K_2: self.setspeed(3, -2)
        if event.key == pygame.K_3: self.gripperangle -= 45    
        if event.key == pygame.K_4: self.gripperangle += 45     
        if event.key == pygame.K_5: self.BTstart()
        if event.key == pygame.K_6: self.BTstop()
        if event.key == pygame.K_0:
          self.setspeed(0, 0)
          self.setspeed(1, 0)
          self.setspeed(2, 0)
          self.setspeed(3, 0)                          
  def updateGUI(self):
    self.clock.tick(self.fps)  
    self.window.fill((220, 220, 220))
    self.inputhandling()
    self.paintobjects()

class Game: 
  def __init__(self):
    random.seed()
    self.myGUI = GUI()
    for step in range(10000000):
      self.myGUI.updateGUI()
      self.myGUI.updatePhysics()
      self.myGUI.updateScene()
      pygame.display.flip()  # display update

myGame = Game()

Wie realistisch sind Nanoroboter?

Bei Star Trek Voyager waren sie bereits Realität — die Rede ist von Nanorobotern. Üblichweise sagen Wissenschaftler voraus, dass es derzeit unmöglich sei und man in vielleicht 20 Jahren mit dessen Realisierung rechnen könne. Schauen wir uns dazu einige Details an:

Von der mechanischen Seite sind Nanoroboter relativ leicht zu verwirklichen. Es gibt bereits erste Prototypen, die in MEMS Bauweise entstanden sind. Dazu wird die Silizium Fertigung die normalerweise in der CPU Produktion genutzt wird, angewendet um kleine Zahnräder und Motoren in eine Oberfläche zu drucken. Die Herausforderung besteht in der Steuerung dieser Kleinstroboter. Man benötigt dafür zwingend eine CPU und eine Software die auf der CPU läuft. Als CPU kommen keine Desktop-Prozessoren wie der Intel Core i5 in Frage, weil deren Abmessungen zu groß sind. Was man jedoch nutzen kann, sind reduzierte Computer mit nur wenigen Tausend Transistoren. Also CPUs, die extrem langsam sind und extrem wenig RAM besitzen. Sowas lässt sich sehr viel kleiner und sehr viel stromsparender fertigen. Jetzt bleibt noch das letzte große Problem zu lösen: wie programmiert man solche CPU?

Aus Sicht der Softwareentwickler hat man eine Kleinst-CPU die 1000x langsamer ist als Commodore 64 mit der ein Realtime-Roboter gesteuert werden muss. Folglich können nur Methoden angewendet werden, die nichts mit Brute-Force zu tun haben. Statische BehaviorTrees sind eine gute Wahl. Man kann solche BehaviorTrees relativ komplex gestalten um beispielsweise Pick&Place Aufgaben wahrzunehmen. Ihr CPU-Footprint und ihr Speicherverbrauch ist fast Null, das heißt sie würden schnell genug auf einem Nanoroboter laufen.

Es ist möglich — wenn auch bisher noch nicht praktisch demonstriert — dass man einen Nanoroboter entwickelt, nicht erst in 20 Jahren sondern heute. Notwendig dazu ist lediglich State-of-the-art MEMS Fertigung in Verbindung mit State-of-the-art Realtime-Software.

Was man mit derartigen Naniten anfangen könnte ist simpel: Schwarze Magie. Also das was Harry Potter, Merlin der Zauberer, der Zauberer von Oz und all die anderen aus der Sagen und Märchenwelt seit Jahrhunderten tun und wovon es immer hieß, es wäre nicht möglich. Naniten sind soetwas ähnliches wie ein Zauberstab mit dem man alles in Gold verwandeln kann, was man berührt, womit man Blinde sehend machen kann und womit sich Planeten über Terraforming in ein blühendes Paradies verwandeln lassen.