i3C

Serial connection Host <--> VirtualBox VM
-----------------------------------------

In VirtualBox create named pipe:

  Select machine (MiniPi, Debian 9): RClick Settings
  Serial Ports:
  Port 1:
  [v] Enable Serial Port
  Port Number: COM1  IRQ: 4 I/O Port: 0x3F8
  Port Mode Host Pipe
  [ ] Connect to existing pipe/socket
  Path/Address: \\.\pipe\myvbox
  COM1
  [ ]

  $ sudo dmesg | grep ttyS
  [    0.874587] 00:02: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200)
                 is a 16550A

  $ sudo apt-get install putty

  Putty on Guest:

  Serial line:       Speed:  (serial)
  /dev/ttyS0         9600
  Window -> Fonts: Font used for ordinary text:
  client: Monospace 14

  Putty on Host:

  Serial line:       Speed:  (serial)
  \\.\pipe\myvbox    9600*
  Window -> Fonts: Font used for ordinary text:
  client: Monospace 14

*) NOTE that windows named pipe \\.\pipe\myvbox have nothing in common with serial port, so you may freely set putty speed to whatever (say 115200) or send some data to virtualbox side as:

  Windows CMD (Run as Administrator) # echo Hello > \\.\pipe\myvbox

Links:

  https://www.cyberciti.biz/faq
  /find-out-linux-serial-ports-with-setserial/

Downloads:

  https://www.wago.com/wagoweb/documentation/navigate/nm9mpl_e.htm

  SerComm.lib   deutschAcrobat Reader265 kB V 1.5.0
                englishAcrobat Reader270 kB V 1.5.0   ZIP

Last Update 09-12-08

SimulIDE:

Right Click on Arduino Uno: Open Serial Port (dialog window)

On dialog window press 'Open' button:

  Device: /dev/ttyS0
  Button: Open

Test sketch:

  void setup() {
      Serial.begin( 9600);
      pinMode( 13, OUTPUT);
      // wait for serial port to connect.
      // Needed for native USB port only.
      while ( !Serial);
  }

  void loop() {
      if ( Serial.available() > 0) {
          int inByte = Serial.read();
          if ( inByte == '+') digitalWrite( 13, HIGH);
          if ( inByte == '-') digitalWrite( 13, LOW);
      }
  }

Run sketch and connect with Putty session on host:

  Serial line: \\.\pipe\myvbox
  Speed: 9600

Sketch with BCD 7SEG display on D11..D8

  int i = 0;

  void setup() {
      Serial.begin( 19200);
      pinMode( 8, OUTPUT);
      pinMode( 9, OUTPUT);
      pinMode( 10, OUTPUT);
      pinMode( 11, OUTPUT);
      // wait for serial port to connect.
      // Needed for native USB port only.
      while ( !Serial);
  }

  void loop() {
      if ( Serial.available() > 0) {
          int inByte = Serial.read();
          if ( inByte == '+') i++;
          if ( inByte == '-') i--;
          digitalWrite( 8,  i & 1);
          digitalWrite( 9,  i & 2);
          digitalWrite( 10, i & 4);
          digitalWrite( 11, i & 8);
      }
  }

To simplify this sketch, we have to look at Arduino Uno schematics:

  int i = 0;

  void setup() {
      Serial.begin( 19200);
      DDRB = 0xff;
      while ( !Serial);
  }

  void loop() {
      if ( Serial.available() > 0) {
          int inByte = Serial.read();
          if ( inByte == '+') i++;
          if ( inByte == '-') i--;
          PORTB = i;
      }
  }

If Arduino writes:

  void setup(){
      Serial.begin(19200);
      while ( !Serial);
  }

  void loop(){
      Serial.write(45); // send a byte with the value 45

      //send the string "hello" and return the length of the string.
      int bytesSent = Serial.write("hello");
  }

Python 2.7 (Clone Debian machine, serial pipe exists ([v]) in case you start this machine later)

Older PySerial

  https://pypi.python.org/pypi/pyserial/2.7
  pyserial-2.7.win32.exe35

