Category Archives: Uncategorized

servo for scratchClient

During a conversation on scratch forum there have been quite a few issues to get a servo run on someones computer.

Here a video on installation scratchClient on a new sd card, run scratchClient and prepare a script in scratch1.4.

install scratchClient and running servo sample.

The sequence is shortened a bit. Especially the system update is at multiple speed.

When the servo moves, there is noticeable jitter. Caused by delays in python and operating system.

scratchClient and scroll_phat_hd

There is a nice little led matrix moard from PIMORONI, “SCROLL PHAT HD”. The form factor is for the pi zero, but it runs well also with a pi 3.

scroll_phat_hd

scratchClient offers support for this board.

The interface allows to set pixel with brightness, write large and somewhat smaller text and of course clear the display.

There is a sample scratch script in scratch/scrollphathd/scroll_phat_hd.sb

There are quite a few commands from scratch which need parameters.
This is not a trivial task with scratch. Here a variable is used as a ‘command’-Variable ‘sph_command which receives operation names optionally with parameters.


Clear the display. There is also a broadcast command for this ‘clearDisplay’


Set a pixel at x=1, y=1, brightness = 1.0. Valid ranges are x in [0..16], y in [0..6], brightness is [0.0..1.0]. Values out of scope are ignored.


Draw a box between two pixels, here between [0;0] and [17;7] with brightness 0.3. This command effectively sets all led to on.

There are two text variables provided with a 5*7-font and a 3*5 font. Not all chars are supported. The 5*7 font basically supports ascii, the 3*5 font supports digits and some extra chars as ,;.:-_+\/.
The fonts are defined in ‘pseudographics’ in a python file and can easily be expanded.

There is a sample config file available, start scratchClient with

cd ~/scratchClient
python src/scratchClient.py -c config_scrollphathd

The adapter code has been written based on code from pimoroni.

minecraft and scratchClient

On raspberry pi, there is a local minecraft release available which supports a python API.

There is a MinecraftAdapter available for scratchClient which supports this API and allows to do basic operations.

For most of the operations, there are coordinate values to be set first before the operation is performed.

Example: set position of ‘person’.

Example: set Block

There is a sample scratch application in scratch/minecraft/minecraft.sb which demonstrates the basic concepts.

There are some demo scripts in minecraft.sb. One of these writes ‘scratch’ to the landscape. There is no ‘printString’-Function in the adapter. The pixel are defined in a local list, containing x and y-values of pixels. The data for this array are generated by a small python script and then imported into the list.

The python code is in scratch/minecraft/scratch_x_y.py. Run it by

python scratch_x_y.py > scratch_x_y.txt

and import the txt-file into the array.

The python code is quite simple.

f0="                         *          *        "    
f1="                         *          *        "
f2=" ***   ***  * **   ***  ***    ***  * **     "
f3="*     *   * **  *     *  *    *     **  *    "
f4=" ***  *     *      ****  *    *     *   *    "
f5="    * *   * *     *   *  *  * *   * *   *    "
f6="****   ***  *      ****   **   ***  *   *    "

def printPixel(f, level):
    for i in range(len(f)):
        if '*' == f[i]:
            print(i)      # print x-koordinate
            print(level)  # print y-koordinate
            
printPixel(f6, 1)
printPixel(f5, 2)
printPixel(f4, 3)
printPixel(f3, 4)
printPixel(f2, 5)
printPixel(f1, 6)
printPixel(f0, 7)

