Wie weiter im Blog?

1

Als Screenshot habe ich mal die aktuelle Abrufstatistik der letzten Zeit eingefügt. Wie man sieht sind die Zahlen niedrig. Pro Tag rund 25 Aufrufe mit einem kleinen Außreißer. Warum der da ist? Keine Ahnung. Nur mal zur Einordnung, solange die tägliche Abrufzahl kleiner 100 ist spricht von man einem sogenannten C-Blog, also eine reichweite die extrem niedrig ist, was niemand kennt und wo es nur selten zu Kommentaren kommt. Das hier ist ein typisches C-Blog.

Anders als früher ist mir das inzwischen jedoch egal. Denn erstens kann man da ohnehin nichts gegen unternehmen, weil das Google Ranking sich nicht beeinflussen lässt und zum Zweiten weil ich bei Wikipedia die Möglichkeit haben, extrem hohen Traffic zu erzeugen, vorausgesetzt mein Posting dort wird nicht von der Eingangskontrolle einkassiert. Beispielsweise darf ich mich jetzt stolz als Co-Autor für den Wikipedia Eintrag Roboter nennen. Mein Absatz dort hat im Schnitt 400 Abrufe am Tag. Und zwar jeden Tag. Gleichzeitig hat Wikipedia bei google das maximal mögliche Ranking und so ist es ein kleiner Trost, dass ich über diesen Umweg doch noch ein wenig Traffic generiere.

Ebenfalls relativ hoch ist der Traffic wie auch die Kommentarhäufigkeit im Usenet und bei Stackoverflow, so dass ich langsam den Verdacht habe, dass Blogs generell weniger Traffic haben als Foren und große Portale. Auf der anderen Seite ist mir das blog hier dennoch ans Herz gewachsen. Weil es hier keine Moderatoren gibt, sondern wirklich nur das erscheint, was ich einstelle.

Update:
Absoluter Lieblingsartikel der Leser dieses Blogs ist derzeit https://trollheaven.wordpress.com/2016/07/24/das-7d-hologramm/ Offenbar besteht hier ein großes Informationsbedürfnis. Es könnte auch damit zusammenhängen dass Google unter diesem Stichwort und bei der Sprachwahl Deutsch, den Text derzeit auf Platz 1 der Rangliste einordnet. Warum? Keine Ahnung. Andere Blog-Einträge hingegen erhalten nur wenig Aufmerksamkeit von Außen.

Advertisements

Update: Robot-Control-System

Das Robot-Control-System hat kleinere Verbesserungen erhalten. Zum einen gibt es jetzt einen zweiten Gripper und zum zweiten wurden mehr Motion Primitive verbaut. Wenn man das Programm startet drückt man auf die Taste 5 und sieht dann eine längere Animation ablaufen, einen sogenannten Physics Animation Controller. Dieser besteht aus mehreren Finite-States-Maschines, die als Behavior Tree ineinander verschachtelt sind und erstaunlich komplexe Aktionen ausführen. Für den Benutzer passiert wenig: es ist nur ein Pick&Place Task zu sehen, der zudem noch mehrere Pausen enthält.

Das zentrale Element ist die Behavior Engine, welche sich wie folgt gliedert:

main
  task1
     selectgrasp
     place
     move(0)
     selectgrasp
     place
     move(1)
     selectgrasp
     place

Die Motion Primitive „selectgrasp“, „place“ und „move“ sind noch weiter untergliedert bis am Ende dann Steueranweisungen für die Box2D Physik-Engine ausgeführt werden. Die Leistungsfähigkeit des Roboters bemisst sich nach den Lines of Code für die Behavior Engine, je umfangreicher sie ist, desto mehr kann der Roboter machen. Das Prinzip ist in der Robotik nichts neues: Marc Raibert hat damit experimentiert, die NaturalMotion Engine funktioniert so, Simbicon basiert darauf und bei der Darpa Robotics Challange 2015 wurden die Controller ebenfalls nach diesem Prinzip realisiert. Neu ist jedoch, dass diesmal Python als Programmiersprache verwendet wurde. Damit ist die Verständlichkeit hoffentlich höher, als bei ROS und vergleichbaren Projekten.