Sender:

  import serial
  import time
  import pipes

  ser = serial.Serial('/dev/ttyS0',9600)

  time.sleep(2)
  while True:
      ser.write('+')
      time.sleep(1)
      ser.write('-')
      time.sleep(1)

  ser.close()

Receiver:

  import serial
  import time

  ser = serial.Serial('/dev/ttyS0',9600)

  o = ''
  while True:
      if ser.in_waiting :
          o = ser.read()
          print( o)


Pendulum

  # Swing -- a seat suspended by ropes or chains, on which
  #          someone may sit and swing back and forth.

  # import serial
  from visual import *
  from math import *

  SCREEN = 800;
  PENLEN = 10;  # pendulum length
  BALLRA = 1.5  # ball radius
  PERSPE = PENLEN / 3
  INITDA = .013
  scene.width  = SCREEN;
  scene.height = SCREEN;

  G      = 9.81

  w = box( color=(.2,.2,.2), pos=(0,0,-2),  \
           size=( 2*PENLEN+2*BALLRA+PERSPE, \
                  2*PENLEN+2*BALLRA+PERSPE, \
                  .1                        \
           )                                \
      )
  c = cylinder( pos=(0,0,-2), axis=(0,0,1), \
                length = 4, color=color.red \
      )
  b = box( color=color.blue, size=(1,PENLEN,1))
  s = sphere( color=color.green, radius=BALLRA)

  da = INITDA # initial speed
  a = da
  dam = 1
  h = PENLEN
  c = 0
  cold = 0
  t = 0

  # ser = serial.Serial('/dev/ttyS0',9600)

  while True:
      c += 1
      rate(200)
      b.axis=( cos(a), sin(a), 0)
      b.pos=( PENLEN/2 * sin(a),-PENLEN/2 * cos(a), 0)
      s.pos=( PENLEN * sin(a), -PENLEN * cos(a), 0)

      h = PENLEN * (1 - cos(a))

      tmp = INITDA*INITDA - 0.000001*G*h
      if tmp > 0:
          da = sqrt( tmp)
      else:
          dam = sign( a)

      if h < 0.001:
          if (c - cold) != 1 and c > 3:
              t = 0 if t > 255 else t + 1
              print(t)
              # INITDA = 0.5 * INITDA
              # if da < 0.0001:
              #     INITDA = 0.014
              # ser.write(bytearray([t]))
          cold = c

      a = a - da * dam