The pixels are defined in ‘pseudographic’. It is simple to add more text, decorations or extend the output by colors ( * ==> green, # ==> red) and adjust the scratch script to take each third line for the color information.
But keep in mind that ‘the world’ is limited size for minecraft for py and coordinates should be kept in range.

python timing loop accuracy

On a raspberry pi in python, it is not possible to produce accurate timings in μs range. The question is how accurate the timing is in real live.

The issue was raised by someone asking a question in raspberry pi forum on an 80Hz timing loop “the values may not always be accurate at the milliseconds level”.

To measure this, a simple timing loop was set up in python, and the timing was measured with the help of an arduino due. The arduino due runs at 84MHz and is ideal as a versatile measuring tool for this sort of problems.

Python timing loop. The loop should produce a square wave with 12.5ms or 80Hz.

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

pin_AO = 17
GPIO.setup(pin_AO, GPIO.OUT)

dt = 0
diff = 0.0115
while True:
    drun = diff - dt
    
    t0 = time.time()
    for _ in range(0, 1000):
        GPIO.output(pin_AO, GPIO.LOW)
        time.sleep(0.001)
        GPIO.output(pin_AO, GPIO.HIGH)
        time.sleep(drun)
    t1 = time.time();
    # calculate the deviation from ideal value 12.5 ms.
    dt = (t1 - t0) / 1000 - 0.0115 - 0.001
    print(dt)

The idea is to adjust timing based on average of last 1000 pulses.

The output of the arduino due is printed to Serial and looks like (values in μs):

...
12508
12509
12509
12514
12513
12516
12513
12509
12510
12512
12510
12515
12510
12515
12514
12515
12508
12512
12508
12514
12514
...

Grouping the output values into 10 μs slots and calculating the the number of events per group yields this bar chart. There are prox 27.000 events included the chart.

12-5ms

X-axis is slot times in μs; y-axis is count of events in the slot.

The printout of the script is (shortened)

9.77396965027e-06
0.000155053138733
1.0488986969e-05
0.000154378175735
1.00150108337e-05
0.000154267787933
9.80496406555e-06
0.000156002044678
8.39877128601e-06
0.000155970096588

This demonstrates some oscillation. Values like 0.00015 and ‘something- e-05’ are repeating. The two peaks in the diagram reflect this behavior.

Summary: precise timing with loops in python is accurate only to prox 0.2 ms.

rotary encoder performance

Rotary encoders produce two waveforms, shifted by 90 degrees, which allow to decode position and direction of movements.

The two waveforms look as given in the chart. Only one direction is shown.

encoder

In raspberry pi forum, someone asked for the performance of a python program to decode these signals.

The code used to validate python program is

import RPi.GPIO as GPIO
import time

GPIO.setmode (GPIO.BCM)
GPIO.setwarnings(False)
pin_A = 22   
pin_B = 27

Encoder_Count = 0      # Encoder Count variable
   
def do_Encoder(channel):
    global Encoder_Count
    if GPIO.input(pin_B) == 1:
        Encoder_Count += 1
    else:
        Encoder_Count -= 1

GPIO.setup (pin_A, GPIO.IN, pull_up_down=GPIO.PUD_UP)         # pin input pullup
GPIO.setup (pin_B, GPIO.IN, pull_up_down=GPIO.PUD_UP)         # pin input pullup

GPIO.add_event_detect (pin_A, GPIO.FALLING, callback=do_Encoder)   # Enable interrupt

lastCount = 0
t0 = time.time()
while(1):
    t0 += 20
    time.sleep(t0 - time.time())
    print ("{e:d} diff={d:d}".format(e=Encoder_Count, d = Encoder_Count-lastCount))
    lastCount = Encoder_Count

As a driver for these signals I use an arduino DUE.

The results for the python code on a Raspberry Pi 3 are

freq       exp     measure
   10Hz    200         200
  100Hz   2000        2000
  500Hz  10000       10000  +-2
 1000Hz  20000       20000 +-25
 2000Hz  40000       40000 -40
 3000Hz  60000       60000 -660
 5000Hz 100000     -100000 +-20, but received negative values, so python too slow to get matching level

Up to 3.000 pulses, the results are quite reliable. For a 1.000RPR encoder, these are 3 rotations per second.

Usually I recommend to use an atmel328-processor as a slave processor to handle time sensitive operations. With an arduino UNO, 16MHz, the results are precise up to 15.000Hz.
There is no complete arduino needed. A bare atmel328, clocked from GPIO4, using level shifters for clock and serial line, would be a cost effective solution.
The sketch uses interrupts for the event inputs:

const byte ip2 = 2;
const byte ip3 = 3;
volatile long counter = 0;

void ip2Int() {
  byte iip2 = digitalRead(ip2);
  byte iip3 = digitalRead(ip3);
  if ( iip2 == 1 ) {
    if ( iip3 == 1 ) {
      counter --;
    }
    else
    {
      counter ++;
    }
  }
  else // ip2 == 0
  {
    if ( iip3 == 1 ) {
      counter ++;
    }
    else
    {
      counter --;
    }
  }
}

void ip3Int() {
  byte iip2 = digitalRead(ip2);
  byte iip3 = digitalRead(ip3);
  if ( iip2 == 1 ) {
    if ( iip3 == 1 ) {
      counter ++;
    }
    else
    {
      counter --;
    }
  }
  else // ip2 == 0
  {
    if ( iip3 == 1 ) {
      counter --;
    }
    else
    {
      counter ++;
    }
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("encoder");

  pinMode(ip2, INPUT);
  pinMode(ip3, INPUT);

  pinMode( 13, OUTPUT);
  pinMode(pin_sync, INPUT );
  
  attachInterrupt(digitalPinToInterrupt(ip2), ip2Int, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ip3), ip3Int, CHANGE);
}

void loop() {
  long c0 = 0;
  noInterrupts();
  c0 = counter;
  interrupts();

  Serial.println(c0);
  delay(10000);
}

This code runs up to 15.000Hz, at 20.000 Hz it fails.

An obvious optimization is to change the interrupt routine and avoid the digitalRead-function for the atmel328-processor.

void ip2Int() {
  uint8_t pd = 0b00001100 & PORTD;  // pins 2,3 are PD2, PD3
  if ( pd == 0b00001000 || pd == 0b00000100 ) {
    counter ++;
  }
  else {
    counter --;
  }
}

void ip3Int() {
  uint8_t pd = 0b00001100 & PORTD;
  if ( pd == 0b00001100 || pd == 0b00000000 ) {
    counter --;
  }
  else {
    counter ++;
  }
}

This code is much faster and update rates till 50.000Hz work perfect.

With handcrafted assembler code for the interrupt-routine I would expect to extend performance even more.

Last option investigated was an arduino feather M0 board running at 48MHz.
This produces good results up to 30.000Hz, at 40.000Hz there are failures. With the results from optimized atmel328-code, there is quite a lot of optimization expected.

For the fast running signals, timing accuracy is crucial. To work around this problem, a sync pattern was used: an additional sync signal indicated start and end of measurement from generator to measurement device. Pulse sequence was 10 sec in each case.

encoder_sync

For faster signals, either optimized assembler code needs to be used, or a hardware solution with a FPGA.

Updated 2017-02-19: optimized atmel code.

scratchClient singleton reworked

scratchClient needs to run alone, as a ‘singleton’, on one computer. The reason is that concurrent access to GPIO, SPI or other resources could result in unpredictable results.

First approach was to use a pid-file with some logic. At startup, scratchClient writes its own process identification ‘pid’ into a file scratchClient.pid. When another scratchClient is started, it looks for existing pid-file, doublechecks if a process with the recorded pid is running. In this situation, the new started process stopped.

In practice, this situation arised quite often when kids started scratchClient with wrong config file and simply closed the terminal. On a fresh start in a new terminal, the ‘old’ pid file was still existing or even the previous process was still running somewhere. These situations asked too much linux knowledge from kids and teachers and often resulted in unnecessary reboots of the computers.

A better solution is that a new start of scratchClient causes previously started processes to stop. This should work inside one computer and work independent from user permissions on the process: a new scratchClient started by ‘pi’ should be able to stop a previously started process by ‘root’.

The new singleton mechanism uses a socket to achieve this behavior. On startup of scratchClient, socket 42003 is opened as a TCPServer and listens to commands.
A new started process will get errors on opening same socket as a listener, switches to client mode and issues a shutdown command to the server. Next step is then to open TCPServer on this socket.

The video shows this effect with two terminal sessions.

In upper window, scratchClient is started. Another start in lower window causes the first process to stop.

This behavior now is default for scratchClient.

The command line allows to select the singleton mechanics:

-singletonPID        when multiple instances are running, report other instance and 
                     terminate
-singletonIPC        when multiple instances are running, terminate other instance
                     used port 42003 (default from 2017-02-14)
-singletonNONE       no singleton policy applied. For debug only

Summary: new singleton mechanism introduced in scratchClient since Feb 2017.

 

.scratch.ini

Scratch 1.4 on raspberry pi has some possibilities to tweak the behavior.
This is done with a properties file ‘.scratch.ini’ which is usually located in /home/pi.
Note the dot in front of the file name, which makes it a hidden file for linux.
You need to enable the ‘hidden file’-feature in filemanager to see these files.

fontscale=1.2
Change the default size of fonts used for all the texts.
Values are floating point numbers, good values are [0.7 .. 1.5]

remoteconnectiondialog=0
Prevents the little sensor block dialogue to tell the using that remote sensing has been tuned on from popping up, useful for many projects
Values are [0, 1]

gpioserver = 0
Disables the gpioserver, 1 enables it, 2 makes it be on by default
Values are [0, 1, 2]
Please note that with the scratch start script, the ‘pigpiod’-code is started independent from this setting. On pi A, this takes considerable cpu power with 15-20%.

presentation= 0
Will open Scratch in presentation mode; ‘1’ will open Scratch in presentation mode
Values are [0, 1]

language=en
Some language descriptor fitting the two-letter ISO 639-1 standard
For values see https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes

Values I never tested:

home = directory for home
visibledrives = a list of drive names (Windows) or root directories (Mac) to add to the file dialogues.
share = 0 or non-0. 0 means do not allow sharing of project files
proxyserver = IP for a server
proxyport = port number for the server
renderplugin = 0 or non-0. 0 will try to force not using the PAngoCairo font renderer and likely make things ugly.

Post is based on https://www.raspberrypi.org/forums/viewtopic.php?p=1031498#p1031498

 

Door closing speed analysis

The entry door in the house I live has an automatic door closer, which started to close the door faster and faster over time and slammed the door with an incredible sound. There is the possibility to to adjust closing speed with two screws on the door closer for the overall closing speed, and the speed for the final few degrees.

As tuning the system with the screws is quite difficult (a few degrees of turning the screws changes closing times by 10 secs), I added a speed recording device temporarily to the door and recorded the closing speed. And I wanted to use the wireless capabilities of the MKR100 to avoid having a lot of cables in a public area.

The door angle was measured with a simple potentiometer, uses the ADC in the  MKR1000 processor and sends the measurement values with a rate of 100 samples per second to a host computer.

door

The chart shows in blue the original closing action, in black the last two records. Horizontal axis is time. The ascending slope is decreased on the black lines, indicating lower speed. And especially the last few degrees move slower and avoid the ‘big bang’ of the door.

door2

The measurement device is temporarily clipped to the door.

door_device

The acryl rod with the small parallel vice form the anchor point for the potentiometer.

A closeup of the device shows the details

  • the MKR100 is mounted on a prototyping board.
  • Three LED display wireless connection status ‘connect to access point’, ‘access to socket’, ‘operational’.
  • The LiPo battery is on the back.
  • The adapter is 3d-printed.

door_device_2

On the host computer, a python program opens a socket and receives the data. With TKinter, the data are displayed.