'''
Created on 16.02.2017
gantry robot
@author: Manuel Rodriguez
'''
import time, sys, pygame, random, math, Box2D, os, numpy, threading
import logging
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
logging.basicConfig(
  stream=sys.stdout,
  level=logging.DEBUG,
  format='%(message)s'
)
log = logging.getLogger(__name__)

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 = 55  # 60 fps
    self.pause = 100000 / self.fps
    self.black = (0, 0, 0)
    self.grey = (150, 150, 150)
    self.red = (230, 0, 0)
    self.blue = (0, 0, 230)
  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(p2[1] - p1[1], p2[0] - p1[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 = p1[0] + radius * math.cos(angle)
    y = p1[1] + radius * math.sin(angle) 
    x,y=self.floattoint((x,y))
    return (x, y)
  def floattoint(self, p):
    return (int(p[0]), int(p[1]))
  def incircle(self,p1,radius,p2):
    """ checks if p2 is in circle """
    square_dist = (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2
    return square_dist <= radius ** 2
  def getpixel(self, p):
    surf3d = pygame.surfarray.pixels3d(self.window)
    temp=surf3d[p[0]][p[1]]
    del surf3d # prevent blocking
    return temp

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, 1),
        shapes=polygonShape(box=(20, 0.05)), angle=-0))  # ground
    self.groundbody.append(self.myworld.CreateStaticBody(position=(0.5, 10),
        shapes=polygonShape(box=(0.05, 10)),))  # left
    self.groundbody.append(self.myworld.CreateStaticBody(position=(18, 7),
        shapes=polygonShape(box=(0.05, 10)),))  # right
    self.groundbody.append(self.myworld.CreateStaticBody(position=(15, 13),
        shapes=polygonShape(box=(20, 0.05)),))  # 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 setspeed(self, id, speed):
    self.joint[id].motorSpeed = speed 
  def movelinear(self, id, p):
    self.body[id].linearVelocity = p
  def moveang(self, id, angle):
    self.body[id].angularVelocity = angle
  def updatePhysics(self):
    timestep = 1.0 * 3 / self.fps
    self.adjustgripper()
    self.myworld.Step(timestep, 1000, 10)

class Gripper(Physics):
  def __init__(self):
    super(Gripper, self).__init__()
    self.gripper1 = (0, 0)
    self.gripper2 = (550, 100)
    self.gripperangle1=180
    self.joint = []
    startid = len(self.body)
    log.info('add id single1 ' + str(startid))
    self.body.append(self.myworld.CreateDynamicBody(position=(10, 15), angle=0))
    self.body[-1].CreatePolygonFixture(box=(1, 0.5), density=1, friction=self.fric)
    self.body.append(self.myworld.CreateDynamicBody(position=(10, 10), angle=0))
    self.body[-1].CreatePolygonFixture(box=(0.5, 0.5), density=1, friction=self.fric)
    self.body.append(self.myworld.CreateDynamicBody(position=(9, 5), angle=0))
    self.body[-1].CreatePolygonFixture(box=(0.3, 1), density=1, friction=self.fric)
    self.body.append(self.myworld.CreateDynamicBody(position=(10, 5), angle=0))
    self.body[-1].CreatePolygonFixture(box=(0.3, 1), density=1, friction=self.fric)
    
    self.body.append(self.myworld.CreateDynamicBody(position=(9, 4), angle=0))
    self.body[-1].CreatePolygonFixture(box=(1, 1), density=1, friction=self.fric)

    self.joint.append(self.myworld.CreatePrismaticJoint(# x
        bodyA=self.body[startid],
        bodyB=self.groundbody[3],
        anchor=(0, 0),
        axis=(1, 0),
        lowerTranslation=-6.0,
        upperTranslation=6,
        enableLimit=False,
        maxMotorForce=self.torque,
        motorSpeed=0.0,
        enableMotor=True,
    ))     
    self.joint.append(self.myworld.CreatePrismaticJoint(# up/down
        bodyA=self.body[startid+1],
        bodyB=self.body[startid],
        anchor=(0, 0),
        axis=(0, 1),
        lowerTranslation=-15.0,
        upperTranslation=15,
        enableLimit=False,
        maxMotorForce=self.torque,
        motorSpeed=0.0,
        enableMotor=True,
    ))   
    self.joint.append(self.myworld.CreateRevoluteJoint(# rotate
        bodyA=self.body[startid+1],
        bodyB=self.body[startid+2],
        localAnchorA=(0, 0),
        localAnchorB=(0, 1),
        enableMotor=True,
        enableLimit=False,
        lowerAngle=math.radians(60),
        upperAngle=math.radians(120),
        maxMotorTorque=self.torque,
        motorSpeed=0,
    ))
    
    self.joint.append(self.myworld.CreatePrismaticJoint(# gripper openclose
        bodyA=self.body[startid+2],
        bodyB=self.body[startid + 3],
        localAnchorA=(0, 0),
        localAnchorB=(0, 0),
        axis=(1, 0),
        lowerTranslation=1,
        upperTranslation=3.4,
        enableLimit=True,
        maxMotorForce=self.torque,
        motorSpeed=1.0,
        enableMotor=True,
    ))    

    startid = len(self.body)
    log.info('add id single2 ' + str(startid))
    self.body.append(self.myworld.CreateDynamicBody(position=(10, 13.5), angle=0))
    self.body[-1].CreatePolygonFixture(box=(1, 0.5), density=1, friction=self.fric)
    self.body.append(self.myworld.CreateDynamicBody(position=(10, 10), angle=0))
    self.body[-1].CreatePolygonFixture(box=(0.4, 0.4), density=1, friction=self.fric)
    self.joint.append(self.myworld.CreatePrismaticJoint(# x
        bodyA=self.body[startid],
        bodyB=self.groundbody[3],
        anchor=(0, 0),
        axis=(1, 0),
        lowerTranslation=-6.0,
        upperTranslation=6,
        enableLimit=False,
        maxMotorForce=self.torque,
        motorSpeed=0.0,
        enableMotor=True,
    ))     
    self.joint.append(self.myworld.CreatePrismaticJoint(# up/down
        bodyA=self.body[startid+1],
        bodyB=self.body[startid],
        anchor=(0, 0),
        axis=(0, 1),
        lowerTranslation=-15.0,
        upperTranslation=15,
        enableLimit=False,
        maxMotorForce=self.torque,
        motorSpeed=0.0,
        enableMotor=True,
    ))   
    
  def adjustgripper(self):
    # position
    pos = self.gripper1
    p1 = self.getpos(1)
    dx = pos[0] - p1[0]
    dy = pos[1] - p1[1]
    dx = 2.0 * -dx /100  
    dy = 2.0 * dy / 100  
    self.setspeed(0, dx)
    self.setspeed(1, dy)
    # angle
    a1 = (self.getangle(2) + 90) % 360
    a2 = self.gripperangle1
    diff = a2 - a1
    da=-1.0*diff/100
    self.setspeed(2, da)

    # position gripper2
    pos = self.gripper2
    p1 = self.getpos(6)
    dx = pos[0] - p1[0]
    dy = pos[1] - p1[1]
    dx = 2.0 * -dx /100  
    dy = 2.0 * dy / 100  
    self.setspeed(4, dx)
    self.setspeed(5, dy)