Elevator
--------

  from visual import *
  import math

  FLOOR = 16
  SCREEN = 800
  DOOR = FLOOR-2
  BALLRA = -1+DOOR/2
  ELEVARA = 9
  THICK = 0.1

  class BB:
      def __init__( self, afloor):
          self.btop = box( \
              width=DOOR, height=.05, length=DOOR, color=(.3,.3,.3));
          self.btop.pos=(+9.95+DOOR/2,DOOR/2-FLOOR+(FLOOR)*afloor, 0);
          self.bbottom = box( \
              width=DOOR, height=.05, length=DOOR, color=(.3,.3,.3));
          self.bbottom.pos=(+9.95+DOOR/2,-DOOR/2-FLOOR+(FLOOR)*afloor, 0);
          self.bback = box( \
              width=DOOR, height=DOOR, length=.05, color=(.3,.3,.3));
          self.bback.pos=(+9.95+DOOR,-FLOOR+(FLOOR)*afloor, 0);
          self.bf = box( \
              width=.05, height=DOOR, length=DOOR, color=(.3,.3,.3));
          self.bf.pos=(+9.95+DOOR/2,-FLOOR+(FLOOR)*afloor, DOOR/2);
          self.br = box( \
              width=.05, height=DOOR, length=DOOR, color=(.3,.3,.3));
          self.br.pos=(+9.95+DOOR/2,-FLOOR+(FLOOR)*afloor, -DOOR/2);

  class Door:
      def __init__( self, afloor):
          self.bb = BB( afloor);
          self.bg = box( \
              width=DOOR, height=DOOR, length=0.05, color=(.3,.3,.3))
          self.bg.pos=(+9.9,-FLOOR+(FLOOR)*afloor, 0);
          self.mfloor = afloor;
          self.status = "closed";

      def open( self):
          if self.status == "closed":
              self.status = "opened";
              for k in range(91):
                  rate(100)
                  self.bg.axis = (math.cos(math.radians(k)), \
                      math.sin(math.radians(k)),0)
                  self.bg.pos=(+9.9-DOOR*math.sin(math.radians(k))/2, \
                      -FLOOR+(FLOOR)*self.mfloor-DOOR/2+ \
                      DOOR*math.cos(math.radians(k))/2, 0)

      def close( self):
          if self.status == "opened":
              self.status = "closed";
              for k in reversed( range(91)):
                  rate(100)
                  self.bg.axis = (math.cos(math.radians(k)), \
                      math.sin(math.radians(k)),0)
                  self.bg.pos=(+9.9-DOOR*math.sin(math.radians(k))/2, \
                      -FLOOR+(FLOOR)*self.mfloor-DOOR/2+ \
                      DOOR*math.cos(math.radians(k))/2, 0)

  class Elevator:
      color.lightblue=(0.5,0.8,1);
      rainbow = [color.red, color.orange, color.yellow, color.green, \
                 color.lightblue, color.blue, color.magenta];

      def __init__( self):
          self.mfloor = -1;
          self.r = [];
          for k in range(7):
              self.r.append( \
                  ring( radius=ELEVARA, pos=(0,27,0), \
                  color=self.rainbow[k], axis=(0,1,0)) \
              )

      def comes( self, afloor):
          if self.mfloor == -1:
              for k in range(7):
                  for y in range(3*(3-afloor)*FLOOR-6*k):
                      rate(200);
                      self.r[k].pos=(0, 3*FLOOR/2+2-y/3., 0);
              self.mfloor = afloor;

      def goes( self):
          for k in reversed( range(7)):
              for y in reversed( range(3*(3-self.mfloor)*FLOOR-6*k)):
                  rate(200);
                  self.r[k].pos=(0, 3*FLOOR/2+2-y/3., 0);
          self.mfloor = -1; # gone

  class Ball:
      color.pink = (0.95, 0.72, 0.8);

      def __init__( self, afloor):
          self.mfloor = afloor;
          self.ma = 0;
          self.ball=sphere( radius=BALLRA, \
                            material=materials.marble, \
                            color=color.pink);
          self.ball.pos = (10+BALLRA,-FLOOR+afloor*FLOOR,0);
          self.ball.opacity = 1;

      def get_floor( self):
          return self.mfloor;

      def appears( self, afloor):
          self.mfloor = afloor;
          self.ball.pos = (0,-FLOOR+afloor*FLOOR,0);
          for o in range(11):
              rate(20);
              self.ball.opacity = o/10.;

      def disappears( self):
          for o in range(11):
              rate(20);
              self.ball.opacity = 1 - o/10.;

      def pop( self):
          x = self.ball.pos.x;
          a = self.ma;
          while( x > 0):
              rate(50);
              self.ball.pos = (x,-FLOOR+self.mfloor*FLOOR,0);
              self.ball.axis = (math.cos(a), math.sin(a), 0);
              a += .011
              x -= .1;
          self.ma = a;

      def push( self):
          x = self.ball.pos.x;
          a = self.ma;
          while( x < 10+BALLRA):
              rate(50);
              self.ball.pos = (x,-FLOOR+self.mfloor*FLOOR,0);
              self.ball.axis = (math.cos(a), math.sin(a), 0);
              a -= .011;
              x += .1;
          self.ma = a;

  def travel( ato):
      door[ball.get_floor()].open();
      ball.pop();
      elevator.comes(ball.get_floor());
      ball.disappears();
      elevator.goes();
      door[ball.get_floor()].close();

      door[ato].open();
      elevator.comes(ato);
      ball.appears(ato);
      elevator.goes();
      ball.push();
      door[ato].close();

      rate(2);

  scene.width  = SCREEN;
  scene.height = SCREEN;

  box( pos=(0,0,-10), width=THICK, height=4*FLOOR, \
       length=0.1, color=color.black);

  pyramid( pos=(0,1+3*FLOOR/2,0), axis=(0,1,0), \
           size=(15,25,25), color=(.3,.3,.3));

  door = [Door(0), Door(1), Door(2)];
  elevator = Elevator();
  ball = Ball( 0);

  while True:
      travel( 1);
      travel( 2);
      travel( 0);

      travel( 2);
      travel( 1);
      travel( 0);

      travel( 2);
      travel( 0);

