Arduino serial connection speed

Did you know that the arduino can use arbitary serial speeds? I have connected my UNO to my pc and uploaded the following sketch:

void setup() {
// put your setup code here, to run once:
Serial.begin(500000);
Serial.write("hello");}

void loop() {
}

This works fine when I connect my pc to the arduino via putty and set the speed to 500,000

I wonder what the maximum speed is.
My tests showed that it is 4,000,000. This is 4 megabit/s. About 16 times the memory of an arduino UNO. I am not sure how this could be useful, but it is good to know.

Reissverschlusstäschchen (Zipper pouch)

English version: see my Instructables

So, heute mal was nicht so technisches. Ein einfaches Reissverschlusstäschchen. Alleine das Wort sieht schon so lustig aus, das muss ja toll sein. Die englischen Texte in den Bildern sind übrigens für die Anleitung auf Instructables. Alles wird im Text auch deutsch erklärt.

Aber los, was braucht ihr:

01-Needed

  • Etwas Stoff. Der Stoff sollte doppelt so breit sein wie das Täschchen nachher breit wird. Die Höhe entspricht der Tiefe des Täschchens. Natürlich sollte etwas Nahtzugabe mit dazugerechnet werden.
  • Einen Stück Endlosreissverschluss in der Länge wie das Stoffstück breit ist.
  • Einen dazu passenden Reißverschlussschieber
  • Nähausrüstung: Nähmaschine, Faden, Schere

02-Sew Zipper

 

Als erstes müsst ihr den Reissverschluss annähen. Dazu den Stoff ein wenig umschlagen und den Reißverschluss mit der Nähmaschine festnähen.

03-Split Zipper

Dann einfach den Reißverschluss teilen. Das sollte mit ein wenig ziehen einfach gehen. Das zweite Teil brauchen wir nicht mehr. Macht einfach ein zweites Täschchen daraus und verschenkt es.

04-Join Zipper

Dann wie abgebildet den Stoff falten und den Schieber aufschieben. Das geht recht einfach wenn man weiß wie. Auf Youtube gibt es da Leute die einem das genau zeigen, dann ist das kein Problem. Etwas zuziehen und auf Links drehen

06-Sew Sides2

Die Seiten zunähnen. Beim Reissverschluss anfangen. Vorsichtig Nähen damit die Nadel sich nicht verbiegt. Das erste Stück ruhig mehrfach darübernähen damit das gut hält. Dann einfach weiter. Ich habe den Rest mit der Overlock genäht (nicht das Reissverschlusstück) wie man auf dem Bild erkennen kann, aber das kann man auch mit einer normalen Nähmaschine einfach zunähnen und dann mit dem ZickZack versäubern.

Umstülpen und

07-Finished2

Fertig!

Viel Spaß damit

 

Samplerbox LCD Display

As already posted, I have created a Samplerbox. Mine has a 16×2 LCD Display instead of an LED display. To use this configuration, just connect the LCD identical as the LED display. The coding needed is a library found at github to access the lcd display:
https://github.com/dotmat/Mathew-s-Git/blob/master/BeeSafe/i2c/i2clibraries/i2c_lcd_smbus.py
Just copy the library file in the same directory as the python script. The samplerbox.py needed is as follows:

#
#  SamplerBox 
#
#  author:    Joseph Ernest (twitter: @JosephErnest, mail: contact@samplerbox.org)
#  url:       http://www.samplerbox.org/
#  license:   Creative Commons ShareAlike 3.0 (http://creativecommons.org/licenses/by-sa/3.0/)
#
#  samplerbox.py: Main file
#



#########################################
##  LOCAL  
##  CONFIG
#########################################

AUDIO_DEVICE_ID = 2                     # change this number to use another soundcard
SAMPLES_DIR = "/media/"                       # The root directory containing the sample-sets. Example: "/media/" to look for samples on a USB stick / SD card
USE_SERIALPORT_MIDI = True             # Set to True to enable MIDI IN via SerialPort (e.g. RaspberryPi's GPIO UART pins)
USE_I2C_7SEGMENTDISPLAY = True         # Set to True to use a 7-segment display via I2C 
USE_BUTTONS = True                     # Set to True to use momentary buttons (connected to RaspberryPi's GPIO pins) to change preset
MAX_POLYPHONY = 80                      # This can be set higher, but 80 is a safe value


#########################################
##  IMPORT 
##  MODULES
#########################################