class BehaviorTree(Gripper):
  def __init__(self):
    super(BehaviorTree, self).__init__()
    self.stopflag = False
  def BTstart(self):
    self.stopflag = False
    self.mythread = threading.Thread(target=self.taskmain)
    self.mythread.daemon = True  # stops, if mainprogram ends
    self.mythread.start()
  def BTstop(self):
    log.info('stop request')
    self.stopflag = True
  def taskmain(self):
    self.input = "auto"
    log.info('start thread')
    self.task1()
    self.input = "manuel 1" 
    log.info('end thread')
  def task1(self):
    self.taskselectgrasp()
    self.taskplace()
    self.taskmove(0)
    self.taskselectgrasp()
    self.taskplace()
    self.taskmove(1)
    self.taskselectgrasp()
    self.taskplace()
  def taskselectgrasp(self):
    type = self.grasptype()
    if type=="grasp": 
      self.taskgrasp()
      self.taskpostgrasp()
    if type=="tiltleft" or type=="tiltright":
      self.tasktilt(type)
      self.taskgrasp()
      self.taskpostgrasp()
  def taskpostgrasp(self):
    log.info('postgrasp')  
    # single rest
    p = self.getpos(6)
    self.taskmovexy(1, (p[0], 0))
    self.taskpause()
    self.taskmovexy(1, (550, 100))
    self.taskpause()
    # move up
    p = self.getpoint("grasp")
    self.taskmovexy(0, p[0])
    self.taskpause()
    self.taskrotate(180)
    self.taskpause()
  def taskplace(self):
    log.info('place ')
    p1=(250,200) # middle screen
    self.taskmovexy(0, p1)
    self.taskpause()
    self.taskopengripper()
    self.taskpause()
    p2=(0,0) # rest position
    self.taskmovexy(0, p2)
    self.taskpause()
  def taskmove(self,id):
    if id==0: 
      p1=(150,300)
      p2=(150,430)
      p3=(600,430)
      p4=(400,430)
    if id==1: 
      p1=(450,300)
      p2=(450,430)
      p3=(0,430)
      p4=(200,430)
    self.taskmovexy(1, p1)
    self.taskpause()
    self.taskmovexy(1, p2)
    self.taskpause()
    self.taskmovexy(1, p3)
    self.taskpause()
    self.taskmovexy(1, p4)
    self.taskpause()
    self.taskmovexy(1, (550, 100)) # rest
    self.taskpause()
  def taskgrasp(self):
    log.info('grasp ')
    self.taskrotate(180+self.angleobject())
    self.taskpause()
    p1,p2 = self.getpoint("grasp")[0],self.getpoint("grasp")[3]
    self.taskmovexy(0, p1)
    self.taskpause()
    self.taskmovexy(0, p2)
    self.taskpause()
    # close
    self.taskclosegripper()
    self.taskpause()
  def tasktilt(self,direction):
    log.info('tilt '+str(direction))
    # above
    p = self.getpoint(direction)
    self.taskmovexy(1, p[0])
    self.taskpause()
    # down
    self.taskmovexy(1, p[1])
    self.taskpause()
    # move
    self.taskmovexy(1, p[2])
    self.taskpause()