Balls
-----

  from random import seed, randint
  from visual import *

  palette=[ color.red, color.orange, color.yellow, color.green, \
            color.cyan, color.blue, color.magenta]

  seed()
  box( pos=(0, 0, -1.2), color=(.4, .6, .4), \
  width=0.1, height=13, length=13)
  sphere( color=color.orange, pos=(0, 4, 0))

  for y in range(1, 5):
    for x in range(0, y+1):
      sphere(color=palette[ randint(0,6)], pos=(-y+2*x,4-1.7*y,0))

Serial Connection with Arduino C++ class:

  https://blog.manash.me
  /serial-communication-with-an-arduino-using-c-on-windows-d08710186498
  https://github.com/jacobsa/go-serial/issues/28

Does anyone know of a good C++ serial port class? Take a look at:

  http://www.naughter.com/serialport.html

Found here:

  https://social.msdn.microsoft.com/Forums/en-US
  /f1f9a71f-3e55-40dc-9b82-44f910b7f078
  /c-serial-port-classlibrary?forum=vcgeneral

Pendulum Python 3.6 (VPython 7 adaptation)
------------------------------------------

In Thonny REPL:

  >>> import pip
  >>> pip.main(['install','vpython'])    # visual python 7
  >>> pip.main(['install','pywin32'])    # pipes
  >>> pip.main(['install','pyserial'])   # serial

# Pendulum36.py

  # Swing -- a seat suspended by ropes or chains, on which
  #          someone may sit and swing back and forth.

  # import serial
  from vpython import *
  from math import *

  SCREEN = 800;
  PENLEN = 10;  # pendulum length
  BALLRA = 1.5  # ball radius
  PERSPE = PENLEN / 3
  INITDA = .014007
  scene.width  = SCREEN;
  scene.height = SCREEN;

  G      = 9.81

  w = box( color=vector(.2,.2,.2), pos=vector(0,0,-2),  \
           size=vector( 2*PENLEN+2*BALLRA+PERSPE,       \
                        2*PENLEN+2*BALLRA+PERSPE,       \
                        .1                              \
                       )                                \
          )

  c = cylinder( pos=vector(0,0,-2), axis=vector(0,0,1), \
                length = 4, color=color.red \
               )

  b = box( color=color.blue, size=vector(1,PENLEN,1))
  s = sphere( color=color.green, radius=BALLRA)

  da = INITDA # initial speed
  a = da
  dam = 1
  h = PENLEN
  c = 0
  cold = 0
  t = 0

  # ser = serial.Serial('/dev/ttyS0',9600)

  while True:
    c += 1
    rate(200)
    b.axis = vector( cos(a), sin(a), 0)
    b.pos  = vector( PENLEN/2 * sin(a),-PENLEN/2 * cos(a), 0)
    s.pos  = vector( PENLEN * sin(a), -PENLEN * cos(a), 0)

    h = PENLEN * (1 - cos(a))

    tmp = INITDA*INITDA - 0.000001*G*h
    if tmp > 0:
        da = sqrt( tmp)
    else:
        dam = 1 if a>0 else -1

    if h < 0.001:
        if (c - cold) != 1 and c > 3:
            t = 0 if t > 255 else t + 1
            # print(t)
            # INITDA = 0.5 * INITDA
            # if da < 0.0001:
            #     INITDA = 0.014
            # ser.write(bytearray([t]))
        cold = c

    a = a - da * dam