import wave
import time
import numpy
import os, re
import pyaudio
import threading   
from chunk import Chunk
import struct
import rtmidi_python as rtmidi
import samplerbox_audio



#########################################
##  SLIGHT MODIFICATION OF PYTHON'S WAVE MODULE
##  TO READ CUE MARKERS & LOOP MARKERS
#########################################

class waveread(wave.Wave_read):
    def initfp(self, file):
        self._convert = None
        self._soundpos = 0
        self._cue = []
        self._loops = []
        self._ieee = False
        self._file = Chunk(file, bigendian = 0)
        if self._file.getname() != 'RIFF':
            raise Error, 'file does not start with RIFF id'
        if self._file.read(4) != 'WAVE':
            raise Error, 'not a WAVE file'
        self._fmt_chunk_read = 0
        self._data_chunk = None
        while 1:
            self._data_seek_needed = 1
            try:
                chunk = Chunk(self._file, bigendian = 0)
            except EOFError:
                break
            chunkname = chunk.getname()
            if chunkname == 'fmt ':
                self._read_fmt_chunk(chunk)
                self._fmt_chunk_read = 1
            elif chunkname == 'data':
                if not self._fmt_chunk_read:
                    raise Error, 'data chunk before fmt chunk'
                self._data_chunk = chunk
                self._nframes = chunk.chunksize // self._framesize
                self._data_seek_needed = 0
            elif chunkname == 'cue ':
                numcue = struct.unpack('<i',chunk.read(4))[0]
                for i in range(numcue): 
                  id, position, datachunkid, chunkstart, blockstart, sampleoffset = struct.unpack('<iiiiii',chunk.read(24))
                  self._cue.append(sampleoffset)
            elif chunkname == 'smpl':
                manuf, prod, sampleperiod, midiunitynote, midipitchfraction, smptefmt, smpteoffs, numsampleloops, samplerdata = struct.unpack('<iiiiiiiii',chunk.read(36))
                for i in range(numsampleloops):
                   cuepointid, type, start, end, fraction, playcount = struct.unpack('<iiiiii',chunk.read(24))                     self._loops.append([start,end])              chunk.skip()         if not self._fmt_chunk_read or not self._data_chunk:             raise Error, 'fmt chunk and/or data chunk missing'     def getmarkers(self):         return self._cue              def getloops(self):         return self._loops ######################################### ##  MIXER CLASSES ######################################### class PlayingSound:     def __init__(self, sound, note):         self.sound = sound         self.pos = 0         self.fadeoutpos = 0         self.isfadeout = False         self.note = note     def fadeout(self, i):         self.isfadeout = True              def stop(self):         try: playingsounds.remove(self)          except: pass class Sound:     def __init__(self, filename, midinote, velocity):         wf = waveread(filename)         self.fname = filename         self.midinote = midinote         self.velocity = velocity         if wf.getloops():              self.loop = wf.getloops()[0][0]             self.nframes = wf.getloops()[0][1] + 2         else:             self.loop = -1             self.nframes = wf.getnframes()         self.data = self.frames2array(wf.readframes(self.nframes), wf.getsampwidth(), wf.getnchannels())         wf.close()                 def play(self, note):         snd = PlayingSound(self, note)         playingsounds.append(snd)         return snd     def frames2array(self, data, sampwidth, numchan):         if sampwidth == 2:             npdata = numpy.fromstring(data, dtype = numpy.int16)         elif sampwidth == 3:             npdata = samplerbox_audio.binary24_to_int16(data, len(data)/3)         if numchan == 1:              npdata = numpy.repeat(npdata, 2)         return npdata FADEOUTLENGTH = 30000 FADEOUT = numpy.linspace(1., 0., FADEOUTLENGTH)            # by default, float64 FADEOUT = numpy.power(FADEOUT, 6) FADEOUT = numpy.append(FADEOUT, numpy.zeros(FADEOUTLENGTH, numpy.float32)).astype(numpy.float32) SPEED = numpy.power(2, numpy.arange(0.0, 84.0)/12).astype(numpy.float32) samples = {} playingnotes = {} sustainplayingnotes = [] sustain = False playingsounds = [] globalvolume = 10 ** (-12.0/20)    #  -12dB default global volume ######################################### ##  AUDIO AND MIDI CALLBACKS ######################################### def AudioCallback(in_data, frame_count, time_info, status):     global playingsounds     rmlist = []     playingsounds = playingsounds[-MAX_POLYPHONY:]         b = samplerbox_audio.mixaudiobuffers(playingsounds, rmlist, frame_count, FADEOUT, FADEOUTLENGTH, SPEED)     for e in rmlist:         try: playingsounds.remove(e)         except: pass     b *= globalvolume     odata = (b.astype(numpy.int16)).tostring()        return (odata, pyaudio.paContinue) def MidiCallback(message, time_stamp):     global playingnotes, sustain, sustainplayingnotes     global preset     messagetype = message[0] >> 4
    messagechannel = (message[0] & 15) + 1
    note = message[1] if len(message) > 1 else None
    midinote = note
    velocity = message[2] if len(message) > 2 else None

    if messagetype == 9 and velocity == 0: messagetype = 8

    if messagetype == 9:    # Note on
        try:
          playingnotes.setdefault(midinote,[]).append(samples[midinote, velocity].play(note))
        except:
          pass

    elif messagetype == 8:  # Note off
        if midinote in playingnotes:
            for n in playingnotes[midinote]: 
                if sustain:
                    sustainplayingnotes.append(n)
                else:
                    n.fadeout(50)
            playingnotes[midinote] = []

    elif messagetype == 12: # Program change
        print 'Program change ' + str(note)
        preset = note
        LoadSamples()

    elif (messagetype == 11) and (note == 64) and (velocity < 64): # sustain pedal off         for n in sustainplayingnotes:             n.fadeout(50)         sustainplayingnotes = []                sustain = False     elif (messagetype == 11) and (note == 64) and (velocity >= 64): # sustain pedal on
        sustain = True



