Final Project - TIKTOK

Final Project

TIKTOK project


Adobe Illustrator, for 2D modeling, armband design
Fusion360, for 3D modelling, body and cover design
Ultimaker Cura, for printing body
Prusa slicer, for printing cover
Laser Cutter 5.3 - the software to format illustrator file to laser cutter code
For prototypes:
KiCad, open source electronics design tool suite.
Mods, control software for the Roland mill
PartWorks 3D (software for translating mold design to G-code for the Shopbot)
Shopbot controll software (for sending the G-code to the Shopbot)
Arduino IDE (Simple IDE to program especially Arduino based microcontrollers)
AVRDude (the AVR programming application used and integrated in the Arduino IDE)
Android Studio, for writing the Android app


Prusa i3 MK3S MMU2S, for cover 3D print
Ultimaker 2+, for body 3D print
Laser cutter, for leather arm band
Protomat S62, mill for PCB
Multimeter, for checking traces
Knife, for cutting wires
Anti static tweezers, for electrical components
Solder iron, for soldering components
Solder tin, for SMD components soldering
Various surface mounted components (see BOM and PCB design files)
A regulated digital controlled DC power supply, to test initial power usage
Macbook Pro 15 inch, 2015 edition, for programming board and Android app
ISP programmer, USBtiny, made in week 05
A USB to TTL controller. (also know as a FTDI controller)
Motorola Moto G 2nd edition, for Android application
Micro usb cable, for uploading code to Android application