# Elevator36.py (VPython 7 adaptation)

  from vpython import *
  import math

  FLOOR = 16
  SCREEN = 800
  DOOR = FLOOR-2
  BALLRA = -1+DOOR/2
  ELEVARA = 9
  THICK = 0.1

  class BB:
    def __init__( self, afloor):
        self.btop = box( \
            width=DOOR, height=.05, length=DOOR, color=vector(.3,.3,.3))
        self.btop.pos = \
            vector(+9.95+DOOR/2,DOOR/2-FLOOR+(FLOOR)*afloor, 0)
        self.bbottom = box( \
            width=DOOR, height=.05, length=DOOR, color=vector(.3,.3,.3))
        self.bbottom.pos = \
            vector(+9.95+DOOR/2,-DOOR/2-FLOOR+(FLOOR)*afloor, 0)
        self.bback = box( \
            width=DOOR, height=DOOR, length=.05, color=vector(.3,.3,.3))
        self.bback.pos=vector(+9.95+DOOR,-FLOOR+(FLOOR)*afloor, 0)
        self.bf = box( \
            width=.05, height=DOOR, length=DOOR, color=vector(.3,.3,.3))
        self.bf.pos=vector(+9.95+DOOR/2,-FLOOR+(FLOOR)*afloor, DOOR/2)
        self.br = box( \
            width=.05, height=DOOR, length=DOOR, color=vector(.3,.3,.3))
        self.br.pos=vector(+9.95+DOOR/2,-FLOOR+(FLOOR)*afloor, -DOOR/2)

  class Door:
    def __init__( self, afloor):
        self.bb = BB( afloor)
        self.bg = box( \
            width=DOOR, height=DOOR, \
            length=0.05, color=vector(.3,.3,.3))
        self.bg.pos=vector(+9.9,-FLOOR+(FLOOR)*afloor, 0)
        self.mfloor = afloor
        self.status = "closed"

    def open( self):
        if self.status == "closed":
            self.status = "opened"
            for k in range(91):
                rate(100)
                self.bg.axis = vector(math.cos(math.radians(k)), \
                    math.sin(math.radians(k)),0)
                self.bg.pos = \
                    vector(+9.9-DOOR*math.sin(math.radians(k))/2, \
                    -FLOOR+(FLOOR)*self.mfloor-DOOR/2+ \
                    DOOR*math.cos(math.radians(k))/2, 0)

    def close( self):
        if self.status == "opened":
            self.status = "closed"
            for k in reversed( range(91)):
                rate(100)
                self.bg.axis = vector(math.cos(math.radians(k)), \
                    math.sin(math.radians(k)),0)
                self.bg.pos = \
                    vector(+9.9-DOOR*math.sin(math.radians(k))/2, \
                    -FLOOR+(FLOOR)*self.mfloor-DOOR/2+ \
                    DOOR*math.cos(math.radians(k))/2, 0)

  class Elevator:
    color.lightblue=vector(0.5,0.8,1)

    rainbow = [color.red, color.orange, color.yellow, color.green, \
               color.lightblue, color.blue, color.magenta]

    def __init__( self):
      self.mfloor = -1
      self.r = []
      for k in range(7):
        self.r.append( \
          ring( thickness=0.7, radius=ELEVARA, \
            pos=vector(0,27,0), color=self.rainbow[k], \
            axis=vector(0,1,0)) \
        )

    def comes( self, afloor):
      if self.mfloor == -1:
        for k in range(7):
          for y in range(3*(3-afloor)*FLOOR-6*k):
            rate(100)
            self.r[k].pos=vector(0, 3*FLOOR/2+2-y/3., 0)
        self.mfloor = afloor

    def goes( self):
      for k in reversed( range(7)):
        for y in reversed( range(3*(3-self.mfloor)*FLOOR-6*k)):
          rate(100)
          self.r[k].pos=vector(0, 3*FLOOR/2+2-y/3., 0)
      self.mfloor = -1; # gone

  class Ball:
    color.pink = vector(0.95, 0.72, 0.8)

    def __init__( self, afloor):
      self.mfloor = afloor
      self.ma = 0
      self.ball=sphere( radius=BALLRA, \
                        texture=textures.stucco, \
                        color=color.pink)
      self.ball.pos = vector(10+BALLRA,-FLOOR+afloor*FLOOR,0)
      self.ball.opacity = 1

    def get_floor( self):
      return self.mfloor

    def appears( self, afloor):
      self.mfloor = afloor
      self.ball.pos = vector(0,-FLOOR+afloor*FLOOR,0)
      for o in range(11):
        rate(20)
        self.ball.opacity = o/10.

    def disappears( self):
      for o in range(11):
        rate(20)
        self.ball.opacity = 1 - o/10.

    def pop( self):
      x = self.ball.pos.x
      a = self.ma
      while( x > 0):
        rate(50)
        self.ball.pos = vector(x,-FLOOR+self.mfloor*FLOOR,0)
        self.ball.axis = vector(math.cos(a), math.sin(a), 0)
        a += .011
        x -= .1
      self.ma = a

    def push( self):
      x = self.ball.pos.x
      a = self.ma
      while( x < 10+BALLRA):
        rate(50)
        self.ball.pos = vector(x,-FLOOR+self.mfloor*FLOOR,0)
        self.ball.axis = vector(math.cos(a), math.sin(a), 0)
        a -= .011
        x += .1
      self.ma = a

  def travel( ato):
    door[ball.get_floor()].open()
    ball.pop()
    elevator.comes(ball.get_floor())
    ball.disappears()
    elevator.goes()
    door[ball.get_floor()].close()

    door[ato].open()
    elevator.comes(ato)
    ball.appears(ato)
    elevator.goes()
    ball.push()
    door[ato].close()

    rate(2)

  scene.width  = SCREEN
  scene.height = SCREEN

  box( pos=vector(0,0,-10), width=THICK, height=4*FLOOR, \
       length=0.1, color=color.black)

  pyramid( pos=vector(0,1+3*FLOOR/2,0), axis=vector(0,1,0), \
           size=vector(15,25,25), color=vector(.3,.3,.3))

  door = [Door(0), Door(1), Door(2)]
  elevator = Elevator()
  ball = Ball( 0)

  while True:
    travel( 1)
    travel( 2)
    travel( 0)

    travel( 2)
    travel( 1)
    travel( 0)

    travel( 2)
    travel( 0)