#########################################
##  LOAD SAMPLES
#########################################

LoadingThread = None            
LoadingInterrupt = False

def LoadSamples():
    global LoadingThread
    global LoadingInterrupt

    if LoadingThread:
        LoadingInterrupt = True
        LoadingThread.join()
        LoadingThread = None
    
    LoadingInterrupt = False
    LoadingThread = threading.Thread(target = ActuallyLoad)
    LoadingThread.daemon = True
    LoadingThread.start()

NOTES = ["c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b"]

def ActuallyLoad():    
    global preset
    global samples
    global playingsounds
    global globalvolume
    playingsounds = []
    samples = {}    
    dirname = next((f for f in os.listdir(SAMPLES_DIR) if f.startswith("%d " % preset)), None)      # or next(glob.iglob("blah*"), None)
    globalvolume = 10 ** (-12.0/20)    #  -12dB default global volume
    if dirname:
        samplename = dirname
        dirname = os.path.join(SAMPLES_DIR, dirname)
    if not dirname: 
        print 'Preset empty: %s' % preset
        display("%03d Empty" % preset,'                ')
        return
    print 'Preset loading: %s' % preset
    display("%03d Loading..." % preset,samplename)
    definitionfname = os.path.join(dirname, "%d.txt" % preset)                     # parse the sample-set definition file
    if not os.path.isfile(definitionfname): 
        definitionfname = os.path.join(dirname, "definition.txt")
    if os.path.isfile(definitionfname):
        with open(definitionfname, 'r') as definitionfile:
            for i, pattern in enumerate(definitionfile):
                try:
                    if r'%%volume' in pattern:        # %%paramaters are global parameters
                        globalvolume *= 10 ** (float(pattern.split('=')[1].strip()) / 20)
                        continue
                    defaultparams = { 'midinote': '0', 'velocity': '127', 'notename': '' }
                    if len(pattern.split(',')) > 1:
                        defaultparams.update(dict([item.split('=') for item in pattern.split(',', 1)[1].replace(' ','').replace('%', '').split(',')]))
                    pattern = pattern.split(',')[0]
                    pattern = pattern.replace("%midinote", r"(?P\d+)").replace("%velocity", r"(?P\d+)").replace("%notename", r"(?P[A-Ga-g]#?[0-9])").replace("*", r".*").strip()
                    for fname in os.listdir(dirname):
                        if LoadingInterrupt: 
                            return
                        m = re.match(pattern, fname)
                        if m:
                            info = m.groupdict()
                            midinote = int(info.get('midinote', defaultparams['midinote']))
                            velocity = int(info.get('velocity', defaultparams['velocity']))
                            notename = info.get('notename', defaultparams['notename'])
                            if notename: midinote = NOTES.index(notename[:-1].lower()) + (int(notename[-1])+2) * 12
                            samples[midinote, velocity] = Sound(os.path.join(dirname, fname), midinote, velocity)
                except:
                    print "Error in definition file, skipping line %s." % (i+1)

    else:
        for midinote in range(0, 127): 
            if LoadingInterrupt: 
                return
            file = os.path.join(dirname, "%d.wav" % midinote)
            if os.path.isfile(file):
                samples[midinote, 127] = Sound(file, midinote, 127)             

    initial_keys = set(samples.keys())
    for midinote in xrange(128):
        lastvelocity = None
        for velocity in xrange(128):
            if (midinote, velocity) not in initial_keys:
                samples[midinote, velocity] = lastvelocity
            else: 
                if not lastvelocity: 
                    for v in xrange(velocity): samples[midinote, v] = samples[midinote, velocity]
                lastvelocity = samples[midinote, velocity]
        if not lastvelocity: 
            for velocity in xrange(128): 
                try: samples[midinote, velocity] = samples[midinote-1, velocity]
                except: pass
    if len(initial_keys) > 0:
      print 'Preset loaded: ' + str(preset) 
      display("%03d" % preset,samplename)    
    else:
      print 'Preset empty: ' + str(preset) 
      display("E%03d Empty" % preset,'')    