class Motionprimitive(BehaviorTree):
  def taskpause(self):
    pygame.time.wait(self.pause)
  def taskmovexy(self, id, p):
    log.info('-- movexy ' + str(id) + " " + str(p)) 
    if id == 0: self.gripper1 = p
    if id == 1: self.gripper2 = p 
  def taskopengripper(self):  
    log.info('-- opengripper')
    self.setspeed(3, 1)
  def taskclosegripper(self):
    log.info('-- closegripper')
    self.setspeed(3, -0.5)    
  def taskrotate(self, angle): 
    log.info('-- rotate '+str(angle))
    self.gripperangle1 = angle
        
class Cube(Motionprimitive):
  def __init__(self):
    super(Cube, self).__init__()
    self.objectid=4
  def angleobject(self):
    topangle = []
    for i in range(4):
      temp = (self.getangle(self.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 getpoint(self, action):
    p1 = self.getpos(self.objectid)
    angle = self.angleobject()
    pygame.draw.circle(self.window, self.red, self.floattoint(p1), 5, 2)
    if action == "grasp": 
      p2 = self.polarpoint(p1, angle - 90, 52)  # point left from center
      p3 = self.polarpoint(p2, angle, 100)
      p4 = self.polarpoint(p1, angle + 90, 52)  # point right from center
      p5 = self.polarpoint(p2, angle, 55) 
      pygame.draw.circle(self.window, self.red, self.floattoint(p2), 10, 2)
      pygame.draw.circle(self.window, self.red, self.floattoint(p3), 10, 2)
      pygame.draw.circle(self.window, self.red, self.floattoint(p4), 5, 2)
      pygame.draw.circle(self.window, self.red, self.floattoint(p5), 10, 2)
      return (p3, p2, p4,p5)
    if action == "tiltleft" or action == "tiltright":
      if action == "tiltleft": direction=-1
      if action == "tiltright": direction=1
      p2 = self.polarpoint(p1, angle + direction*90, 48)  # point left from center
      p7 = self.polarpoint(p1, angle + direction* 90, 10) 
      p8 = self.polarpoint(p7, angle, 45)
      p9 = self.polarpoint(p1, angle, 100)  # above center
      pygame.draw.circle(self.window, self.red, self.floattoint(p2), 10, 2)
      pygame.draw.circle(self.window, self.red, self.floattoint(p7), 5, 2)
      pygame.draw.circle(self.window, self.red, self.floattoint(p8), 10, 2)
      pygame.draw.circle(self.window, self.red, self.floattoint(p9), 5, 2)
      return (p9, p8, p2)
  def grasptype(self):
    log.info('check grasptype')
    arealeftfree, arearightfree, leftedge, rightedge = False, False, False, False
    # check grasp
    p = self.getpoint("grasp")
    colorleft, colorright = self.getpixel(p[1]), self.getpixel(p[2])
    #print p[1], colorleft
    if colorleft[0] == 220: arealeftfree = True
    if colorright[0] == 220: arearightfree = True
    # check border
    p = self.getpos(self.objectid)[0]
    if p < 100: leftedge = True
    if p > 510: rightedge = True
    # decision table
    type = None
    if leftedge == False and rightedge==False and arealeftfree == True and arearightfree == True: type= "grasp"
    elif arealeftfree == True and leftedge == False: type = "tiltleft"
    elif arearightfree == True and rightedge == False: type = "tiltright"
    return type
              
class GUI(Cube):
  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 1"

  def paintobjects(self):
    # Text1
    text = str(self.input)
    text2 = " " + str(self.mouse)
    pygame.display.set_caption(text+text2)
    # box2d
    colors = { staticBody: self.grey,
        dynamicBody: self.blue,
    }
    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 1":
          self.gripper1 = self.mouse
        if self.input == "manuel 2":
          self.gripper2 = self.mouse
        if self.input == "manuel 3":
          self.gripper3 = self.mouse
      if event.type == pygame.MOUSEBUTTONUP:
        pass
      if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_1: self.taskrotate(self.gripperangle1-22.5)
        if event.key == pygame.K_2: self.taskrotate(self.gripperangle1+22.5)
        if event.key == pygame.K_3: self.taskopengripper()
        if event.key == pygame.K_4: self.taskclosegripper()
        if event.key == pygame.K_5: self.BTstart()
        if event.key == pygame.K_6: self.BTstop()
        if event.key == pygame.K_7:
          if self.input == "manuel 1": self.input="manuel 2"
          elif self.input == "manuel 2": self.input="manuel 1"

  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.getpoint("grasp")
      pygame.display.update()  
      
 
if __name__ == "__main__":
  myGame = Game()
  

Sich selbst-reproduzierende Roboter

Konrad Zuse hat im Jahr 1995 am sogenannten Helix-Turm gearbeitet, eine mechanische Konstruktion die sich selbst ausfahren konnte. Ketzerisch formuliert handelt es sich dabei einfach um ein Metall-Maßband was auf Knopfdruck ausfährt. Aber wenn man so sich-selbstreproduzierende Roboter nicht realisieren kann wie dann?

Eine Möglichkeit die besonders in den letzten Jahren modern geworden ist, verwendet einen 3D Drucker um damit einen Roboter oder andere 3D Drucker herzustellen. Doch auch hier scheint es sich um eine Sackgasse zu handeln, weil der Druck von simpelsten Bauteilen sehr viel Zeit in Anspruch nehmen und noch dazu teurer sind, als wenn man traditionelle Maschinen nutzt. Ist womöglich der Traum von sich-selbst reproduzierenden Maschinen ähnlich wie ein Perpetuum Mobile nicht realisierbar? Nicht ganz. Zunächst sollte man wissen, dass sowohl für die Reproduktion von Menschen als auch von Maschinen die Sonne der wichtigste Energielieferant ist. Man muss also keineswegs etwas aus dem Nichts erschaffen sondern es reicht wenn man es schafft die Sonnenenergie irgendwie umzuformen. Man braucht als Ausgangsmaterial entweder Rohstoffe die durch Sonnenlicht wachsen (Pflanzen, Bäume und Holz) oder aber man verwendet Sonnenlicht nur zur Stromversorgung und nutzt als Rohstoffe Altmetalle wie sie auf Schrottplätzen oder in unterirdischen Lagerstätten zu finden sind.

Wirliche Selbstreplikation aus dem Nichts heraus ist eine Illusion die auch die Natur nicht kann. Roboter müssen es demnach auch nicht beherschen, sondern es reicht wenn man Pseudo-Selbstreplikation realisiert. Im einfachsten Fall geht das durch einen Roboterarm, der aus einem Stabilbaukasten einen Roboter konstruiert. Er nutzt also jene Bauteile die schon da sind. Im zweiten Schritt kann man sich dann überlegen, wie man eine unbegrenzte Anzahl von Stabilbäukästen erzeugt. Entweder behauptet man, die wären schon vorher da gewesen, oder baut einen Roboter, der Maschinen bedienen kann die Bauteile eines Stabilbaukastens herstellen. Also einen humanoiden Roboter der eine CNC-Fräse, einen Gabelstapler usw. bedienen kann. Der Ablauf ist dabei so, dass man sich das Rohmeterial irgendwoher besorgt und dann über Arbeitsleistung daraus Fertigprodukte herstellt. Und wie deutlich zu erkennen ist, gibt es sehr oft das Problem dass man irgendwoher von außerhalb etwas zuführen muss. Das heißt, an keiner Stelle des Prozesses handelt es sich um ein autarkes System sondern Selbstreplikation ist immer geschummelt. Der Roboter der aus vorhandenen Teile etwas baut, benötigt zunächst einmal diese Teile. Der Roboter der Bauteile herstellt benötigt zunächst einmal Rohstoffe usw.

Bei Selbstreplikation geht es keineswegs darum, aus sich selbst heraus autark etwas zu generieren sondern worum es eigentlich geht sind die Kopierkosten. Also wie teuer es ist, einen Roboter ein zweites Mal zu bauen. Soetwas kann 10000 US$ kosten oder auch nur 1 US$, jenachdem wie effizient der Ablauf ist. Von Selbstrepliaktion spricht man wenn die Kopierkosten Null oder nahe Null sind.

Um das Problem weiter einzugrenzen gilt es zwei Probleme zu lösen: erstens, self-assembly und zweitens, self-production. Self-assembly wurde bereits erwähnt. Es ist die Fähigkeit aus einem Stabilbaukasten etwas sinnvolles zu bauen. Um das zu realisieren benötigt die Künstliche Intelligenz dexterous Manipulation Fähigkeiten inkl. der Bedienung von Werkzeugen wie ein Schraubenzieher. Self-production meint, dass der Roboter in der Lage ist, die Rohstoffproduktion zu überwachen. Das heißt, er muss mit einem LKW das Metall heranschaffen, er muss das Fließband einschalten, er muss die CNC Fräse bedienen usw.

Man kann den Gesamtprozess aber auch deutlich vereinfachen. Und zwar deswegen weil klar ist, dass ohnehin geschummelt wird. Die Frage ist nur wie sehr man betrügt. Die wohl simpelste Form von Selbstreplikation besteht darin, dass ein Roboter bei einem anderen Roboter auf den On-Schalter drückt. Roboter1 schaltet Roboter2 an. Roboter1 schaltet Roboter3 und Roboter4 an und gleichzeitig schaltet Roboter2 Roboter5 und Roboter6 an und so geht die Kettenreaktion munter weiter. Wie nicht anders zu erwarten, müssen diese externen Roboter irgendwoher kommen, sie sind nicht einfach da sondern man muss sie von außen zuführen. Aber zumindest hat man so eine grobe Vorstellung was es heißt, eine Kettenreaktion auszulösen. Man kann jetzt derartige Systeme realistischer und zugleich schwieriger zu realisieren gestalten. Indem man beispielsweise vor dem Einschalten zunächst noch die Batterie einsetzen muss, und bevor man sie einsetzt diese erst irgendwo herholen muss usw. Dadurch wird der Prozess sehr viel detalierter aber auch schwieriger zu automatisieren.

Letztlich funktioniert so die Selbstreplikation von Robotern. Jenachdem wieviel Teilschritte man vollautomatisch gestalten kann sinken die Kosten und das System wird sich ein wenig mehr anfühlen wie Science-Fiktion. Der schwierigste Part ist jedoch nicht die mechanische Seite sondern es ist die Software. Wenn man bereits über ein Robot-Control-System verfügt ist Selbstreplikation simpel, wenn man aber noch keines hat muss man eines programmieren und zwar möglichst autonom. Hier stellt sich die Frage was das kleinst-mögliche Startsystem ist, also wie der minimale Programmcode aussieht, der gerade noch funktionsfähig ist. Für die Praxis hat die Software jedoch nur eine untergeordnete Bedeutung, denn Software wird von Menschen erstellt, ist also ähnlich wie das Sonnenlicht standardmäßig vorhanden. Wenn man zusätzlich noch die Software von Null aus replizieren will, müsste man zunächst einmal ergründen was menschliche Intelligenz ausmacht. Das ist jedoch eine rein philosophische Frage. Man kann auch ohne darauf eine Antwort zu wissen, self-replicating Robots realisieren.

FLIEßBAND
Realistisch gesehen wird Selbst-Replikation aussehen wie ein Fließband. Es ist nicht nur für menschliche Arbeit das effizientes Mittel sondern auch für automatisierte Arbeit gibt es nichts besseres. Der Unterschied ist lediglich, dass an den einzelnen Stationen dann Roboter stehen, und wenn ein Roboter kaputt geht wird dieser ebenfalls am Fließband wieder repariert.

NANOROBOTER
Auf den ersten Blick klingt die Aussicht auf sich-selbst reproduzierende Maschinen wie der wahr gewordene Traum von Fabrikbesitzern. Allerdings ist diese Utopie nicht besonders mächtig. Denn auch heute schon gibt es arbeitssparende Techniken in der Produktion. Für die Menschheit als solche würde sich gar nichts verändern. Natürlich wäre es schön wenn man manuelle repititive Arbeit durch Roboter durchführen könnte, aber noch schöner wäre es wenn man Roboter auf anderem Gebiet einsetzt wo sie vielmehr bewirken können. Und das ist in der Medizin. Das Hauptproblem was sich in den letzten 100 Jahren trotz Automatisierung nicht verbessert hat ist die Sterblichkeit von Menschen. Im Normalfall dauert das Leben eines Individuums selten mehr als 70 Jahre und diese Spanne zu verlängern ist derzeit technisch nicht möglich. Es gibt gegen die meisten Krankheiten keine Heilung. Der Normalfall ist stattdessen, dass man den nahenden Tod von seiner zynischen Seite betrachtet weil man weiß dass er jeden gleichermaßen trifft. Aber was wäre, wenn Robotik an diesem Dogma etwas ändern könnte? Was wäre, wenn man mit medizinischen Nanorobotern Krebs heilen kann?

Es gibt auch friedliche Roboter

Roboter müssen nicht immer nur böse sein. Der Kamerad im obigen Video zeigt dass es auch anders geht. Er ist komplett friedlich und öffnet das Geschenk. Er muss vorher noch den Karton aufmachen, darf das Gleichgewicht nicht verlieren und muss auch noch ein externes Tool bedienen, aber so schlecht macht er das gar nicht. Unnötig zu erwähnen, dass der Roboter auch noch eine Hand mit 10 Fingern besitzt und auf keinen Fall mit Finite-State-Maschines programmiert wurde.

Python vs. C++

Das Robot-Control-System was hier in zwei Blog-Einträgen bereits vorgestellt wurde ist mit Python programmiert. Aber dass soll nicht heißen, dass Python die beste Sprache dafür ist. Ein kleiner Exkurs zu C++ und SFML hat ergeben, dass man auch damit sehr ordentliche Programme schreiben kann. Um ehrlich zu sein, eigentlich kommt mir C++ ein wenig professioneller vor. Wenn man dort einen Grafikbildschirm öffnet ist er einfach da. Man startet das Programm und es werden die benötigten 60fps angezeigt. Kein Ruckeln, kein hoher CPU Verbrauch sondern die Applikation läuft einfach. Wenn also die C++ Community behauptet, dass alle anderen Programmiersprachen auf der Welt nur ein müder Ersatz sind für C++ so kann man ihnen nur beipflichten. Dennoch wird das Robot-Control-System zunächst weiterhin in Python entwickelt werden. Warum? C++ ist zwar eine mächtige Sprache wenn der Code einmal erstellt wurde, aber genau das ist das Problem. Bei Python geht der Edit-Compile-Run Zyklus um einiges schneller, insbesondere dann wenn man zwischendurch noch Stackoverflow fragt weil Probleme aufgetreten sind. Wenn hingegen die Python App inkl. der nötigen Algorithmen bereits fertig ist und es nur noch um Fragen wie Packaging, Bereitstellen auf verschiedenen Zielplattformen und niedrigen Ressourcenverbrauch geht, macht es Sinn den Quellcode nochmal neu für C++ zu schreiben. Die Aufgabe, vorhandenen Python Code nach C++ zu konvertieren ist eine überschaubare und sehr dankbare Tätigkeit, weil man damit die Qualität der Software beträchtlich steigert. Eine sauber programmierte SFML Applikation ist um einiges besser als ein lieblos zusammenprogrammierter Python Prototyp.

Zugegeben, anders als die Überschrift vermuten lässt geht es nicht darum Python mit C++ zu vergleichen, sondern im Grunde lautet die Empfehlung beide Sprachen zu nutzen. Man wird dadurch die Vorteile der anderen Sprache viel besser zu würdigen wissen. Für Python Programmierer wirkt C++ wie eine Offenbarung, weil dort alles so schön effizient läuft. Man ist auch nicht abhängig von irgendwelchen CPython, Jython und sonstigen Interpretern sondern hat am Ende die eine ausführbare Binärdatei die dann mit maximaler Performance läuft. Umgekehrt ist aus Sicht von C++ aber Python ebenfalls eine Verbesserung, weil man dort sehr viel schneller zu vorzeigbarem Code gelangt und man sich stärker auf die eigentliche Applikation kümmern kann.

Beide Sprache miteinander zu verbinden ist mehrmals versucht worden. Es gibt die Boost.Python Library die jedoch sehr schwer verständlich ist, und es gibt neuere Sprachen wie go welchen ebenfalls versprechen das beste von beiden Welten zu vereinen. Wirklich empfehlenswert ist davon nichts. Nach wie vor gilt C++ pur und Python pur als State-of-the-art in der jeweiligen Domäne. Sondern man sollte das ganze lieber von einem Software-Engineering-Prozess aus betrachten. Solange man in der Prototypenphase ist und noch nicht genau weiß was man eigentlich will, ist Python das Mittel der Wahl. Wenn man hingegen bereits einen Prototypen hat und jetzt richtige Software programmieren möchte, ist C++ besser geeignet um ans Ziel zu gelangen.

Sowohl Python als auch C++ müssen sich Kritik gefallen lassen. Python gilt als Anfängersprache die sehr langsam ausgeführt wird und vom Status her noch unterhalb von Java angesiedelt ist. Ist diese Kritik unsachlich? Wohl kaum, es beschreibt Python angemessen. Auf der anderen Seite gilt C++ als Pointerlastige und schwer zu erlernde Sprache wo der Code unleserlich ist und dauernd Compilerwarnungen angezeigt werden. Auch dieser Einwand ist berechtigt. Aber ich glaube nicht, dass man die Sprache verändern sollte. Sondern C++ und Python sind gut dort wo sie heute sind. Als Best-Practice kann man sagen, dass man sich in Eclipse sowohl pydev als auch CDT installieren sollte um beides zu nutzen. Eclipse ist das derzeit mächtigste IDE Framework, Python ist die mächtigste Prototyping Sprache und C++ die beste Programmiersprache.

Kritik an Wikipedia

https://de.wikipedia.org/w/index.php?limit=50&title=Spezial%3ABeitr%C3%A4ge&contribs=user&target=ManuelRodriguez&namespace=0&tagfilter=&year=2017&month=-1

Inzwischen bin ich ca. 2 Monate bei Wikipedia neu dabei und habe insgesamt 8 Edits durchgeführt. Zeit für ein kleines Resüme was mir in dieser Zeit aufgefallen ist. Bei Wikipedia gibt es derzeit zwei große Kritikpunkte. Einmal ist das Verhältnis von Naturwissenschaften zu Geistenwissenschaft nicht ausgewogen, sondern 80% aller Wikipedia Einträge sind aus den Geisteswissenschaften. Übrigens hat sich in den letzten 2 Jahren das Verhältnis sogar noch verschlechtert, das heißt, die Naturwissenschaften verlieren leicht. Der zweite Kritikpunkt betrifft dass zu wenig wert auf wissenschaftliche Belege gelegt wird und stattdessen aus Newsportalen wie Spiegel Online, Heise.de und aus Tageszeitungen zitiert wird.

Das eigentliche Problem von Wikipedia ist jedoch, dass die oben genannte Punkte nicht als Problem erkannt werden. Stattdessen glaubt die Community, dass andere Dinge in der Schieflage sind. Häufig wird als Problem bei Wikipedia verortet, dass dort bezahltes Schreiben stattfindet, dass bei umstrittenen Themen Verschwörungstheorien ausgebreitet werden oder dass der Frauenanteil zu niedrig wäre. Das sind jedoch alles keine wirklichen Probleme.

Aber ich will nicht zuviel kritisieren sondern auch sagen, was mir an Wikipedia gut gefällt. Beispielsweise das Ranking in Suchmaschinen. Wenn man es einmal fertiggebracht hat, einen Edit an der Wikipedia-Eingangskontrolle vorbeizuschmuggeln hat man im Regalfall ein Super-Ranking bei Google. Gibt man das Stichwort in die Suchmaske ein, wird der Wikipedia Artikel im Regelfall auf Platz 1 angezeigt. Ein Durchschnitts-Wikipedia Artikel hat 50-150 Hits am Tag, was höher ist als die meisten Blogs erzielen und höher ist als die meisten wissenschaftlichen Paper auf Arxiv erzielen. Ebenfalls angenehm ist die Markup-Sprache Wikisyntax mit der man die Formatierungen festlegt. Das Einbinden von Grafiken ist leicht, Inhaltsverzeichnisse werden automatisch erzeugt und wenn man sich einmal an die Literaturvorlage gewöhnt hat wird man nichts anderes mehr wollen.

Als sehr mächtig hat sich auch das Kategoriesystem erwiesen. Es handelt sich um hierbei um hierarchiche Tags um Artikel zu gruppieren was vergleichbar ist mit der Dewey-Dezimalklassifikation aus Bibliotheken. Apropos Übersicht: auch die Volltextsuche über alle Artikel hinweg funktioniert perfekt. Die dahinterstehenden Server reagieren wirklich prompt.

Soweit mein kleiner Rückblick auf 2 Monate Wikipedia. Mal sehen ob ich nach weiteren 2 Monaten immernoch lächeln kann oder ob bis dahin alle meine Edits zurückgesetzt wurden. …

Vintage Computer shreddern

Aktuell schießen Computermuseuen wie Pilze aus dem Boden. Es gibt sogar eigene Festivals die sich mit älterer Computerhard- und Software beschäftigen. Ausgestellt sind dort Rechner von Commodore, Atari und IBM. Aber wie wäre es, wenn man zur Abwechslung alte Dinge nicht in einem Museum präsentiert sondern in einen Metall-Shredder zerkleinert? Ein sogeannanter E-Waste-Shredder ist der Höhepunkt eines echten Vintage Computer Festivals wo als Höhepunkt einige besonders wertvolle Sammlerstücke dem nimmersatten Zerkleinerer anvertraut wären. Leider gibt es dazu aktuell noch keine Videos auf Youtube. Was jedoch in einigen Videos aus dem Kontext „PC Shredding“ zu sehen ist, waren zerkleinerte MS-DOS 6.22 Disketten, und Platinen die aus den 1990’er stammen und noch mit Pentium Prozessor ausgestattet waren. Wer traut sich, und shreddert einen goldenen C-64 (davon wurden nur wenige Stück produziert), oder wer shreddert eine funktionsfähige DEC PDP11 inkl. aller Magnetbänder?

Man könnte dochmal mit einem mobilen Shredder vor ein Computermuseum fahren … Na ja, jedenfalls gibt es da gewisse Gemeinsamkeiten. Beide Male geht es um ausrangierten Elektroschrott aus dem Profit gemacht gemacht. Beim Museum werden Eintrittsgelder kassiert und beim Elektroschrott-Verwerten geht es um die Metall-Rohstoffe.