Python Pipes
............

Modern pywin32 is on github (makes import win32pipe, win32file.. available)

  https://github.com/mhammond/pywin32/releases

NOTE that on windows named pipe \\.\pipe\myvbox have nothing in common with serial port..

Thonny, v.3.6.4 on Windows host.

  >>> import struct; print(struct.calcsize("P") * 8)
  32
  >>> import sys; >>> sys.version_info[0:5]
  (3, 6, 4, 'final', 0)

  >>> import pip
  >>> pip.main(['install','pywin32'])
  Collecting pywin32
  ..
  Installing collected packages: pywin32
  Successfully installed pywin32-223

rs.py

  import win32pipe
  import win32file

  fileHandle = \
      win32file.CreateFile("\\\\.\\pipe\\myvbox",
          win32file.GENERIC_READ | win32file.GENERIC_WRITE,
          0, None,
          win32file.OPEN_EXISTING,
          0, None)

  dati = win32file.ReadFile(fileHandle, 4096)
  print( dati)

  dato = "Hello Pipe".encode("ascii")
  win32file.WriteFile(fileHandle, dato)

Output:

  PS G:\TMP> python .\rs36.py  # key 'T'
  (0, 'T')

Check architecture installed:

  PS> python -c 'import struct; print struct.calcsize(\"P\") * 8'

Tip of the day: Range

  >>> [x * 0.1 for x in range(0, 10, 3)]
  [0.0, 0.30000000000000004, 0.6000000000000001, 0.9]

Links
-----

  https://www.programcreek.com/python/example/70014
  /win32pipe.CreateNamedPipe

  https://stackoverflow.com/questions/13319679
  /createnamedpipe-in-python