#########################################
##  OPEN AUDIO DEVICE
#########################################

p = pyaudio.PyAudio()
stream = p.open(format = pyaudio.paInt16, channels = 2, rate = 44100, frames_per_buffer = 512, output = True, input = False, output_device_index = AUDIO_DEVICE_ID, stream_callback = AudioCallback)
print 'Opened audio: '+ p.get_device_info_by_index(AUDIO_DEVICE_ID)['name']



#########################################
##  BUTTONS THREAD (RASPBERRY PI GPIO) 
#########################################

if USE_BUTTONS:
    import RPi.GPIO as GPIO

    lastbuttontime = 0

    def Buttons():
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)    
        global preset, lastbuttontime
        while True:
          now = time.time()
          if not GPIO.input(18) and (now - lastbuttontime) > 0.2:
            lastbuttontime = now 
            preset -= 1
            if preset < 0: preset = 127             LoadSamples()           elif not GPIO.input(17)  and (now - lastbuttontime) > 0.2:
            lastbuttontime = now
            preset += 1  
            if preset > 127: preset = 0
            LoadSamples()      

          time.sleep(0.02)

    ButtonsThread = threading.Thread(target = Buttons)
    ButtonsThread.daemon = True
    ButtonsThread.start()    



#########################################
##  7-SEGMENT DISPLAY 
##  
#########################################

if USE_I2C_7SEGMENTDISPLAY:
    import i2c_lcd_smbus
    lcd = i2c_lcd_smbus.i2c_lcd(0x27,1, 2, 1, 0, 4, 5, 6, 7, 3)
    lcd.command(lcd.CMD_Display_Control | lcd.OPT_Enable_Display)
    lcd.backLightOn()

    def display(s,t):
        lcd.setPosition(1,0)
        lcd.writeString(s+"                ")
        lcd.setPosition(2, 0)
	lcd.writeString(t+"                ")
    display('Starting','Samplerbox')
    time.sleep(0.5)

else:

    def display(s):
        pass    



#########################################
##  MIDI IN via SERIAL PORT
##  
#########################################

if USE_SERIALPORT_MIDI:
    import serial

    ser = serial.Serial('/dev/ttyAMA0', baudrate=38400)       # see hack in /boot/cmline.txt : 38400 is 31250 baud for MIDI!

    def MidiSerialCallback():
        message = [0, 0, 0]
        while True:
          i = 0
          while i < 3:             data = ord(ser.read(1)) # read a byte             if data >> 7 != 0:  
              i = 0      # status byte!   this is the beginning of a midi message: http://www.midi.org/techspecs/midimessages.php
            message[i] = data
            i += 1
            if i == 2 and message[0] >> 4 == 12:  # program change: don't wait for a third byte: it has only 2 bytes
              message[2] = 0
              i = 3
          MidiCallback(message, None)

    MidiThread = threading.Thread(target = MidiSerialCallback)
    MidiThread.daemon = True
    MidiThread.start()



#########################################
##  LOAD FIRST SOUNDBANK
##  
#########################################     

preset = 0
LoadSamples()



#########################################
##  MIDI DEVICES DETECTION
##  MAIN LOOP
#########################################