For prototypes:
Shopbot, for milling mold
Wax, for first mold
Smooth cast, for final cast
PCM, for flexible mold cast
Roland Modella MDX-20 mill , for milling prototypes
with the mill bit for traces - mini end mills two flutes 0.40 mm 826 (
with the mill bit for cutout - two flutes 0.8 mm


(c) Joey van der Bie, Amsterdam University of Applied Sciences, 2019-06-18

This work may be reproduced, modified, distributed, performed, and displayed for any purpose, but must acknowledge “Joey van der Bie, Amsterdam University of Applied Sciences project TIKTOK”. Copyright is retained and must be preserved. The work is provided as is; no warranty is provided, and users accept all liability.


TIKTOK micocontroller code (Arduino) with accelerometer, vibration and BLE
TIKTOK Android application
Illustrator arm band design
Laser arm band instruction code
Smart watch case and cover Fusion360
Ultimaker file watch case
Gcode Ultimaker watch case
Cover stl
Cover Gcode Prusa


Qty Description Price per unit* Price Link          
1 ” GREEN LED1206 1206 LED_GREENL, 160-1169-1-ND “ $0,15 $0,15 Fablab        
1 ” BLUE LED1206 1206 LED_1, 160-1889-1-ND “ $13,00 $13,00 Fablab        
2 ” 0,1uF CAP1206 1206 C7, C8 Capacitor 399-4674-1-ND “ $0,12 $0,24 Fablab        
1 ” 100nF CAP1206 1206 C5 Capacitor 311-1174-1-ND “ $0,04 $0,04 Fablab        
2 ” 10uF CAP1206 1206 C1, C3 Capacitor 587-1352-1-ND “ $0,18 $0,36 Fablab        
1 ” 1uF CAP1206 1206 C4 Capacitor 445-1423-1-ND “ $0,07 $0,07 Fablab        
5 10k RESISTOR1206 1206 R1,R3,R4,R7,R8 311-10,0KFRCT-ND $0,01 $0,05,0KFRCT-ND Fablab        
1 1k RESISTOR1206 1206 R5 Resistor 311-1.00KFRCT-ND $0,01 $0,01 Fablab        
1 330 RESISTOR1206 1206 R6 Resistor $0,10 0,1 Fablab        
1 ” 499 RESISTOR1206 1206 R2 Resistor, 311-499FRCT-ND “ $0,01 $0,01 Fablab        
1 ATMEGA328P-AU ATMEGA48/88/168-AU TQFP32-08 MICRO $2,87 $2,87 Fablab        
1 3.3 V converter NDS356AP-D PMOSFETSOT23 SOT-23 T1 MOS FET $0,34 $0,34 Fablab        
1 ” REGULATOR_SOT223 REGULATOR_SOT223 SOT223 U3, ZLDO1117G33DICT-ND “ $0,34 $0,34 Fablab        
0 ” RESONATOR RESONATOR EFOBM RESONATOR, 535-10004-1-ND “ $0,25 $0,00 Fablab        
1 Microchip RN4871-V/RM118 SMD-16 Microchip $7,24 $7,24 Fablab        
1 ” Schottkey 100V 1A DIODESOD123 SOD123 D1 DIODE, 641-1331-1-ND “ $0,19 $0,19 Fablab        
1 Serial debug PINHD-1X5 1X05 PADS_2 PIN HEADER $0,25 $0,25 Fablab        
1 battery PINHD-1X2 1X02 JP3 PIN HEADER $0,11 $0,11 Fablab        
1 on/off switch PINHD-1X2 1X02 JP4 PIN HEADER $0,11 $0,11 Fablab        
1 vibration motor connector PINHD-1X2 1X02 JP1 PIN HEADER $0,11 $0,11 Fablab        
1 Accelerometer header FE08-1 FE08 SV1 FEMALE HEADER $0,37 $0,37 Fablab        
1 BLE_DEBUG PINHD-1X5 1X05 JP2 PIN HEADER $0,25 $0,25 Fablab        
1 M01PTH M01PTH 1X01 MOUNT $0,10 0,1 Fablab        
1 M09LONGPADS M09LONGPADS 1X09_LONGPADS PADS_1 Header 9 $0,56 $0,56 Fablab        
1 Vibration Motor $2,95 2,95 Me        
1 Double sided copper plate, 1,6 x 1,6 inch, 0,06 inch thick $1,32 $1,32 Me        
1 Accelerometer: MPU6050 board $1,56 $1,56 Me        
1 Battery $3,49 $3,49 Me        
1 Battery charging module $0,99 $0,99 Fablab        
1 3D fillament 1 meter, 8g, ultimaker white $0,33 $0,33 Fablab        
1 3D fillament, lipstick red for prusa, 1 meter, 8g $0,25 $0,25 Fablab        
1 Piece of leather $2,23 $2,23 no link available Me        
  Total price   $39,99            
  • prices are from Fabacademy partlist if provided, otherwise via link or direct purchase price.

A haptic smart band for people with a visually impairment.

Personal Internet of things devices are becoming more common (e.g. smarthome, health, sports). The accessibility of these devices is often low, user groups as visually impaired are not supported or even considered when the hardware and software is designed and implemented. While Apple devices do support accessibility via Voice-over this is not always implemented in the apps. Still when implemented it results in the VI having to rely on the text-to-speech interface. The TTS/voice interface demands the full attention of the VI when using the device, making it very difficult to interact with other people while interaction with the device. This demand on voice interfaces can be greatly reduces by implemented haptic based input and output. Unfortunately Apple Watches do not allow for advanced haptic feedback. We created a smart wearable optimised for delivering haptic in- and output that can be utilised for VI. By starting with presenting notifications via vibrations and input via tap patterns, we believe we can create a small, affordable and flexible wearable that is easy to use. We now present the platform that can recognise taps, vibrates and can send these events from and to the smartphone. It can be further extended and integrated for specific use cases. For example, with a specific vibration pattern the current time can be communicated via vibrations, or an indication can be given if the lights in the home are on or off.


  • Comfortable wearable form factor
  • Recognise tap gestures via accelerometer
  • Vibrations as output and feedback
  • Bluetooth connected to phone (Android application)
  • LED indicators for debugging
  • Headers for debugging
  • Uses (rechargeable) battery
  • Extendable Android Smartphone application to send vibrations and receive taps

Initial sketches of accessible smartwatch concept

topview of accessible smartwatch concept sideview of accessible smartwatch concept decomposed view with components of accessible smartwatch concept


From the start of the Fabacademy course I knew I wanted to create a watch body.
In Week 1: Concept I sketched the look and feel, in week 3: Computer Aided Design when experimenting with Fusion360 I created the basic design. I further refined my design in week 10: Molding and Casting and casted my first casing. It was not perfect, I made many errors along the way, and I find the molding and casting process to be time consuming and having many potential fail moments.

Milling wax mold

Finished PCM cast/mold from wax mold

Frankenstein mold with casting material all over the mold

My almost fully succesfull cast of my watch body

To reduce the posibility of error, save time and try out something different I wanted to also try 3D printing the design. Also with 3D printing I could add even more design feature that were not possible with the mold.

3D print body with Ultimaker 2+

For my final body design I opened my molding design and changed the width parameter to fit my new board size.
Fusion360 automatically updated the size of my bodies to the new parameters.
Bigger body design

I added a mount for the on/off switch.
The datasheet provided the dimension, that I copied to my parameters in Fusion360.

switch dimension New parameters in Fusion360 for body design and switch

I started on adjusting my button/switch holder, I extracted the rectangle from my sketch, than wanted to make a hollow form out of my new cube.
Then something happened: TRIAGE!
I had reached the time to start my 3D print. It was Friday and around 1400. If I really wanted to print a case that day, I had to finish my design in a few minutes. I had to drop my holder for the switch, and just print the design I created earlier.

The watchbody design with the unfinished switch rectangle

After this painfull decision, and opened my manual on how to 3D print from week 6: 3D Scanning and Printing.
I took the Ultimaker 2+, exported my design from Fusion to Cura, and copied my specifications from my previous description. With an infill of 20% it will the Ultimaker take about 1,5 hours, not bad.
I added a build plate and supports. The build to prevent the print from moving, and the supports for my small cutout I made at the bottom for the armband.

The desing in Cura

I switched filament from black to white and performed a first test print of a small servo arm of our group machine to make sure there was no more black in the nozle, and I had the device properly calibrated.
After the servo arm was finished I loaded my case design.
After 1,5 hours it was finished. And the result looked nice, besides that one of the arm band mounts was 2 mm off!
I checked my design, and just before exporting I accidentally moved the mount with my mouse!
I fixed my mistake, reexported to cura and exported to the Ultimaker.
This time printing went succesfull.
One thing that still went wrong was that the support was fused to my small cutout for the armband.
I accepted this fail, since the other parts of the body were perfect, and you wont see this mistake when wearing the watch.
Mount arm failure Me moving the mount to its proper position support stuck to the cutout Hero shot of my case with band

3D print cover with prusa

After having a working body, I found an extra hour to design a cover for my body.
Although I tried to keep it simple it became complex fast.
First I started by extracting the circle of my watchsketch, and them adding about 0.1 mm to make sure my cover would be a little bit larger than the body. I noticed my electronics was allready sticking out of the watch case, so I made my top 7mm high to make sure all the electronics would fit.
Next I made a shell of my cilinder, but keeping the top solid.
To make sure the whole cilinder would not slide over my watch case, I had to ad some form of legs inside my cover to stop at the edge of my watch case.
I decided to extract another cilinder from my watch circle from the sketch, but only making it 1 mm high and then making a shell out of it off about 1 mm width. So I ended up with a small ring that would fit exactly on top of my watch cover.
I combined the ring and cover on about a 1 mm height, giving me the stop at the edge of my watch inside my cover.
New cover made transparant to show the ring inside For esthetics reasons I extracted the TIKTOK markings . and , from the sketch and combined them with the cover by extracting them from a fraction of a mm of the top of the cover.
Last I extracted also two small cilinders of 1 mm each right above where my LEDs of my microcontroller board are.
Maybe I can connect some form of light guidance to this in the future, for example with glass fiber. But that will be after the Fabacademy course due to time constraints.
I exported the cover to an STL, and imported it in a new piece of software Prusa Slicer
Due to the Ultimaker not being available I had to switch to the Prusa i3 MK3S MMU2S.
This is the improved prusa MK3S, having a module that allowes to print with different filament at the same time!
I am not using different filament, I just want to quickly print this cover with one color.
But the new module does mean I have to use Prusa Slicer instead of Cura.
If provides pretty much the same settings options as Cura, only with the addition of the extra filament.
Also it has a beginner mode, making it easy for me to use.
I used the following settings:

  • filament: Prusament PLA (red)
  • printer: Prusa i3 MK3S MMU2S Single
  • supports: supports on build plate only
  • brim: yes
  • infill 15%

The cover STL in prusa slicer

I cleaned the board, loaded the filament in the first hole of the new module (the Prusa auto graps the filament, when you load in the hole), and started the print.
As with the Ultimaker the first print failed, now the brim was wrapping upwards.
I cancelled the job and started a new one again.

printing in progress

Now everything went fine and after an hour I had a big red cover, and trying to fit it on the watch case made a beautifull snapping sound!

New red cover fitting on the case

Creating a leather arm band

After discussing with Micky, I really wanted to create my own leather arm band for my TIKTOK watch.
I experimented with two small pieces of leather (thank you Micky) to create the TIKTOK arm band strap.

In Adobe Illustrator I designed the armband.
Looking at similar bands, I decided my dimensions.


  • lenght: 420 mm
  • width: 22 mm
  • holes length: 120 mm
  • holes diameter/width: 2.2 mm

I created a rectangle of 420 by 22 mm, and modified the top corner with the Direct Selection tool (white pointer) to give it a round finish.

Modified corner with Direct Selection Tool

Next I drew some circles at one side for the holes for the pin of the arm band.
And I created a small rectangle at the other side of the rectangle for the position of the pin.
Last I though it would be nice to decorate the band with engravings of the TIKTOK logo, so I places a few logo’s on it.
Note that when you want to laser cut text, you should first make vectors out of the text.
This also saves you hasle with transfering the design to another computer that does not have the font you use.
You can create a vector out of you text by right clicking your text and selecting the option, create outlines.

Creating the outlines of the text, when saving this will be a vector like all other shapes

Next to the band, I created two small test designs, as you can also see in the picture.
I saved the Illustrator file as .ai and .dxf and copied them to the laser computer. I took my laser manual I made in week 4 and started the laser software, and imported my design.

Testing on leather with a test design

I selected the test cut piece and gave each item a color, and assigned to each color different settings.
Since I had not cut with leather before, I did not know the correct laser speed and power combination.
I had 5 circles, and for each one I selected a different cutting setting. For example I started with:

  1. speed: 500, power: 10
  2. speed: 400, power: 10
  3. speed: 300, power: 10
  4. speed: 200, power: 10
  5. speed: 100, power: 10

I worked my way up to a higher power, and ended up selecting the cutting for speed: 300 and power 30.
Next I tried engraving with the same systematic approach, using the circles as a start.
After finding a nice engraved circle I tried to engrave the TIKTOK logo on the test piece.
I ended up selecting for the engraving:

  • speed: 100, power: 20 Higher powers looked to burned for my tast, and higher speeds actually spoiled some engraving outside the desired area.
    Last I tried the cutout settings around my engraving to cutout the test piece.
    I found that my previous selected power and speed combination did cut through the material, but left some thin lines of fabric connected, giving a rough uneven look when releasing the piece from the leather.
    After some trying with larger speeds, I concluded I had to use:
  • speed: 80, power: 50
    I think this big difference between a larger square and a small circle has to do with the laser slowing down when reachting a corner, and needing a certain lenght to get up to speed. The circle was simply to small for the laser to actually reach the speed 300, but with the bigger square I was able to reach this speed.

Result with correct settings after 1,5 hours of testing small pieces

After finding the correct settings, which took me 1,5 hours I had to try on my actual design.
And… Succes! While I only needed one, I made 3 pieces to have some spares.

Loading the file in the laser

First armband cut in the laser on leather

The 3 arm bands displayed with my 3D printed casing

Time management.

I find this task a really nice example of my planning and triage, I had to keep my design simple to finish in time and almost finished exactly at the desired time. The leather band is a nice addition, but should take me to much time. Therefor I allowed me to take 5 hours to make the band.

  • 2 hours design
  • 2 hours cutting
  • 1 hour finishing Also I would save this activity for the final days, since, if I could not find the time, I would make a sticker on the vynil cutter.

Thirsday I had to make my band on the laser cutter.
From 13:00 the device was reserved, so I had to finish it before that time.
I decided to take the time from 9.30 till 11.00 to design the band and test cuts in Illustrator,
and cut from 11:00 till 13:00 different band versions. I finished my cut at 13.15.


Board design

The board for my smarband builds on the knowledge I gained in the past weeks.
In week 5 I learned how to mill a board.
In week 7 , week 11 and week 12, I learned how to design a board with input and output devices.
Further in these weeks I evolved my design towards my smart band board design. With each new board I added functionality I needed for my final project.

Ground poor on first ever designed board

Full schematic of 3.3V board in KiCad

Evolution of boards: 1. round design, mounting holes and ground poor, 2.  3.3V, accelerometer and I2C, 3. vibration motor and through hole components

In week 14 I further explored the capabilities of my board by adding a Bluetooth module over Serial.

Bluetooth board connected to my ATTiny

For my final board design I want to create a round board with a onboard Bluetooth module,
and expansion headers for an I2C accelerometer and serial communication.
Further I want it to have an on/off button, indicator LEDs, and the possibility for adding a battery module.
I want to make the board as small as possible.
I want to try to use both sides of the board as much as possible.
To get animpression of how the board will look I stacked all my modules on top of eachother

composition of all the components

My first sketch I made in week 1 still resembles these requirements.

decomposed view with components of accessible smartwatch concept

Now understanding better what components I am able to use, I could make my new board.


Having decided I want to make a double sided board, I also want to try out a new design tool.
I installed Autodesk EAGLE and downloaded the FabAcademy components library. You can import the files by copying them to “$HOME/Documents/EAGLE/libraries”.

Fabfiles in the libraries folder

Next, use the “File->New” menu to start a new project and create a new schematic.

New project, schematic, ect.

I started by downloading the Satshakit schematics.
The Satshakit is an Arduino Uno compatible board design, based on the Atmel Atmega 328p.

Defining components, connecting components, linking wires, all goes pretty much the same as in KiCad. The biggest difference is that in KiCad the options are on the right, in EAGLE on the left.

Schematic of the TIKTOK board

For some advice on how to use EAGLE, I searched around on the Fabacademy website and got some usefull tips from Jimena Galvesparedes. I modified the Satshakit by making it a 3.3V board, adding the RN4871 Bleutooth chip and the vibration motor circuit.

Double sided TIKTOK board design with its many features

Bluetooth board RN4871

The Bluetooth board I will be using for my new board is the Microchip RN4871. It is a very tiny BLE 4.2 board, that allows me to further shrink my design.
The datasheet can be found here.

On the website of Martyn Currey we find a nice hands-on with the board, plus he explains how to update the firmware of the board.

Although the board is part of the FabAcademy inventory, its schematic and footprint are not part of the design files.
They can be found for both KiCad as EAGLE on

Next up is connecting the board.
I connected the wires as specified in the datasheet.

Battery management

For connecting and charging the battery with my module I encountered some difficulties.
I received a battery charging module from Henk, but that does not provide an output to connect to your board.
Also I found that the charging module provided up to 4,7V, while this is to low for my voltage converter to 3.3V.
It really was a bummer that I could not use this board for my design and I had to drop onboard battery managment.


During development, I discovered I used the wrong 3.3V converter.
The one I use only supports up to 100mA, while my board will use more due to the combination of the components and the vibration motor.
I switched the LM3480IM3-3.3/NOPBCT-ND for the ZLDO1117G33DICT-ND, that will support up to 1A.
Its datasheet can be found here The biggest difference between the two components is the footprint: SOT223 instead of SOT23.
Next I noticed I did not included a capacitor from the raw voltage to the GND, thus I also included that.

MOSFET wrongly connected

Despite my efforts in week 12, I still connected my MOSFET wrong in my new board.
This resulted in a short circuit, the device kept drawing 2.5V and 1A, instead of 5V and about 0.06A.

Milling the board

I milled my board on the Protomat S62, a PCB mill we have a the Amsterdam University of Applied Sciences Makerlab.
Since I had not used the device before, I decided to first explore its capabilities by making a test cut.
While doing this I learned how the device worked, and directly explained two of my students how the device works. Honestly, most of the thinking was done for me, Fabacademy student and college Loes Bogers explored how to use the device and wrote a manual explaining all the steps. Thank you again Loes!

Protomat milling Milled PCB of TIKTOK Soldering the board Finished product with all the components

Burning the bootloader - Chip not responding

When trying to upload the bootlader, as I had specified in my week 9 , I received an error.

avrdude: Device signature = 0x000000 (retrying)

Error while burning bootloader.
Reading | ################################################## | 100% 0.00s

This should be ATMEGA328P: 0x1E950F not 0x000000

I analyzed my traces and solder points.
Together with Henk I found 2 solder points that were connected to a copper area. This should not result in a short circuit, but still, unwanted.
Next I found that I had my MOSFET orientation wrong in the schematic.

Last I found that I had my pins reversed. In stead of having the SCK, MISO and MOSI on the left of my headers, they were on the right!
To prevent myself from making these errors, I quickly made a layout of pins on paper. I ended up using this piece of paper multiple times over the course of several days.

Layout specification on paper

Afer rechecking with AVRDUDE, I could confirm that my chip was detected.
I burned the bootloader via the Arduino IDE. After burning the bootloader, I tried to upload a Sketch via the FTDI controller. This resulted in upload errors and AVRDUDE telling me the device is out of sync.

To test if the Serial interface could be used at al, I uploaded my SerialTest sketch from week 12 via de SPI interface by selecting the upload via programmer option in Arduino. Upload via Programmer

FTDI connected to TIKTOK

Now when testing the serial, everything worked, and I knew I had a working chip that I could program va SPI and debug over Serial.

Microcontroller code


In week 9 I explored how to use input devices as buttons and light sensors, in week 12 I explored how to use output devices as the vibration motor.
I designed a board with a vibration motor circuit. It is based on the “Learn about Electronics” circuit and translated to my needs and Fabacademy available components. In searching for the components, I stumbled on the FabAcademy website of Silvia Pallazi, she had the exact scheme used from the “Learn about electronics website” and converted the components to the FabAcademy part list. I could not be more lucky!
After checking Silvia’s work I decided to use a MOSFET that could handle more Amps. I did made a mistake in my schematic design, I did not realize I had a PNP type MOSFET and not a NPN type and therefor missing a pull-up resistor, als I connected the wrong legs. In my new board I used the same circuit and somehow made the exact same mistakes! I did made 1 important new addition to my design, that is to not drill holes to solder the vibration motor on, but to use headers for the vibration motor. This allows me to quickly switch between motors when I break one. These things tend to break fast.

Schematic for the vibrator Vibration motor on the back of the board MOSFET rotated with small wire for Gate

Vibration patterns

I tried several different vibration patterns in a test sketch -> Code for vibration pattern tests From these test I determined optimal delay between patterns is 100ms when the pin is high (255) at analogWrite (maximum PWM).
Longer than 100ms makes the vibration feel very strong, between 200 and 300ms feels like the duration of smartphone patterns.
The lowest possible PWM strenght is analogWrite(50), but I would recommend 60 or 70.
When creating a fade-in or fade-out steps should not be bigger than 10, and thus start at 50.

A nod pattern is:

  analogWrite(VIBRATIONPIN, 255);
  analogWrite(VIBRATIONPIN, 0);

A short nod is:

  analogWrite(VIBRATIONPIN, 255);
  analogWrite(VIBRATIONPIN, 0);

Testing vibration motor

Detecting taps

In week 11: Input devices I created a prototype of my board with an accelerometer ADXL343. as input device.
The ADXL343 is great because of its many build in functions, that you can activate via I2C. I designed it in KiCad. The footprint for the ADXL was not available in the fabacademy library. Therefor I thought about design a footprint myself.
But I found that a fellow fabacademy student Ilias Bartolini had designed a footprint for the ADXL343 for KiCad.
Further my design contained an ATtiny and the whole board ran on 3.3V using a voltage converter. The accelerometer talks I2C and I made the mistake with my board to not select the correct pins.
I fixed it by bridgin the correct pins.
Also I was not able to correctly solder the accelerometer, so in the end I never communicated with the accelerometer, and I think I broke it with the heat gun. Next my whole board stopped responding, and I was not able to communicate with it over Serial.

Connected pins for the accelerometer PCB design in KiCad New vibration motor milled board Components for soldering  bridging the wires Infamous no I2C devices found messages

For my final board I did not wanted to make the same mistake as in week 11, and I decided to play it save and design the board to use an accelerometer breackoutboard with the MPU-6050 that I also used in week 11: Input devices

Raw accelerometer and gyroscope values from MPU6050 plotted with ArduinoIDE

I wanted to use this board to detect taps. The MPU-6050 does not have dedicated algorithms for detecting taps, therefor we create a basic implementation on the Atmega using a threshold to detect a peak from the raw signal.

  byte x: 1;
  int xIntensity;
  byte y: 1;
  int yIntensity;
  byte z: 1;
  int zIntensity;
  long last;
  long current;
} peak;

 AcX = abs(AcX);
    xNorm = (AcX * alpha) + (xNorm * (1 - alpha));
    AcX = abs(AcX - xNorm);
    xBuf[0] = xBuf[1];
    xBuf[1] = xBuf[2];
    xBuf[2] = AcX;
    if (xBuf[1] > TAP_MIN_THRESHOLD && xBuf[0]*TAP_SENSITIVITY_LEVEL < xBuf[1] && xBuf[1] > xBuf[2]*TAP_SENSITIVITY_LEVEL) {
      peak.x = 1;
      peak.xIntensity = xBuf[1];
      peak.current = previousRead;


 //handle peaks
    if ((peak.x > 0 || peak.y > 0 || peak.z > 0) &&  peak.current - peak.last > 50) {
      //tap detected, send package over serial
      int intensity = (peak.xIntensity + peak.yIntensity + peak.zIntensity)/3/100;
      byte pattern[4];
      pattern[0] = intensity;//intensity
      pattern[1] = 0x0A;//duration
      if ((peak.current - peak.last) > 1000) {
              pattern[2] = 0x00;//max pause reached
      } else {
             pattern[2] = ((peak.current - peak.last) / 10); //pause
      pattern[3] = 0xFF;//end
      bleSerial.write(pattern, 4);
      Serial.write(pattern, 4);
      peak.last = peak.current;
    //reset peak detection
    peak.x = 0;
    peak.xIntensity = 0;
    peak.y = 0;
    peak.yIntensity = 0;
    peak.z = 0;
    peak.zIntensity = 0;

The code loads a measurement of one axis, in this example the X axis.
Next it makes the value absolute, making sure we only work with positive values.
Then I normalise the value by substracting a running average (the alpha calculation) of the previous values.
Having a normalized X value I store it in a buffer with 2 previous measurements.
Then there is an if statement with peak detection above a threshold.
I compare the 2nd measurement with the first and 3rd measurement and see if it is 8 times higher (TAP_SENSITIVITY_LEVEL).
I determined this sensitivity level by tapping a lot of times on the device and next to the device.
Funny note, without this sensitivity threshold, I would many many peaks when the washing machine is on that is 5 meters away from the table!
So when the 2nd value is higher than the two other values, I count it as a peak, and store this in a struct.
After repeating these steps for the Y and Z axis I check the peak struct if a peak is found.
When found I calculate the average intensity by combining the 3 axis intensity values.

Serial communication

In week 9 and week 16 I explored Serial communication with the ATTiny using the software serial library. In our group assingment I explored the Serial lib and the Atmel328p. I designed a board for the Arduino pro mini to controll up to 6 servo’s. To calibrate each servo I wrote a simple servo controll code, that allows you to move (up to 6) servo arms from 0 to 180 degrees using the Serial monitor.
To move for example servo arm 1 (0x01) to 160(0xA0) degrees you send the following command over the Serial in HEX:

01 A0

The range between 0 and 180 is 0x00 till 0xB4. Then I extended the protocol with an end bit 0xFF. The 0xFF code is to indicate a message is finished making it easy for the Arduino to process the received data.

To move for example servo arm 1 (0x01) to open (0x01) you send the following command over the Serial in HEX:

01 01 FF

To close it you send:

01 00 FF


For my new board I wanted to incorporate this protocol, but allow for sending vibration information in small packages. I created a package in a byte array containing my new package protocol:

  • byte intensity
  • byte duration, now default 0x0A (15, what translates to 15x10=150 ms)
  • byte pause, either a value lower than 1000 ms or 0
  • byte endbit 0xFF I send this over the software serial to the BLE device, that sends it to the smartphone.
    Also for debug I send it to my Serial
    To notify the user, I also vibrate the pattern.
    Last I reset the peak struct and start the loop over.
void serialEvent() {
  while (Serial.available()) {
    byte incommingByte =;
    if (incommingByte == endByte) {
      if(counter != 0){
       //orden the last 3 bytes
       byte temp[3];
      temp[0] = incomming[counter];
      counter = ( counter + 1 ) % messageLimit;
      temp[1] = incomming[counter];
      counter = ( counter + 1 ) % messageLimit;
      temp[2] = incomming[counter];
        counter = 0;
      incomming[counter] = incommingByte;
      counter = ( counter + 1 ) % messageLimit;

Testing the Bluetooth board

Next up was the testing of the Bluetooth board.
My new board had special debug headers for the Bluetooth board, that I connected my FTDI controller to.
The board uses 3.3v, so I used a 5v to 3.3v converter to convert the VCC and TX pin of my FTDI controller.

I download the “RN4870/71 Bluetooth® Low Energy Module User’s Guide” and looked up the specific serial commands I need.

From the manual on page 12 I learned the device is by default a pipe directly transfering received data:

The RN4870/71 operates in two modes: Data mode (default) and Command mode. When RN4870/71 is connected to another BLE device and is in Data mode, the RN4870/71 acts as a data pipe: any serial data sent into RN4870/71 UART is trans- ferred to the connected peer device via Transparent UART Bluetooth service. When data is received from the peer device over the air via Transparent UART connection, this data outputs directly to UART.

On page 13, we see we can connect over serial using the following settings:

  • Baud Rate: 115200
  • Data Bits: 8
  • Parity: None
  • Stop Bits: 1
  • Flow Control: Disabled

I copied these settings to CoolTerm and directly got response when starting the device.

In the manual on page 15, we find that commands can be send in ASCII and always end with a CR (Cariage Return). To start communicating with the chip over serial you first need to activate “Command mode”. This can be done by sending:


When the device is in Command Mode it sends the response:


Next with the SN command, I set the name to “TikTok”:


When askin the name with the GN command, I received “TikTok” as name.

Set and confirmed TikTok is the new name of the device

With the D command we get some default settings information of the device:

CMD> BTA=D88039FA6F73

With V we get the firmware version on the device

CMD> RN4871 V1.18.3 4/14/2016 (c)Microchip Technology Inc

At the website of Microchip, we find the latest firmware ie 1.30. I am a bit behind. Still we have enough basic functionality to continue without updating the firmware.

Android app

Inweek 14 I added a Bluetooth board to my microcontroller and was able to communicate with my iPhone and a Serial Bluetooth app with the microcontroller.
In week 16 I expanded this functionality by creating a custom app.
It is based on the BLEArduino app, but I had to expand its functionality to be able to send and receive data with my board new board. This because in week 16 I used the HM-10 module and I now use the Microchip RN4871. Also I did not refined the user interface.

Sending a 0, 1,2 and 3 using the BLEArduino app

Receiving data from the BLE module and displayed in the connection state label

Serial communication over Bluetooth

I tested connection with the module, by downloading the Microchip Bluetooth Smart Discovery app With this app I could not connect to the device.
I tried to connect with the device via my own Android app created in week16, and this worked! I directly got a connection and saw the connect and disconnect messages in the Cool Term app. However I was not able to send and receive data from my app.

Showing connect and disconnect messages in Cool Term.

To further get my apps working I read on page 59 of the manual, how to get the Transparent UART functionality for BLE working.
I had to type the following commands over serial:


Now I could see the GATT services, communicate and properly connect with most apps.
Only not my Android app, this was because it was only looking for the GATTs from the HM10 device, not the RN4871.
I looked up the specific UUID’s on page 65 in the manual and added them to my Android app.

    public static String RF4871_RX_TX = "49535343-FE7D-4AE5-8FA9-9FAFD205E455"; //the service
    public static String RF4871_TX = "49535343-1E4D-4BD9-BA61-23C647249616"; // the characteristics
    public static String RF4871_RX = "49535343-8841-43F4-A8D4-ECBE34729BB3"; // the characteristics

Fail with setting the UUID HEX codes for the new GATT

At first my changes did not had any effect. Only after a few hours tweeking and trying out different combinations, I found that somehow the HEX codes in Android are case sensitive!
This is clearly a bug, HEX codes should be either all upper case or it should not matter.
After setting the HEX values to lower case sending of the data worked.

 public static String RF4871_RX_TX = "49535343-FE7D-4AE5-8FA9-9FAFD205E455".toLowerCase();

Fail, not able to receive values

Next, I was not able to receive values from the BLE chip on my app. As I looked at the received services, and read about the service, I thought that maybe I used the wrong approach in Android.
I found this great simple tutorial on all about circuits and implemented it in my BLE app. But, when asking the Android Bluetooth service if data was available, I kept receiving the message that this GATT was not available.
When I looked at the logs, I noticed I sometimes tried to ask to fast for this data, so before the Bleutooth service was finished with connecting and gathering the available services.
Since the Bleutooth service tells us when it is finished gathering BLE services, I used that listener to tell me when I could start gathering data.

    } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
        //enable communication buttons.


 	public void enableCommunicationButtons(){
		 if(mBluetoothLeService != null) {
		     Log.d(TAG, "GATT Services received, you can start listening");

Still the receiving of the data gave no result, but at least I now had no errors.

I went back to my old code for my MH10 BLE device and looked at how I received data via that device.
I did it not by directly requesting available data, but by setting a notification.
Both approaches should work according to the documentation in the Microchip R4871 manual, but I thought that maybe it is an Android thing why it does not work via the new approach.
I modified the code to activate the notification. And I started receiving the values.

    public void readCustomCharacteristic() {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
        /*check if the service is available on the device*/
        BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString(SampleGattAttributes.RF4871_RX_TX));
        if(mCustomService == null){
            Log.w(TAG, "Custom BLE Service not found");
        /*get the read characteristic from the service*/
        BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(UUID.fromString(SampleGattAttributes.RF4871_TX));
        if(mBluetoothGatt.readCharacteristic(mReadCharacteristic) == false){
            Log.w(TAG, "Failed to read characteristic, setting notification");
            setCharacteristicNotification(mReadCharacteristic, true);

     * Enables or disables notification on a give characteristic.
     * @param characteristic Characteristic to act on.
     * @param enabled If true, enable notification.  False otherwise.
    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);

        if ( UUID.fromString(SampleGattAttributes.RF4871_TX).equals(characteristic.getUuid())) {
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(

Note that I kept the CLIENT_CHARACTERISTIC_CONFIG. This is a special descriptor telling the Bluetooth service the BLE service is a custom service, not defined in the BLE documention. Read more about this and GATT atributes on this Oreilly page.

After receiving the data I processed it to my new protocol containing 4 bytes:

  1. intensity of the vibration (desired values between 10 and 100)
  2. duration of the vibration
  3. pause after vibration
  4. end bit 0xFF

If the received message is a complete message, I search for the end bit (0xFF) and then gather the intensity, duration and pause data to pass it to the next class.

    private void broadcastUpdate(final String action,final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);
        final byte[] data = characteristic.getValue();

        if(data != null && data.length >= 4){

            for(int i=0; i< data.length; i++){
                if(data[i] == (byte)0xFF && i-3 >= 0){
                    intent.putExtra(EXTRA_DATA, new byte[]{data[i-3],data[i-2], data[i-1]});

At the next class I process it to an Object, that makes more sense for the application and programmer:

    void handleReceivedDataFromBLE(byte[] data){
        VibrationDataPoint vdp = new VibrationDataPoint(data);

I designed the VibrationDataPoint class to know about bytes and integers, making it easier to work in Android.

public class VibrationDataPoint {
    private int intensity; //between 10 and 1000
    private int duration; //between 10 and 1000ms
    private int pause; //between 10 and 1000ms

    public VibrationDataPoint(int intensity, int duration, int pause){
        this.intensity = intensity;
        this.duration = duration;
        this.pause = pause;

    public VibrationDataPoint(byte[] dataPoint){
        if(dataPoint.length == 3) {
            setIntensity(((int)dataPoint[0]& 0xFF)*10);
            setDuration(((int)dataPoint[1]& 0xFF)*10);
            setPause(((int)dataPoint[2]& 0xFF)*10);
            throw new DataPointInvalidError();


    public byte[] toByteArray(){
        return new byte[]{(byte)intensity, (byte)duration, (byte)pause};

Writing code in Android Studio


My app still had the basic interface, so I modified the interface to match with my new TIKTOK brand.
I created a theme with and the main colors to match my hardware: red, black, white and grey.

<?xml version="1.0" encoding="utf-8"?>
<!-- Palette generated by Material Palette - -->
<color name="primary">#F44336</color>
<color name="primary_dark">#D32F2F</color>
<color name="primary_light">#FFCDD2</color>
<color name="accent">#9E9E9E</color>
<color name="primary_text">#212121</color>
<color name="secondary_text">#757575</color>
<color name="icons">#FFFFFF</color>
<color name="divider">#BDBDBD</color>

Next I opened the activity_control.xml file, my main screen layout, and placed slider components (Seekbar) for setting the TIK (vibration pattern). To let the components match with my new color theme I created a theme in the values folder defined in the styles.xml Here I gave the app its new colors, and de seekbar and the buttons the correct colors and dimensions.

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primary_dark</item>
        <item name="colorAccent">@color/accent</item>

    <style name="Seekbar" parent="Base.Widget.AppCompat.SeekBar">
        <item name="android:maxHeight">5dp</item>
        <item name="android:splitTrack">false</item>
        <item name="android:progressDrawable">@drawable/custom_seekbar</item>
        <item name="android:thumb">@drawable/custom_thumb</item>

    <style name="Button" parent="Widget.AppCompat.Button">
        <item name="android:background">@color/primary</item>
        <item name="android:textAppearance">@style/textButton</item>
        <item name="android:minHeight">60dip</item>
        <item name="android:minWidth">88dip</item>
        <item name="android:focusable">true</item>
        <item name="android:clickable">true</item>
        <item name="android:gravity">center_vertical|center_horizontal</item>

    <style name="textButton" parent="TextAppearance.AppCompat.Widget.Button">
        <item name="android:textColor">@color/icons</item>

Last in the screen editor I assigned the new styles to the specific components.

Editing the main screen in Android Studio

To be able to use the new Seekbar values for our TIK I collected the values in the DeviceControlActivity class before I send the TIK to the microcontroller.

    public void onClickWrite(View v){
        if(mBluetoothLeService != null) {
            	new VibrationDataPoint(((SeekBar) findViewById(,
                    ((SeekBar) findViewById(,
                    ((SeekBar) findViewById(;

And when the app receives a TOK it displays the result on the screen instead of only in the log files.

    void handleReceivedDataFromBLE(byte[] data){
        VibrationDataPoint vdp = new VibrationDataPoint(data);
        Log.d(TAG, "Received vibration data= " + vdp.toString());

        dataList.append("\nTOK: "+System.currentTimeMillis()+" "+ vdp.toString());



Then I was out of time, I would have likes to implement more features, as an API inteface for other apps, vibration pattern examples as the current time in vibrations, and ofcourse design a new board with onboard accelerometer and battery management.
I think that a next iteration I can make the board twice as small, by losing the headers, and adding an onboard accelerometer.
I then want to use the ADXL343 again instead of the MPU6050, but I will not make the same mistake as in Week11. I will make a special component board as how my RN4871 is provided by Microchip. This way I can experiment with correctly soldering the accelerometer, without risking to destroy my traces of my board and having to create a new board.

A Hero shot of my final project, a working TIKTOK band detecting taps, vibrating and communicating with the TIKTOK app via Bluetooth

Share this story