midi_in = [rtmidi.MidiIn()]
previous = []
while True:
    for port in midi_in[0].ports:
        if port not in previous and 'Midi Through' not in port:
            midi_in.append(rtmidi.MidiIn())
            midi_in[-1].callback = MidiCallback        
            midi_in[-1].open_port(port)       
            print 'Opened MIDI: '+ port
    previous = midi_in[0].ports
    time.sleep(2)

My Samplerbox

Samplerbox_topI created my own samplerbox. This is a box which recieves midi data and creates an audio output. So basically it is a sampler. See the web presence for details:

Samplerbox

I did some modifications to use a 16×2 lcd display instead of an 4 char led display. I thought it would fit better for my needs since it can display the name of the selected intrument quite nicely. Unfortunately I changed the source and didn’t make a copy before closing the casing. I will do this later.

Setting up the thing was quite easy. A little bit more complicated is it to put everything into a nice case. Mine is made of wood. I put the Raspberry PI usb connectors to the outside to connect the usb midi and the required memory stick.

Samplerbox_connectors

To the right is the audio out and below the usb connectors is the micro usb power connector.

English or German (Deutsch oder Englisch)

Obwohl das eine deutsche Webseite ist und ich aus Deutschland komme werde ich ab sofort englische Beiträge schreiben, aber vielleicht auch mal den einen oder anderen deutschen Beitrag schreiben wenn es besser passt.

Although this is a german webpage and I am from germany I am not sure if I should write in german or english. Therefore I will start doing posts in english, but may also write some in german if it fits better.

Serielle Datenübertragung mit Arduino über Infrarot

 

Heute geht es um Infrarote Datenübertragung.

Eigentlich war sinn des Projektes einen Infrarotsender im Haus zu empfangen, aber dazu schreibe ich in einem anderen Beitrag mal was. Hier also eher eine einfache Übertragung  über die serielle Schnittstelle mit Hilfe von Infrarotlicht.

Boards

Sender

Aufgebaut habe ich einen Sender mit Hilfe eines Arduino Uno. Der macht nichts anderes als alle 2 Sekunden 480 Byte über die serielle Schnittstelle auszugeben. Das Coding dazu ist geradezu trivial:

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
}

void loop()
{
  for(int i = 0; i < 40;i++){
    Serial.write("Hallo Test--");
    }
    delay(2000);
}

Die Elektronik dazu verstärkt das Signal und leitet es an die Infrarot LED CQY 99 weiter. Die LED benötigt bis zu ca. 150mA Strom. Bei 5V braucht man einen 24Ohm Vorwiderstand mit 540mW. Da ich nicht soviel Leistung brauche, habe ich 2x100Ohm parallel geschaltet und komme so auf 75mA und 280mW. Das ist zwar etwas mehr Leistung als die Widerstände vertragen, aber im Pulsbetrieb sollte das kein Problem sein. Mit Hilfe einer Digitalkamera kann man sehen wie die LED alle 2 Sekunden kurz aufleuchtet. Mit bloßem Auge kann man das Infrarotlicht nicht sehen.

IrLed

Besonderst hell sieht das nicht aus, aber eigentlich kann man es ja gar nicht sehen, also ist das schon ein Fortschritt.

Schaltplan

Schaltplan

Die Transistoren verstärken das Signal und da es sich um eine Emitterschaltung handelt wird es auch invertiert. Das soll beim senden vermieden werden, daher eine doppelte Emitterschaltung, ist aber beim Empfangen erwünscht, da das serielle Signal eine invertierte Signalform hat.

Empfänger

Der Empfänger ist ein Arduino Mega. Dort ist ein Fototransistor SFH 300 FA-3/4 der die Infrarotsignale empfängt. Diode und Transistor sind für 950nm Wellenlänge ausgelegt, passen also zusammen. Die Empfangsschaltung ist ein einfacher Transistorverstärker. Ich nehme da den BC337, ein universeller NPN Transistor. Da der Arduino Mega 4 serielle Schnittstellen hat, kann man ganz einfach die empfangenen Daten an den über USB gekoppelten Computer ausgeben.

byte inByte = 0;

void setup()
{
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop()
{
  if (Serial1.available() > 0) {
    // get incoming byte:
    inByte = Serial1.read();
    Serial.print(inByte);
  }
}

Und nach einigen Experimenten funktioniert die Übertragung bei 9600 bps über eine Strecke von 5-20 cm je nach störendem Lichteinfall. Viel ist das nicht, aber doch ganz nett zu sehen dass es zumindest eine kurze Distanz überbrücken kann.

Demnächst mehr Details zu den übertragenen Daten.