Category: tutorial

Sending motion data to the Blynk app (part 2 of the Blynk tutorial)

In the first blog post we explained the basics of controlling the body interaction 2 (BI2) vibrator development board using the concept of  (virtual) pins. This time we want to send data from the BI2 board to the Blynk app. The BI2 has the MPU-9250 9DoF (9 Degrees of Freedom) IMU (Inertial Measurement Unit) sensor on board. This sensor is a combination of an accelerometer, gyroscope and magnetometer. Especially the accelerometer is important for motion detection. This could be used for controlling the vibrator as show with the body interaction 1 (BI1).

For measuring the motion data we use the asukiaa library. Please search and install the library in the Arduino library manager.

In the program code the library must be included and a MPU9250 sensor object must be defined. Finally we need several variables of the type float.

#include <MPU9250_asukiaaa.h>
MPU9250 mySensor;
float aX, aY, aZ, mDirection, pitch, roll, yaw;

In the setup part of the program we need to tell the MPU9250 how it is connected to the ESP8266 microcontroller. [The MPU9250 IMU is connected by the I2C bus to the ESP8266 microcontroller: the sda pin of the IMU is connected to pin 4, the scl pin to pin 5. The connection between MPU9250 and ESP8266 is managed with the standard Wire library.]

For using the accelerometer and magnetometer we have to initialize the sensor with a begiAccel() call to the IMU library.

Wire.begin(4, 5); //sda, scl
mySensor.setWire(&Wire);
mySensor.beginAccel();
mySensor.beginMag();

We have to tell the program how often data is sent to the app. Therefore we need an important concept in microcontroller programming:

Timer

With the help of the timer we can tell the microcontroller to do a given tasks again and again e.g. after 1000 microsecond. You cannot use the delay function to pass time as this would interrupt the important call to the Blynk.run(); function which is located in the loop part of the program.

First we have to define an object of type Timer.

BlynkTimer timer;

In the setup part we have to say how often what the timer has to do. in this example the timer will call the function myTimerEvent every 1000 microsecond.

timer.setInterval(1000L, myTimerEvent);

In the loop part of the program we have to call the timer to keep things going:

timer.run(); // Initiates BlynkTimer

Now we need the function myTimerEvent what has to be done every 1000 seconds.

void myTimerEvent()
{
  // here add was has to be done
}

First we have to update the sensors (accelUpdate, magUpdate). Then we read out the acceleration data in the X, Y and direction. You can already use this data but they are hard to catch. Therefore we can calculate the pitch, roll and yaw. These are angles from -180° to +180°. The calculation is complicated and I don’t understand it. But with the given formulas you get a very rough approximation which makes the data quite accessible.

void myTimerEvent() {
  mySensor.accelUpdate();
  aX = mySensor.accelX();
  aY = mySensor.accelY();
  aZ = mySensor.accelZ();

  // calculate pitch, roll, yaw (raw approximation)
  float pitch = 180 * atan (aX/sqrt(aY*aY + aZ*aZ))/M_PI;
  float roll = 180 * atan (aY/sqrt(aX*aX + aZ*aZ))/M_PI;
  float yaw = 180 * atan (aZ/sqrt(aX*aX + aZ*aZ))/M_PI;

  // read gyroscope update
  mySensor.magUpdate();
  mDirection = mySensor.magHorizDirection();
}

Finally we send the data back to the Blynk app. Now we use the virtual pins. For the variables pitch we  use virtual pin 2 (V2), for roll V3, for yaw V4 and for mDirection V5. We have to add the following line to the myTimerEvent function.

void myTimerEvent() {
  // send data to app via virtual ports, e.g. virtual pin V2 is set to pitch
  Blynk.virtualWrite(V2, pitch);
  Blynk.virtualWrite(V3, roll);
  Blynk.virtualWrite(V4, yaw);
  Blynk.virtualWrite(V5, mDirection);
}

Now the data are continously sent to the Blynk app. To visualize the data we add the widget SuperChart.

For each variable we have to define the input (virtual) pin. For pitch we use the virtual pin V2. In addition we define the color and style of the graph and more.

 

Finally the super graph shows us the date from the accelerometer which are updated every second.

First part of the tutorial (setup Arduino, setup Blynk, LED and motor control) is here

Here is the complete code:

 

/*************************************************************
bodyinteraction.org
sample program for reading MPU data, setting LED color and motor speed
*/
#define BLYNK_PRINT Serial
// include this library in the Arduino library manager
#include "FastLED.h"

// How many leds in your strip?
#define NUM_LEDS 1
// LED data pin is connected to pin?
#define DATA_PIN 14

// Define the array of leds
CRGB leds[NUM_LEDS];
int wave;

// include this library in the Arduino library manager
#include <MPU9250_asukiaaa.h>
MPU9250 mySensor;
float aX, aY, aZ, mDirection, pitch, roll, yaw;

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "Your Auth Token XXXXXXXXXX";

// Your WiFi credentials.
char ssid[] = "YOUR SSID   XXXXXXXXXXXXXX";
char pass[] = "YOUR Password XXXXXXXXXXXX";
BlynkTimer timer;

void myTimerEvent()
{
  // read acceleration data
  mySensor.accelUpdate();
  aX = mySensor.accelX();
  aY = mySensor.accelY();
  aZ = mySensor.accelZ();
  // read gyroscope update
  mySensor.magUpdate();
  mDirection = mySensor.magHorizDirection();
  // calculate pitch, roll, yaw (raw approximation)
  float pitch = 180 * atan (aX/sqrt(aY*aY + aZ*aZ))/M_PI;
  float roll = 180 * atan (aY/sqrt(aX*aX + aZ*aZ))/M_PI;
  float yaw = 180 * atan (aZ/sqrt(aX*aX + aZ*aZ))/M_PI;
  // send data to app via virtual ports, e.g. virtual pin V2 is set to pitch
  Blynk.virtualWrite(V2, pitch);
  Blynk.virtualWrite(V3, roll);
  Blynk.virtualWrite(V4, yaw);
  Blynk.virtualWrite(V5, mDirection);
}

BLYNK_WRITE(V0) // set RGB color values which are transmitted from the app as V0 (virtual pin 0)
{ 
  int i = param[0].asInt();
  int j = param[1].asInt();
  int k = param[2].asInt();
  leds[0].setRGB(j,i,k);
  FastLED.show();
}

void setup()
{
  Serial.begin(115200);
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);

  Wire.begin(4, 5); //sda, scl
  mySensor.setWire(&Wire);
  mySensor.beginAccel();
  mySensor.beginMag();

  Blynk.begin(auth, ssid, pass);
  timer.setInterval(1000L, myTimerEvent);
}

void loop()
{
  Blynk.run();
  timer.run(); // Initiates BlynkTimer
}

 

Please feel free to comment or write to jacardano@gmail.com

Programming the body interaction 2 (BI2) with Blynk part 1

This in an intro to using and programming the BI2 with the Blnyk app. Read here how to set up Arduino. For a more general basic intro (based on the body interaction 1 board) read here.

Pins

The communication between app and BI2 microcontroller is realized by pins. The idea is very easy: Each widget in the Blynk app is connected to a physical pin of the microcontroller. Every microcontroller has several pins where you can connect other electronic parts like a LED or a vibration motor. For each pin you have to configure if it is a output or input pin. Output pins are for controlling actuators, like LED, motor or display. Input pins are connected to sensors, like buttons, temperature sensors, acceleration sensor.  In addition each pin can be digital, analog or virtual.

Digital output pins can only set the actuator to on or off e.g. turning the LED on or off. Analog pins can set the actuator to a specific value in a given range. Usual this in done in the range [0..255] or [0..1023]. For a motor 0 will set the motor off, 50 may be make the motor move very slowly and 255 will be full speed. An analog output pin is sometimes called PWM. (PWM is a method to simulate an analog signal with a sequence of digital on/off signals.)

Digital input pins can read the position of a button (on/off). Analog input pins can read a value in a given range, e.g. the acceleration in the X-axis or the temperature.

So what you have to do to connect a widget to a pin? Just set the widget (e.g. on/off switch widget) to the pin you want to set on/off (e.g. a pin which is connected to a LED). That’s all. No programming required. All you need is this small program which must be uploaded to the microcontroller with the Arduino IDE.

The body interaction 2 use the ESP8266 microcontroller. There are 16 pins, all could be used as digital or analog, input or output. But only pin 12 and 13 are free to use (the rest if for internal communication). Pin 14 is connected to the LED WS2821B.

The Arduino sketch

The first 3 lines are for configuring Blynk and using two libraries. The 3 variables auth, ssid and pass are defined. (The variables are from thy type char (=character) and in this case it is not only one character but an array which you can see by the “[” and “]”. Here you have to add your AUTH token from the Blynk app, and SSID and password from your local WLAN/WIFI.

#define BLYNK_PRINT Serial 
#include <ESP8266WiFi.h> 
#include <BlynkSimpleEsp8266.h> 

char auth[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXX"; 
char ssid[] = "XXXXXXXX"; 
char pass[] = "XXXXXXXX";

Each Arduino program consists of a setup and a loop procedure. The setup is called only one time when the microcontroller is started (or connected to a battery). It is used to initialize the microcontroller, in this case Blynk is started. The loop will be called indefinitely and all statements are executed in the given order. To get Blynk running you have to call Blynk again and again (“Blynk.run();”). According to the Blynk manual, you should not add a delay() function here, because this could disturb the communication between the app and the microcontroller.

void setup() { 
  Blynk.begin(auth, ssid, pass); 
} 

void loop() { 
  Blynk.run(); 
}

Virtual pins

So far communication is only possible with physical pins. But how can you exchange other information? Maybe you want to tell the microcontroller to “shut up immediately”,  or you want to play a given vibration pattern like a sinus curve. For this you can use “virtual pins”. (IMHO there is no reason to call this mean of data exchange “virtual” and it is has nothing to do with a pin. You can call it a variable or channel for data exchange.) The zeRGBa widget is a good example. The color of the LED is controlled by 3 values, the amount of red, green and blue color. This 3 values can be connected to one virtual pin (“V0”) and then they will be transmitted to the microcontroller. To change the color of the LED you have to program the microcontroller  to read out the amount of each color and set the LED to the appropriate value.

We will demonstrate virtual pins with the LED. The WS2821B LED is connected to pin 14, but you cannot control the LED directly by setting the pin to a given value. This is done by a library which controls the LED.

First we have to include the library, we use FastLED.

#include "FastLED.h"

Then  we have to tell how many LEDs we have (you can put several of them in a chain). The BI2 has only one on board (but you can add more).

#define NUM_LEDS 1 // number of LEDs

The you have to tell to which physical pin the LED is connected (14). Finally you have to set up a (instance of an) object “CRGB” for the LED where all relevant data is hidden.

#define DATA_PIN 14 // pin for LED 
CRGB leds[NUM_LEDS]; // define the array of leds

Now comes the more difficult part. The zeRGBa widget has 3 values (one for red, one for green, one for blue) and all are put in the virtual variable V0.

We have add a new function called “BLYNK_WRITE(V0)”. To get the first value we have to read out “param[0]”, for the second “param[1]” etc. We want to store this first value in a variable “i” of the type integer. To assure that param[0] is also from the type integer we add “.asInt()”. The value for red is put in variable i, green in j and blue in k.

BLYNK_WRITE(V0) {
  int i = param[0].asInt();
  int j = param[1].asInt(); 
  int k = param[2].asInt();
}

Now we have to tell the function BLYNK_WRITE what to do with the values i, j an k. This is done by using the method setRGB which is attached to the LED (which is number 0)

leds[0].setRGB(j,i,k);

Now we can make changes to other LEDs (if we have more than one). If you are ready you have to tell the LED to show the new color.

FastLED.show();

In addition a new statement has to be added to setup the LED within the setup part.

void setup() { 
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
  [...]

Now we can put everything together the script will look like this:

/*************************************************************
Controling the body interaction 2 board with the Blynk app
*/

#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

// Auth Token infor the Blynk App.
char auth[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXX";

// Your WiFi credentials.
char ssid[] = "XXXXXXXX";
char pass[] = "XXXXXXXX";

// Library for controlling the WS2821B (Neopixel) LED or LED strip
#include "FastLED.h"
#define NUM_LEDS 1 // number of LEDs
#define DATA_PIN 14 // pin for LED
CRGB leds[NUM_LEDS]; // define the array of leds

// This function set the LED color according to the selected RGB values in the app.
// RGB values are controlled in the app with zeRGBa widget
// values are stored in the virtual pin V0
// V0 consists of 3 values for Red, Green, Blue
BLYNK_WRITE(V0) // set LED RGB color values
{
  int i = param[0].asInt();
  int j = param[1].asInt();
  int k = param[2].asInt();
  leds[0].setRGB(j,i,k);
  FastLED.show();
}

void setup()
{
  // init LEDs
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);

  // connect to Blynk
  Blynk.begin(auth, ssid, pass);
}

void loop()
{
  Blynk.run();
}

Do you like this, do you need this, do you understand this? Tell me jacardano@gmail.com

BI2 – building a silicone sex toy

Now let’s build the first ESP8266 vibrator. I use the reliable design from this blog post and the new BI2 board. The new BI2 board can be controlled from any smart phone or computer.

As the BI2 board is round there is no need to build a case for the PCB and the LiPo. The easist way is to glue the battery directly on the ESP8266. Connect the battery and one or more vibration motors with the BI2 board.

 

The form consists of two parts which are fastened together with tinker wire. Before you have to insert the board with the vibration motor(s) and the battery. Therefore I used a handle. The handle could be put on top of the form. Then fix a USB connector to the handle. Plug in the BI2 board. Fasten the second half of the form.

Very important: The USB micro connector on the board must be protected from the silicone. When silicone flow between USB plug and connector it will be impossible to pull out the plug. I use wax to seal the USB micro connector. Read more here.

 

Now pour in the silicone, wait for some hours. And open softely the form.

 

Remove the overhanging silicone.

Here ist the Link to Tinkercad where you can edit the form and download STL files for your 3D printer: Download from Tinkercad: formhandle. Download ready to print zipped STL files.

Now build YOUR personal sex toy. Here you find the code for the ESP8266 as well as an IOT server application for quantifying your sex and remote control.

BI2: ESP8266 Vibrator Development Board – becoming colourful

The second version of the development board – I will call it BI2 from now on –  has some improvements:

  • I used more components of the original design (Adafruit Feather Huzzah) instead of comparable (and cheaper) Seeedstudio Open Part Library components. The reason for this is easy. The Adafruit design is reliable and approved. No need for designing your own circuits, no risk to fail. (But also no fun in inventing new circuits.)
  • I added LED light – the WS2812B – which is a  colourful LED (16 Mill. colours). They are commonly known as Adafruit Neopixel – a strip or a ring of individual programmable LEDs.
  • The diameter is smaller the first version.
  • It can drive three motors. (When you use the LED then only two motors can be driven.)

Here are some impressions of the board:

 

As you can see I had to wire the LED by hand. The reason for this is that I used GPIO16 which does not work at all. So I wired the LED to GPIO0 which can be used for testing only. The only free GPIOs are 12, 13 and 14.

 

 

 

 

 

 

 

Basic Node for the Internet of Sex Toys – part 3: software

This the third part of the tutorial which has the following parts:

part 1: Basic Node for the Internet of Sex Toys

part 2: Molding the Basic Node

part 3: Software for the Basic Node

For the basic node a simple software realizes all features like Mqtt communication, Web server, basic web user interface, reading data from the accelerometer. Please use the code at github and send request over github. Now the imported parts of the code are explained.

To communicate with the IOT Mqtt is used (read more here). This is a fast protocol for data transmission. Therefore we need a Mqtt server. You can install one on your local computer or use a cloud-based Mqtt server. We use the free CloudMqtt. The following variables must be initiated with the data  of your server. Please get your own account at CloudMqtt or use my server (but don’t spam it, please). Please remember: Transmission is not encrypted, everybody can read it.

const char* mqtt_server = "m12.cloudmqtt.com";
uint16_t mqtt_port = 15376;
const char* mqtt_user = "nvcuumkf";
const char* mqtt_password = "C-X6glwisHOP";

We have now  7 different modes. In each mode the basic node behaves different.

const int offMode = 0;
const int maxMode = 1;
const int sinusMode = 2;
const int motionMode = 3;
const int constantMode = 4;
const int listenMode = 5;
const int listenAndMotionMode = 6;

In off mode the basic node is off, in max mode the vibration is maximum. In sinus mode the vibration speed is altered according to a sinus curve.

Web user interface of the basic node

In motion mode the vibration changes according to the movement of the basic node. When moved fast the speed goes up, when moved slowly or movement stops, the speed goes down. In constant mode any vibration speed can be set to any strength. This feature is only available by Mqtt messages eg. from the IOT node-RED user interface. The listen mode is still experimental. In this mode the speed will be changed by OTHER basic nodes. Finally in the listenAndMotionMode the speed is changed by movements of the basic node and by other nodes. This feature was already available with the body interaction 1 development board as standard mode!

The basic node starts a web server (see image). A web page is generated which build up the user interface. There are buttons for every mode. In addition the speed and the battery power is displayed. This is done in this function:

void generateWebpage() {

The next lengthy procedure is this:

void mqttCallback(char* topic, byte* payload, unsigned int length) {

This is a call back function which is executed whenever a Mqtt message comes in. It parses the Mqtt message which is in the popular JSON format. The commands which are communicated within JSON are explained here. In principle there is a command for every mode, when the command “set mode to off” is send the mode is set to offMode.

In the setup() part of the code you will find a lot of lines like that:

httpServer.on("/MOTOR=MAX", []() {

They corresponds to the generateWebpage() function. When say the max button on the web page is pressed than the affiliated httpServer function is executed. So for every button on the webpage you need a corresponding httpServer function to implement the functionality. In this case (MOTOR=MAX) the mode is set to the constant speed maxMode.

Finally in the loop section of the code the following functions are implemented:

  • reading the accelerometer data
  • change the vibration motor speed according to the mode
  • generate a new JSON message which is send out via Mqtt
  • do the timing

Not mentioned is the OTA (over the air update) function, which is integrated in the code.

Node-RED

For controlling the toy via the internet you can use node-Red. You can find the code at github via this link.

The flow is explained here and here.

 

Basic Node for the Internet of Sex Toys (part 1)

Wemos mini modules: ESP8266, motor driver and battery charging (in the middle); Wireless charging module (right side); wireless charging coil (top side); encapsulated vibration motors (left side)

In previous posts we showed how to build a vibrating sex toy in principle as part of the Internet of Things (IOT). In addition we have selected a hardware platform – the popular ESP8266 – for controlling a vibrator motor, gathering motion data and connecting to the internet. Now we want to build the toy itself.

part 1: Basic Node for the Internet of Sex Toys

part 2: Molding the Basic Node

part 3: Software for the Basic Node

Brief Review of development boards

There are a lot of development boards which are equipped with the ESP8266. The popular NodeMCU was already introduced here. Here is a quick overview and comparison:

NodeMCU

  • plus: very popular, cheap, USB connector for programming
  • minus: quite large (for being part of a sex toy), no support for battery charging

Adafruit Feather Huzaah ESP

  • plus: USB connector for programming and battery charging, smart form factor (only 23 mm wide), very good support (libraries, tutorials)
  • minus: quite expensive

WeMos D1 mini (pro)

  • plus: very cheap, USB connector for programming, additional stackable modules (eg. battery charging, TFT screens, motor driver), good form factor
  • minus: no real support (but there is a forum, problems with modules reported

ESP8285 (variant of the ESP8266)

  • plus: really small (!!!) and smart form factor, USB programming and battery charging, optional sensors on board (but no motion sensors)
  • minus: quite expensive, only 1MB memory (nevertheless enough for a lot of application)

For our project we selected the WeMos mini cause we get almost everything we need:

  • USB connector for programming
  • module for battery charging
  • module for a motor driver
  • good form factor (eg. to be put in a vibrator handle or in the base of a dildo)
  • cheap, fast delivery

But there is no shield for motion detection (accelerometer,gyroscope). So we have to use an additional board eg equipped with the MPU9250.

But there is a problem with the WeMos motor shield: After a few seconds it stopped working. And in addition the MPU9250 stopped working, too. Hours and hours we tried different configurations, changed the libraries … The problem was the motor driver shield itself. Fortunately there is an easy work around. Read here.

Another issue is the battery shield. It has an extra USB connector for charging the battery. So you have two USB connectors (one for battery charging and one for uploading). Two USB connectors are not handy. Fortunately we can do without the USB connector for uploading as it is possible to update the software over the air (OTA) using WiFi.

Material

As the body interaction philosophy uses motion for controlling the device we have to add the MPU. Again we use the MPU9250 which has an accelerometer, gyroscope and magnetometer.

Another insight was that you need at least a switch for rebooting. As we want to mold everything the switch must meet the IP67 requirements, which means it is water- (and silicone) proof. If you don’t want to mold the electronics you can use the RESET button on the WeMos mini board.

A perfect basic node has a wireless charging option, too.

Material list for the basic node:

  • Wemos mini board
  • Wemos motor driver shield
  • Wemos battery shield
  • Wemos prototyping board
  • Wemos set of pins
  • LiPo battery (eg. 3,7V 650mAh, 2C, JST plug, available at ebay)
  • MPU 9250 board (for motion control)
  • 1 or 2 encapsulated vibration motors, 3V, available at Alibabaexpress
  • Optional: Switch IP 67 protected (eg. Cherry Switches DC1C-K8AA IP67) – for molding
  • Optional: Wireless charging receiver 5V eg from Seeed Studio

Material: battery shield, Wemos mini ESP8266, motor shield, MCU9250 (first row), LiPo battery, switch, vibration motor (second row)

 

Soldering the basic node

We use one connector (part of the Wemos set of pins) to connect the Wemos mini with the battery shield and the motor shield. This is done to save space. If your application has enough space you would use one connector for every shield.

Battery shield, Wemos mini ESP 8266, motor shield (from top to bottom)

Now have a look at the bottom side where the motor shield should be. We can connect up to 2 motors. Solder motor 1 to A1 and A2. Motor 2 has to be soldered to B1 and B2. In addition we need input power for the motor. We just use the 5V provided by the Wemos mini battery shield. Connect 5V to VM and GND (from the pins) and GND. But you could use other (more powerful) power sources, too.

Wemos offers a prototyping board. We use it for mounting the switch and for the MPU9250. Connect the MPU9250 to the bottom side of the prototyping board. Therefore 4 pins have to be soldered

Solder pin (1 row, 4 pins)  on the top side next to TX, RX, D1, D2

 

Now look at the bottom side of the prototyping board. Put the MPU 9250 so that VCC, GND, SDA, SCL are connected to the pins.

Next, solder the MPU 9250.

Then add more pins to the prototyping board at both sides. The picture shows the bottom side of the prototyping board.

Now wire the prototyping board. The picture shows the top side.

Now you can add the switch. Place it in the middle of the board on the top side. Connect GND and RST to the switch. Now you have a switch for rebooting which can be molded.

Now we have both parts ready and can stack them together.

Stack them together!

Now add the LiPo battery, which should have a JST header. Now your basic node is ready.

Wireless charging option

Especially for sex toys a wireless charging option is reasonable as this is a requirement for silicone molding of the toy.  And when the toy is molded it is safe and washable.

The wireless charging module consists of a sender (or transmitter module) and a receiver module. You have to solder the receiver module to the battery shield. Don’t mix the modules.

unfortunately there is only  a USB connector. If you don’t want to remove the USB connector you can solder the red (+) wire to the R330 resistor as shown on the pictures. The black (-) wire can be soldered to any pin labeled (GND).

Now put the receiver module on top of the battery module.

Now stack the protoytping board on top of the battery shield.  And connect the battery.To charge the battery connect the sender (or transmitter) module to 5V. To power the sender module you may use a USB port power source which has about 500mAh or more. Place sender and receiver coil about each other.  For a more professional charging solution you need a charging station. The making of a charging station using 3d printing is described here.

Learn how to construct the mold form in part 2:

part 2: Molding the basic node

part 3: Software for the basic node

OpenSCAD as silicone molding form generator


scadmoldform1tryballs_revisited_3_finalAn alternative to 3d-printed sex toys are silicone toys. For making such a sex toy you need a molding form, where you pour in the silicone. If you use Tinkercad to build the form for the balls motive, you may need more than one hour. If you are not experienced in 3d constrcution it may take days. That’s ok and can be fun as you can realize your fantasies step by step.

 

 

molded-with-ueberh-querBut if you want to change a detail or want to resize some parts of it, it will take a long time as you have to unbuilt parts of the form, make changes and then reassemble. Sometimes building from scratch is faster.

In the last blog post we have introduced OpenSCAD to construct a sex toy form. Now we want to build a hull for the sex toy for overmolding.

The basic idea is very simple:

  • Generate two forms. The smaller one has the size of the sex toy you want to make. The larger one will be the form where you pour in the silicone.
  • Than use the OpenSCAD difference command which “subtracts” or cuts out the smaller form from the larger form.

But it is more complicated:

  • You have to include a frame otherwise the form would fall over.
  • You need two forms (A and b) so you could open the form after molding.
  • Both forms must be fastened together when molding. Therefore you need holes for tinkering wire.

bi-round-12-scadWe have created a solution for molding form generation which is as flexible as our OpenSCAD sex toy generator. In addition you can change the thickness of the frame. Therefore you have to change the variable frame_thickness.

The SCAD script uses the module base which is already introduced. The generation of the frame is done in the module frame. The frame consists of a base plate and two supporting frames which stabilize the whole form. In addition there are extensions to the frame in the upper part of the form. These extensions will provide holes for fastening both forms.

The module complete_form constructs the form which is tricky. The union command is used to join the complete outer form and the frame. Now we have a filled form and have to remove the inner part. This is done by subtracting another complete form which is a bit smaller than the outer form. This is done with the difference command.

Another module hole provides all holes for the tinkering wire. At last we construct part A and part B of the molding form. Again the difference command is used to cut out one half of the form. This is done by subtracting a cube which is placed in the middle of the complete form. In addition the holes must be subtracted from the complete form.

You can build in the body interaction vibrator development board to make a vibrating dildo, controlled by motion or by another body interaction vibrator development board. Read more here.

Try out with the Thingiverse customizer.

Download the zipped SCAD file here: bi1-round12

Or copy and paste the source code to the SCAD software:

// bodyinteraction toy form and mold form generator
// radius of bottom part
r_bottom=25; // [15:5:80] 
// height of bottom part
h_bottom=30; // [10:5:80] 
// top rounding of bottom part
rounding=10; // [10:5:20]
// radius of ball 1 
r_ball1=21; // [15:5:50] 
// radius of ball 2
r_ball2=15; // [15:5:50] 
//radius of ball 3 
r_ball3=11; // [15:5:50] 
// radius of connecting cylinders
connector_radius=8; // [10:2:20]
// distance between balls and bottom part
ball_distance=15; // [10:2:40]
// offset (thickness of hull)
o=2; 
// thickness of frame
frame_thickness=4; 

height=h_bottom+3*ball_distance+r_ball1*2+r_ball2*2+r_ball3*2; echo(height);


// form part A
translate([0,0,height+frame_thickness])rotate([0,180,0])
difference() {
 complete_form(r_bottom,h_bottom,rounding,r_ball1,r_ball2,r_ball3,connector_radius,ball_distance,o,frame_thickness,height);
union(){
 translate([-r_bottom-o-10,0,-5])
 color("red")cube([2*r_bottom+2*o+20,r_bottom+2*o,height+frame_thickness+5]);
 holes(height,h_bottom);
 }
}
//form part B
translate([90,0,height+frame_thickness])rotate([0,180,0])
difference() {
 complete_form(r_bottom,h_bottom,rounding,r_ball1,r_ball2,r_ball3,connector_radius,ball_distance,o,frame_thickness,height);
union(){
 translate([-r_bottom-o-10,-r_bottom-o-2-10,-5])
 color("red")cube([2*r_bottom+2*o+20,r_bottom+2*o+10,height+frame_thickness+5]);
 holes(height,h_bottom);
 }
}

module holes (height,h_bottom){
for (i=[h_bottom+30:10:height])
 translate([r_bottom-1,5,i])rotate([90,90,0])
 color("green")cylinder(h=15,r=1,$fn=20);

for (i=[0:10:h_bottom+20])
 translate([r_bottom-3+10,5,i])rotate([90,90,0])
 color("blue")cylinder(h=15,r=1,$fn=20);

for (i=[h_bottom+30:10:height])
 translate([-r_bottom+1,5,i])rotate([90,90,0])
 color("green")cylinder(h=15,r=1,$fn=20);
for (i=[0:10:h_bottom+20])
 translate([-r_bottom-6,5,i])rotate([90,90,0])
 color("blue")cylinder(h=15,r=1,$fn=20);
}

module complete_form (r_bottom,h_bottom,rounding,r_ball1,r_ball2,r_ball3,connector_radius,ball_distance,o,frame_thickness,height) {
 difference() {
 union() {
 base(r_bottom+o,h_bottom+o,rounding,connector_radius+o,ball_distance-2*o,r_ball1+o,r_ball2+o,r_ball3+o);
 //complete frame
 frame(2*r_bottom+2*o,o,height,frame_thickness,r_bottom,h_bottom,rounding);
 };
 base(r_bottom,h_bottom,rounding,connector_radius,ball_distance,r_ball1,r_ball2,r_ball3);
 
 
};
}

module frame(width,o,height,frame_thickness,r_bottom,h_bottom,rounding) {
 //plate
 translate([-width/2,-width/2-2*o,height]) cube(size=[width,width+2*o,frame_thickness]);
 //frame1
 translate([-width/2,-frame_thickness/2,0]) cube(size=[width,frame_thickness,height]);
 //frame 1 extensions
 translate([-width/2-010,-frame_thickness/2,-5]) color("blue")cube(size=[12,frame_thickness,60]);
 translate([-width/2-10,-frame_thickness/2,55]) color("red")rotate([0,45,0]) cube(size=[12,frame_thickness,20]);
 
 translate([+width/2-2,-frame_thickness/2,-5]) color("green")cube(size=[12,frame_thickness,60]);
 translate([+width/2+01,-frame_thickness/2,47]) color("green")rotate([0,-45,0]) cube(size=[12,frame_thickness,20]);
 //frame2
 translate([-frame_thickness/2,-width/2,0]) cube(size=[frame_thickness,width, ,
 height]);
 // stabilize bottom with cylinder
 color("green")translate([0,0,h_bottom])rotate([00,0,0180])
 cylinder(h=r_bottom*2-rounding*.5, r1= r_bottom-rounding, r2=0);

}

module base (r_bottom,height,rounding,connector_radius,ball_distance, c1,c2,c3) {
 union () {
 // connector
 color("white")cylinder(h=height+2*ball_distance+c1*2+c2*2+c3*2,r=connector_radius,$fn=60);
 //base
 color("DarkSlateBlue") cylinder (h=height-0,r=r_bottom-rounding,$fn=60);
 color("MediumSlateBlue")cylinder (h=height-rounding,r=r_bottom,$fn=60);
 translate([0,0,height-rounding]) color("SlateBlue") rotate_extrude() 
 translate([r_bottom-rounding,0,0]) circle(r=rounding,$fn=120);
 // circle (ball) 1, 2 and 3
 translate([0,0,height+ball_distance+c1]) color("Indigo")sphere(r=c1,center=true,$fn=60);
 translate([0,0,height+2*ball_distance+2*c1+c2]) color("Violet")sphere(r=c2,center=true,$fn=60);
 translate([0,0,height+3*ball_distance+2*c1+2*c2+c3]) color("Purple")sphere(r=c3,center=true,$fn=60);
 }
}

 

Go to the first part of the SCAD tutorial

Internet of (sex) things – part 3: Node-RED

in the second part of this tutorial we have seen how to use the MQTT protocol to send data across the internet. In the third part we show how to add additional functionalities to our sex toys.

The series has 4 parts:

part 1: Exploring the internet of (sex) things

part 2: MQTT messages

part 3: Node-RED

part 4: Building a sex toy dashboard with Node-RED

We want to enable sex toys to communicate and  to connect to social media. Although there are a lot of solutions from the Internet of Things (IoT) community Node-RED is outstanding as you could connect devices without or with little knowledge of programming languages: “NodeRED is a visual tool for wiring together hardware devices, APIs and online services – for wiring the Internet of Things.”  (Wikipedia). There are standard building blocks (called nodes) which are categorized as input, output, function and social nodes. You can select nodes and wire them to create a flow. A typical flow would look like that: input node- function node- output node. If you want to know more you can should have a look at this very good tutorial: http://noderedguide.com/

In this part of the tutorial we will receive and display data from the sex toy. And we want to send control commands to the sex toy. This can be achieved with a few flows in Node-RED:

node-red-overview

Installation of Node-RED:

  1. First you have to install “node.js”. Follow the instructions here.
  2. Now follow the node-red installation instruction.
    For Windows: Press the Windows button. Type in “CMD”. Windows should suggest the command shell app. Now RIGHT-click on the command shell app and select “open as administrator”. In the new command shell window type in

    npm install -g --unsafe-perm node-red
  3. Change to the Node-RED directory and start Node-RED by the command “node red” or “node red.js”
  4. Go to your browser and open http://127.0.0.1:1880/

If you don’t want to make a local installation of Node-RED the online service FRED (https://fred.sensetecnic.com/) offers a good alternative. FRED comes with additional nodes with extra functionalities.

Let’s start with a first flow. We want to control the LED and the motor of our IoT sex toys. Therefore we need two nodes: The input node “INJECT” and the output node “MQTT”. Select both nodes and drag them into the flow window in the middle. Wire both nodes. Then open the Inject-node (just double-click the node). Change the  payload to type “string” and type in the command for switching the LED. This command is taken from the second part of the tutorial:

{messageType : "execute",  actuator : "LED",  actuatorValue : 1 }

In addition you have to enter the topic that will be used for the MQTT message. It is “BIinTopic” – the “in” refers to the sex toy. Select a name like “set LED on”:inject-mode-led-on

Then edit the MQTT node. The name of the MQTT server must be entered. Leave the Topic field empty and the MQTT node will use the topic from the predecessor node INJECT.

mqtt-out-message-to-biNow press the deploy button. You should see the message “successful deployed”.

Now you can press one of the INJECT node button (the button is on the left side of the node) and the LED of the sex toy should go on.controlbi2byrednode

You can use the JSON commands from part 2 of the tutorial and make an INJECT node for each command. With just 5 flows you can control all functions of the vibrator from everywhere. Instead of the INJECT node you could use an Email or Twitter node (instead of the INJECT node) to control the sex toy eg by Email.

There are no file open or save menus in Node-RED. Instead the visual flow can be imported and exported using a simple text file. If you want to import the flow above download and unzip this text file. Select Import -> from clipboard and copy the text from the file to the clipboard. If you want to save the flow, select Export -> from clipboard and copy the text of the clipboard in a new text file.

Now let’s receive messages from the vibrator and parse them. You need a MQTT input node, a JSON function node, a SWITCH node and two DEBUG output node.

We will show how to retrieve the status of the LED. When the LED is on the JSON file includes: “LEDstatus: 1”. Otherwise the JSON file includes: “LEDstatus: 0”.

Edit the MQTT input node and enter the URL of the Mosquitto server and the topic “BIoutTopic”.

mqtt-in

Then add a DEBUG node and select “complete msg”. Wire MQTT and DEBUG node. This node will display the MQTT message in the debug slider (on the rights side). This is only for debugging – you will see if the message from the vibrator comes in (or not).

Now add a JSON function node and connect the MQTT node with the JSON node. The JSON function node will parse the text string which was sent via MQTT and transforms it to a JSON object.

Now select a SWITCH node. As property enter “payload.LEDstatus”. The switch node branches the flow according to LED status which was reported in the JSON file. Now we can test, if the LEDstatus is 0 or 1. For each comparison a line will be added.json-switch-node

Finally make two DEBUG output nodes and wire them with the SWITCH node. Complete the “msg” by adding “payload.LEDstatus”. If the flow reaches the DEBUG nodes you will see a message in the debug slider on the right.

ouputnodeled

 

Now you are ready and can press the deploy button. It should look like that:

analyse-json

Again, the visual flow can be imported. If you want to import the flow above download and unzip this text file. Select Import -> from clipboard and copy the text from the file to the clipboard.

Let us test the flow. You have to set the LED on. Press the “turn on” button in your browser as explained in part 2.vibr iot controlnodemcu prototype breadboard

 

Now have a look at the “debug” slider where you should see the result of the action. The first entry is the JSON file which was received. It is displayed by the DEBUG node “message”. In the second entry the DEBUG node (wired with the SWITCH node) displays 1 which means the LED is on.debug-window-led-on

 

With Node-RED you can add a SQL database to store all data, you can connect to social media and especially you can connect MULTIPLE sex toys and let them interact. Read the excellent guides for parsing JSON files and MQTT:

http://noderedguide.com/index.php/2015/10/28/node-red-lecture-3-basic-nodes-and-flows/#h.5zaw60nvfsyj

What we have achieved: In part 1 we have developed a wifi-enabled sex toy prototype based on the ESP8266. The toy was controlled through a web browser on a local smart phone / laptop. Local refers to the access point. Both the local smart phone / laptop and the ESP8266 must have access to the same access point (eg your router at home.)

In part 2 we opened our connections to the internet. With the fast MQTT protocol we are able to send and receive messages from anywhere. For data transmission  we use the JSON file format. We have sketched a protocol for sending data, commands and messages between sex toys and users.

In this part we introduced Node-RED a visual programming tool for the Internet of Things. With this tool we are able to connect sex toys at different locations, to store sensor data and to get social.

In the fourth part of the tutorial we will introduce User Interfaces to create a sex toy dashboard.

Internet of (sex) things – part 2: MQTT messages

In the first IOT tutorial we have shown how to build a sex toy based on a ESP8266 MCU.

There are two more parts of this tutorial series:

part 3: Node-RED

part 4: Building a sex toy dashboard with Node-RED

The ESP8266 is a microcontroller which can connect to the internet. You can write sketches with the Arduino IDE and connect a lot of actuator modules (like vibration motors, displays) and sensors (motion detection).

nodemcu prototype breadboard

In the first approach a web server was installed on the ESP8266. Control was possible by browsing to the web server, which could be accessed by a computer or smart phone using the same WiFi Access Point (AP).

browser vibrator control

In this second tutorial we will connect the ESP8266 to the internet and publish and receive data as well as commands by internet.

Protocols

There are some protocols for publishing (sending) data. We use the MQTT protocol which is very fast and suited for short messages. In addition we need a MQTT server. We will send the ESP8266 data to the server. And the ESP8266 can receive data (or commands) from the server. Other services can connect to the MQTT server, too. In this tutorial we will use a MQTT client which can display the sex toy data and send commands to the ESP8266.

mqtt-diagramm

Sex toy data exchange format

A big disadvantage of commercial sex toys is their proprietary data exchange formats. Kyle Machutis developed buttplug.io a Cross Platform Framework for Sex Toy Control to overcome this issue.

For this IOT project we will use the JSON format which is a very simple way to exchange data:

This is an example for the message type “sensor”. It says that the fusioned sensor data of the “mps9250” MPU is 5657, the LED is off (0), the motor is in mode sinus curve (2) and the speed of the vibration motor is 766.

{"messageType":"sensor",
"sensor":"mps9250",
"fusionedData":5675,
"messageNumber":8,
"LEDstatus":0,
"motor1mode":2,
"motor1speed":766}

There are three message types: sensor, execute and message.

  • Sensor is for publishing sensor data to everyone who is interested in that.
  • Execute is for controlling a specific device, eg for turning the motor on.
  • Message sends a text message to specific device. If the deviceID is not given it will be sent to all receivers,

For this project we need the

  • hardware from part 1 of the IOT project
  • the Arduino library JSON for parsing and encoding exchange data
  • a library for sending and receiving MQTT data
  • the mqtt-spy software to send and receive MQTT messages
  • optional: a MQTTserver like mosquitto

Arduino JSON library

There is a great library which can parse and build JSON files. Here is the documentation: https://github.com/bblanchon/ArduinoJson

Please go into the Arduino library manager and install the JSON package.

Arduino PubSubClient library

In addition we need a package for sending and receiving MQTT messages. You will find the PubSubClient library in the library manager, too.

Documentation: https://github.com/bblanchon/ArduinoJson

You have to change the maximum length of a message. By default it is only 128. Search for the file PubSubClient.h and change MQTT_MAX_PACKET_SIZE to 1024. On my Win10 system the file is located at

C:\Users\...\Documents\Arduino\libraries\PubSubClient\src\PubSubClient.h

Change the following line:

// MQTT_MAX_PACKET_SIZE : Maximum packet size
 #define MQTT_MAX_PACKET_SIZE 1024

MQTT-SPY software

This is an excellent piece of software which can connect to a MQTT server and send and receive messages: mqtt.spy. We use it to test the connection from the ESP8266 to the mosquitto server and for debugging our vibrator toy control software on the ESP8266.

Download from https://github.com/kamilfb/mqtt-spy/wiki/Downloads

If you haven’t your own MQTT server, you can use the Mosquito test server (only for testing, don’t spam them). Start mqtt-spy and connect to “test.mosquito.org”.

mqtt-start-screen

Subscription of messages: To receive the messages from the ESP8266  you have to subscribe to a topic. Use the same topic as in the source code, eg. “BIoutTopic”. You have to select the “New”-tab in the subscription, a new window pops up. Enter “BIoutTopic”. Now you receive all messages from the ESP8266.mqtt-client

Publishing messages: In the upper part of the window enter “BIinTopic”. In the “data” field you enter commands which will be sent to the ESP8266. Enter the commands and press “Publish”.

subscription-windowTry it out. Here are some examples:

JSON data exchange & command examples

Send message:

{
 messageType : "message",
 message : " Hello world!"
 }

Send Command – LED on:

{
 messageType : "execute",
 actuator : "LED",
 actuatorValue : 1
 }

Send command – motor1 modus is set to sinus curve vibration pattern

{
 messageType : "execute",
 actuator : "motor1",
 actuatorMode : "sinus"
 }

Send Command – set motor speed to 1000.

{
 messageType : "execute",
 actuator : "motor1",
 actuatorValue: 1000
 }

Send command – set motor1 off.

{
 messageType : "execute",
 actuator : "motor1",
 actuatorMode: "off"
 }

Message type “sensor”: this is for publishing sensor data of a sex toy (eg. position in 3d space, movement data, vibration pattern in use). These data can be received by other sex toys for vibration adjustment and synchronization of the vibration speed .

{
 messageType : "sensor",
 sensor: "mps9250",
 fusionedData: 10000,
 }

Remark: If it doesn’t work as expected, check the data field of the MQTT software. Paste & Copy doesn’t work as it should be and you may have to remove some redundant “{“-signs.

Code

The code is based on part 1. In the new code functions for publishing and receiving JSON data over MQTT are added.

Receiving and parsing incoming JSON files is done in “callback”. “callback” will be executed whenever a MQTT message comes in.

void callback(char* topic, byte* payload, unsigned int length) {

At first the incoming message is parsed and the result is stored in “root”. Now each entry in the JSON file can be accessed by assigning a new variable to root[entry]:

StaticJsonBuffer<500> jsonBuffer;
 JsonObject& root = jsonBuffer.parseObject(s);
 if (!root.success()) {
 Serial.println("parseObject() failed");
 } 
 String messageType = root["messageType"];

Build and publishing JSON files is done in the loop. A JsonObject “root” is created and then each entry in the JSON file is added by an assignment to root eg:  root[“messageType”] = “sensor”:

StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["messageType"] = "sensor"; // execute, message, sensor

For producing the JSON file there is “printTo” function. The JSON array of char must be formatted with the snprintf() function and then it can be published.

 root.printTo(outMsg, sizeof(outMsg));
 snprintf (msg,1000, "%s",outMsg);
 mqttclient.publish("BIoutTopic", msg);

Download the zipped and formatted code here: nodemcu-server-mqtt-iot.

In the next part of the tutorial we use Node-RED for visual programming our IOT sex toys.

Here is the complete source code for part 2 of the tutorial.

// bodyinteraction IOT project
// IOT sex toy prototype - control via browser and MQTT
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

#define MPU9250_ADDRESS 0x68
#define MAG_ADDRESS 0x0C

#define GYRO_FULL_SCALE_250_DPS 0x00
#define GYRO_FULL_SCALE_500_DPS 0x08
#define GYRO_FULL_SCALE_1000_DPS 0x10
#define GYRO_FULL_SCALE_2000_DPS 0x18

#define ACC_FULL_SCALE_2_G 0x00
#define ACC_FULL_SCALE_4_G 0x08
#define ACC_FULL_SCALE_8_G 0x10
#define ACC_FULL_SCALE_16_G 0x18

const char* ssid = "ALICE-WLAN";
const char* password = "36s69c3756a65";
const char* mqtt_server = "test.mosquitto.org";

int ledPin = 0; // NodeMCU pad D3 = GPIO 0
int motorPin= 13; // NodeMCU pad D7 = GPIO 13
double sinusValue=0;

// define constants for four different vibration modes
const int offMode=0;
const int maxMode=1;
const int sinusMode=2;
const int motionMode=3;

int motorMode =offMode; //current mode
int motionVector = 0; //current fusioned motion
// Acceleration in x,y and z direction at t(ime)=1 and time=0
// Geroscop data
int16_t ax,ay,az,ax1,ay1,az1,gx,gy,gz,gx1,gy1,gz1;
int valueMotor; //vibrator motor speed 0-1023

WiFiServer server(80);

WiFiClient espclient;
PubSubClient mqttclient(espclient);
char msg[512];
char outMsg[512];

bool requesting=false; // is there a request eg button pressed on webpage

//timing of mqtt messages
long now=0;
long lastMsg = 0;


int value = 0;
int valueLED = LOW;

// This function read Nbytes bytes from I2C device at address Address.
// Put read bytes starting at register Register in the Data array.
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.endTransmission();

// Read Nbytes
Wire.requestFrom(Address, Nbytes);
uint8_t index=0;
while (Wire.available())
Data[index++]=Wire.read();
}

// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.write(Data);
Wire.endTransmission();
}



// Return the response /generate webpage
void generateWebpage(WiFiClient espclient) {
espclient.println("HTTP/1.1 200 OK");
espclient.println("Content-Type: text/html");
espclient.println(""); // do not forget this one
espclient.println("<!DOCTYPE HTML>");
espclient.println("<html>");

espclient.print("Led pin is now: ");

if(valueLED == HIGH) {
espclient.print("On");
} else {
espclient.print("Off");
}

espclient.print("
Motor pin is now: ");
espclient.print(valueMotor);

espclient.println("

");
espclient.println("<a href=\"/LED=ON\"\"><button>Turn On </button></a>");
espclient.println("<a href=\"/LED=OFF\"\"><button>Turn Off </button></a>

");
espclient.println("<a href=\"/MOTOR=MAX\"\"><button>Motor Max </button></a>");
espclient.println("<a href=\"/MOTOR=OFF\"\"><button>Motor Off </button></a>");
espclient.println("<a href=\"/MOTOR=SINUS\"\"><button>Motor sinus curve </button></a>");
espclient.println("<a href=\"/MOTOR=MOTION\"\"><button>Motor motion controlled </button></a>
");
espclient.println("</html>");
}

// function callback is executed when a Mqtt message comes in
// - prints mqtt message
// - parse JSON file
// - execute commands
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
char s[length];
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
s[i]=payload[i];
}
StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(s);
if (!root.success()) {
Serial.println("parseObject() failed");
}
String messageType = root["messageType"]; //sensor, execute , message
String targetDeviceID = root["targetDeviceID"];
String actuator = root["actuator"];
int actuatorValue = root["actuatorValue"];
String actuatorMode = root["actuatorMode"];
String message = root["message"];
Serial.print("messageType: ");
Serial.println(messageType);
Serial.print("actuator: ");
Serial.println(actuator);
Serial.print("actuatorValue: ");
Serial.println(actuatorValue);

// print message
if (messageType=="message") {
Serial.print("Incoming message: ");
Serial.println(message);
}
// LED commands
if (messageType=="execute"&&actuator=="LED"&&actuatorValue==1) {
Serial.println("LED on received");
digitalWrite(ledPin, HIGH);
valueLED = HIGH;
}
if (messageType=="execute"&&actuator=="LED"&&actuatorValue==0) {
Serial.println("LED off received");
digitalWrite(ledPin, LOW);
valueLED = LOW;
}
// set modes commands
if (messageType=="execute"&&actuator=="motor1"&&actuatorMode=="off") {
analogWrite(motorPin, 0);
valueMotor = 0;
motorMode=offMode;
}
if (messageType=="execute"&&actuator=="motor1"&&actuatorMode=="sinus") {
motorMode=sinusMode;
}
if (messageType=="execute"&&actuator=="motor1"&&actuatorMode=="motion") {
motorMode=motionMode;
valueMotor=600;
if (valueMotor<500) {valueMotor=500;} if (valueMotor>1023) {valueMotor=1023;}
}
// set motor speed command
if (messageType=="execute"&&actuator=="motor1"&&actuatorValue!=0) {
Serial.println("set motor speed to fixed value");
valueMotor=actuatorValue;
analogWrite(motorPin,valueMotor);
}
// incoming sensor data, adjust motor speed when in motion mode
int fusionedData = root["fusionedData"];
String sensor = root["sensor"];
if (messageType=="sensor"&&sensor=="mps9250"&&motorMode==motionMode) {
if (fusionedData > 5000) {valueMotor=valueMotor+25;} else {valueMotor=valueMotor-10;}
if (valueMotor<500) {valueMotor=500;} //values must be above 500 otherwise the motor is off if (valueMotor>1023) {valueMotor=1023;} // values higher than 1023 are not supported
analogWrite(motorPin, valueMotor); // set motor speed
}
generateWebpage(espclient);
}

// connect to mqtt server
void reconnect() {
while (!mqttclient.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (mqttclient.connect(clientId.c_str())) {
Serial.println("connected");
mqttclient.subscribe("BIinTopic");
} else {
Serial.print("failed, rc=");
Serial.print(mqttclient.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}

void setup() {
Wire.begin();
// connect MPU9265 via i²c bus
// NodeMCU D1 = GPIO5 connected to MCU9265 SCL
// NodeMCU D2 = GPIO4 connected to MCU9265 SDA
Wire.pins(5,4);
Serial.begin(115200);

// Configure gyroscope range
I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_2000_DPS);
// Configure accelerometers range
I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_16_G);
// Set by pass mode for the magnetometers
I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);

// Request first magnetometer single measurement
I2CwriteByte(MAG_ADDRESS,0x0A,0x01);

Serial.begin(115200);
delay(10);

// init LED pin
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);

// init motor pin
pinMode(motorPin, OUTPUT);
analogWrite(motorPin, 0);

// Connect to WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");

// Start the server
server.begin();
Serial.println("Server started");

// Print the IP address
Serial.print("Use this URL to connect: ");
Serial.print("http://");
Serial.print(WiFi.localIP());
Serial.println("/");

// init mqtt client
mqttclient.setServer(mqtt_server, 1883);
mqttclient.setCallback(callback);
}

void loop() {
if (!mqttclient.connected()) {
reconnect();
}
mqttclient.loop();

// Read accelerometer and gyroscope
uint8_t Buf[14];
I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);

// Create 16 bits values from 8 bits data

// Accelerometer
ax=-(Buf[0]<<8 | Buf[1]);
ay=-(Buf[2]<<8 | Buf[3]);
az=Buf[4]<<8 | Buf[5];

// Gyroscope
gx=-(Buf[8]<<8 | Buf[9]);
gy=-(Buf[10]<<8 | Buf[11]);
gz=Buf[12]<<8 | Buf[13]; // when in "motionMode" the vibration motor is controlled by motion if (motorMode==motionMode) { motionVector=sqrt(pow(ax-ax1,2)+pow(ay-ay1,2)+pow(az-az1,2)); //calculate motion vector // adjust vibration motor speed // if motion vector > 5000 raise speed by 25
// otherwise lover speed by 10
// adjust these constants to your needs
if (motionVector > 5000) {valueMotor=valueMotor+25;} else {valueMotor=valueMotor-10;}
if (valueMotor<500) {valueMotor=500;} //values must be above 500 otherwise the motor is off if (valueMotor>1023) {valueMotor=1023;} // values higher than 1023 are not supported
analogWrite(motorPin, valueMotor); // set motor speed

Serial.print("motionVector: ");
Serial.print(motionVector);
Serial.print(", valueMotor: ");
Serial.println(valueMotor);
delay(200);

// save values
ax1=ax;
ay1=ay;
az1=az;
gx1=gx;
gy1=gy;
gz1=gz;
}

// change vibration motor speed according to a sinus curve
if (motorMode==sinusMode) {
sinusValue=sinusValue+.01;
delay(20);
int sinTmp = ((sin(sinusValue)+1)*.5*(1023-500))+500;
analogWrite(motorPin, sinTmp);
valueMotor=sinTmp;
}

StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["messageType"] = "sensor"; // execute, message, sensor
// execute - send command to other device
// root["targetDeviceID"] = "xxxxx"; //for execute and message message types
// root["actuator"] = "motor1";
// root["actuatorValue"]="222";
// root["actuatorMode"] = "sinus";
// root["command"] = none;
// root["commandParameter1"] ="";

// message - send message to targetDeviceID
// root["message"] = "hello world";

//sensor - for publishing sensor data
root["sensor"] = "mps9250";
// root["time"] = none;
root["fusionedData"] = motionVector;
root["messageNumber"] = 0;
// example for raw data
// JsonArray& rawdata = root.createNestedArray("rawdata"); // x,y,z,roll, pitch better??
// rawdata.add(0, 0); // ax
// rawdata.add(0, 0); // ay
// rawdata.add(0, 0); // az
// rawdata.add(0, 0); // gx
// rawdata.add(0, 0); // gx
// rawdata.add(0, 0); // gx
// rawdata.add(0, 0); // mx
// rawdata.add(0, 0); // mx
// rawdata.add(0, 0); //mx
root["LEDstatus"] = valueLED;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;

// publish motor speed as mqtt message every 10 seconds
// only when motor in not off
if (motorMode==maxMode||motorMode==sinusMode||motorMode==motionMode) {
now = millis();
if (now - lastMsg > 1000) {
if (!mqttclient.connected()) {
reconnect();
}
lastMsg = now;
++value;
root["messageNumber"] = value;
// publish data as MQTT message in JSON format
root.printTo(outMsg, sizeof(outMsg));
snprintf (msg, 1000, "%s",outMsg);
mqttclient.publish("BIoutTopic", msg);
Serial.print("Publish message every 10 sec: ");
Serial.println(msg);
}
}

// Check if a client has connected to the wifi server
WiFiClient espclient = server.available();
if (!espclient) {
return;
}

while(!espclient.available()){
delay(1);
}

// read the first line of the request
String request = espclient.readStringUntil('\r');
espclient.flush();

// LED on button pressed
Serial.println("hi execute rqeuest");
if (request.indexOf("/LED=ON") != -1) {
requesting=true;
digitalWrite(ledPin, HIGH);
valueLED = HIGH;
root["LEDstatus"] = valueLED;
}
// LED off button pressed
if (request.indexOf("/LED=OFF") != -1) {
requesting=true;
digitalWrite(ledPin, LOW);
valueLED = LOW;
root["LEDstatus"] = valueLED;
}
// set motor to maximum speed button pressed
if (request.indexOf("/MOTOR=MAX") != -1) {
requesting=true;
analogWrite(motorPin, 1023);
valueMotor = 1023;
motorMode=maxMode;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;
}
// set motor off button pressed
if (request.indexOf("/MOTOR=OFF") != -1) {
requesting=true;
analogWrite(motorPin, 0);
valueMotor = 0;
motorMode=offMode;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;
}
// motor amplitude controlled like a sinus curve
if (request.indexOf("/MOTOR=SINUS") != -1) {
requesting=true;
motorMode=sinusMode;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;
}
// motor speed is adjusted by movements (classical "body interaction" interaction pattern)
if (request.indexOf("/MOTOR=MOTION") != -1) {
requesting=true;
motorMode=motionMode;
valueMotor=600;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;
}


generateWebpage(espclient);

// send outMessage to Mqtt server
if (requesting) {
requesting=false;
if (!mqttclient.connected()) {
reconnect();
}
++value;

root["messageNumber"] = value;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;

// publish data as MQTT message in JSON format
root.printTo(outMsg, sizeof(outMsg));
snprintf (msg,1000, "%s",outMsg);
mqttclient.publish("BIoutTopic", msg);

Serial.print("Publish message: ");
Serial.println(msg);
}
}

Exploring the internet of (sex) things 1

The internet of things – or short IOT – is getting popular. IOT is a network of physical things like vehicles, buildings, but also everyday objects like lamps, refrigerators. IOT allows objects to be sensed and controlled remotely across the Internet. As a result the physical world will be integrated into the internet and computer systems.

Popular examples are home axiomatization or collection of environmental data.  Even sex toy industry use the internet to connect sex toy users which are far away of each other (like the OhMiBod blueMotion). The vision of remote sex driven by technology is also known as Teledildonics. Unfortunately I didn’t pay much attention to this movement which goes back to 1975. body interaction focused more on wireless connected sex toys for users having sex together and want to integrate his and her’s sex toy. You will find a lot of information at Kyle Machulis site Metafetish. Also have a look at the annual conference Arse Elektronika which focus on the intersection of technology and sex.

In this blog I have already shown how to connect the body interaction development board to the internet. Now I will present some first steps into IOT. I will use the NodeMCU development board which is based on the popular ESP8266 System on a chip. The ESP is a wi-fi enabled microcontroller where you can connect sensors and actuators. It can connect to your wi-fi access point and home and it can be an access point itself and host eg. an internet server.

In my explorations I will try to find out if a IOT sex toy is useful for DIY sex toy community.

In this blog post we will use the ESP8266 as a wi-fi server. The server will connect to your wi-fi access point at home.

The series has 4 parts:

part 1: Exploring the internet of (sex) things

part 2: MQTT messages

part 3: Node-RED

part 4: Building a sex toy dashboard with Node-RED

Building a bread board prototype

nodemcu prototype breadboard

Material needed

  • bread board, wires
  • Node MCU or similar
  • small vibration motor (or LED), eg the Lilipad vibration motor
  • optional: accelerometer  MPU9265
  • optional: another LED and a resistor

WIre MPU9265

mpu-92-65Connect

  • SCL (on MPU9265) and D1 (on NodeMCU),
  • SDA and D2,
  • VCC and 3V3
  • GND and GND

Wire vibration motor

Connect

  • D7 (node MCU) with vibration motor (+) and
  • GND (NodeMCU) and (-)

Wire LED

Connect:

  • D3 (NodeMCU) and LED (long end)
  • LED (short end) and resistor
  • resistor and GND (NodeMCU)

Using the Arduino IDE

NodeMCU and all other ESP8266 boards are not supported by Arduino. But you can use the Arduino board manager to add other development boards. This short Tutorial explains the necessary steps: http://www.instructables.com/id/Quick-Start-to-Nodemcu-ESP8266-on-Arduino-IDE/

Connect the NodeMCU to your access point (WLAN router)

Upload script to NodeMCU

Copy the code below to the Arduino IDE or download and unzip this Arduino “.ino” file.

Within the sketch you have to change the constants SSID and password. Use the same SSID as you would do to connect your smart phone or computer to the internet.

Select your NodeMCU and the port. Connect your computer and the NodeMCU with USB wire. Upload the script to NodeMCU

#include <ESP8266WiFi.h>
#include <Wire.h>

#define MPU9250_ADDRESS 0x68
#define MAG_ADDRESS 0x0C

#define GYRO_FULL_SCALE_250_DPS 0x00
#define GYRO_FULL_SCALE_500_DPS 0x08
#define GYRO_FULL_SCALE_1000_DPS 0x10
#define GYRO_FULL_SCALE_2000_DPS 0x18

#define ACC_FULL_SCALE_2_G 0x00
#define ACC_FULL_SCALE_4_G 0x08
#define ACC_FULL_SCALE_8_G 0x10
#define ACC_FULL_SCALE_16_G 0x18

const char* ssid = "????"; // Enter the name of your Access point
const char* password = "????"; //Enter the password SSID
int ledPin = 0; // NodeMCU pad D3 = GPI0
int motorPin= 13; // NodeMCU pad D7 = GPIO 13
double sinusValue=0;

// define constants for four different vibration modes
const int off_mode=0;
const int max_mode =1;
const int sinus_mode =2;
const int motion_mode =3;

int motor_mode =off_mode;

WiFiServer server(80);

 // This function read Nbytes bytes from I2C device at address Address.
// Put read bytes starting at register Register in the Data array.
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
 // Set register address
 Wire.beginTransmission(Address);
 Wire.write(Register);
 Wire.endTransmission();

 // Read Nbytes
 Wire.requestFrom(Address, Nbytes);
 uint8_t index=0;
 while (Wire.available())
 Data[index++]=Wire.read();
}

// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
 // Set register address
 Wire.beginTransmission(Address);
 Wire.write(Register);
 Wire.write(Data);
 Wire.endTransmission();
}

void setup() {

 Wire.begin();
 // NodeMCU D1 = GPIO5 connected to MCU9265 SCL
 // NodeMCU D2 = GPIO4 connected to MCU9265 SDA
 Wire.pins(5,4);
 Serial.begin(115200);

 // Configure gyroscope range
 I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_2000_DPS);
 // Configure accelerometers range
 I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_16_G);
 // Set by pass mode for the magnetometers
 I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);

 // Request first magnetometer single measurement
 I2CwriteByte(MAG_ADDRESS,0x0A,0x01);

 Serial.begin(115200);
 delay(10);

 pinMode(ledPin, OUTPUT);
 digitalWrite(ledPin, LOW);

 pinMode(motorPin, OUTPUT);
 analogWrite(motorPin, 0);

 // Connect to WiFi network
 Serial.println();
 Serial.println();
 Serial.print("Connecting to ");
 Serial.println(ssid);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 Serial.println("");
 Serial.println("WiFi connected");

 // Start the server
 server.begin();
 Serial.println("Server started");

 // Print the IP address
 Serial.print("Use this URL to connect: ");
 Serial.print("http://");
 Serial.print(WiFi.localIP());
 Serial.println("/");

}

int16_t ax,ay,az,ax1,ay1,az1,gx,gy,gz,gx1,gy1,gz1;
int valueMotor; //vibrator motor speed 0-1023

void loop() {

 // Read accelerometer and gyroscope
 uint8_t Buf[14];
 I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);

 // Create 16 bits values from 8 bits data

 // Accelerometer
 ax=-(Buf[0]<<8 | Buf[1]);
 ay=-(Buf[2]<<8 | Buf[3]);
 az=Buf[4]<<8 | Buf[5];

 // Gyroscope
 gx=-(Buf[8]<<8 | Buf[9]);
 gy=-(Buf[10]<<8 | Buf[11]);
 gz=Buf[12]<<8 | Buf[13];  // when in "motion_mode" the vibration motor 
//is controlled by motion  
if (motor_mode==motion_mode) {  
  int v = 0;  
  //calculate motion vector 
  v=sqrt(pow(ax-ax1,2)+pow(ay-ay1,2)+pow(az-az1,2)); 
 
  // adjust vibration motor speed  
  // if motion vector > 5000 raise speed by 25
  // otherwise lower speed by 10
  // adjust these constants to your needs
  if (v > 5000) {valueMotor=valueMotor+25;} else {valueMotor=valueMotor-10;}
  
  //values must be above 500 otherwise the motor is off 
  if (valueMotor<500) {valueMotor=500;} 
  // values higher than 1023 are not supported
  if (valueMotor>1023) {valueMotor=1023;} 
  analogWrite(motorPin, valueMotor); // set motor speed

  Serial.print("v: ");
  Serial.print(v);
  Serial.print(", valueMotor: ");
  Serial.println(valueMotor);
  delay(200);

  // save values
  ax1=ax;
  ay1=ay;
  az1=az;
  gx1=gx;
  gy1=gy;
  gz1=gz;
 }

 // change vibration motor speed according to a sinus curve
 if (motor_mode==sinus_mode) {
 sinusValue=sinusValue+.01;
 delay(20);
 int sin_tmp = ((sin(sinusValue)+1)*.5*(1023-500))+500;
 Serial.println(sin_tmp);
 analogWrite(motorPin, sin_tmp);
 valueMotor=sin_tmp;
 }

 // Check if a client has connected
 WiFiClient client = server.available();
 if (!client) {
 return;
 }

 // Wait until the client sends some data
 Serial.println("new client");
 while(!client.available()){
 delay(1);
 }

 // Read the first line of the request
 String request = client.readStringUntil('\r');
 Serial.println(request);
 client.flush();

 // Match the request

 int valueLED = LOW;
 if (request.indexOf("/LED=ON") != -1) {
 digitalWrite(ledPin, HIGH);
 valueLED = HIGH;
 }
 if (request.indexOf("/LED=OFF") != -1) {
 digitalWrite(ledPin, LOW);
 valueLED = LOW;
 }

 if (request.indexOf("/MOTOR=MAX") != -1) {
 analogWrite(motorPin, 1023);
 valueMotor = 1023;
 motor_mode=max_mode;
 }
 if (request.indexOf("/MOTOR=OFF") != -1) {
 analogWrite(motorPin, 0);
 valueMotor = 0;
 motor_mode=off_mode;
 }

 if (request.indexOf("/MOTOR=SINUS") != -1) {
 motor_mode=sinus_mode;
 }

 if (request.indexOf("/MOTOR=MOTION") != -1) {
 motor_mode=motion_mode;
 valueMotor=600;
 }

 // Return the response
 client.println("HTTP/1.1 200 OK");
 client.println("Content-Type: text/html");
 client.println(""); // do not forget this one
 client.println("<!DOCTYPE HTML>");
 client.println("<html>");

 client.print("Led pin is now: ");

 if(valueLED == HIGH) {
 client.print("On");
 } else {
 client.print("Off");
 }

 client.print("Motor pin is now: ");
 client.print(valueMotor);

 client.println("");
 client.println("<a href=\"/LED=ON\"\"><button>Turn On </button></a>");
 client.println("<a href=\"/LED=OFF\"\"><button>Turn Off </button></a>");
 client.println("<a href=\"/MOTOR=MAX\"\"><button>Motor Max </button></a>");
 client.println("<a href=\"/MOTOR=OFF\"\"><button>Motor Off </button></a>");
 client.println("<a href=\"/MOTOR=SINUS\"\"><button>Motor sinus curve </button></a>");
 client.println("<a href=\"/MOTOR=MOTION\"\"><button>Motor motion controlled </button></a>");
 client.println("</html>");

 delay(1);
 Serial.println("Client disonnected");
 Serial.println("");

}

Controlling the vibrator prototype

After uploading the script above, open the serial monitor. After some time the NodeMCU will report “wifi connected”.

IOT wifi connectdNow start a browser. Use the URL which the NodeMCU reported eg. http://192.168.1.12/

If your smart phone is connected to the same Access point as your computer is, you can use your smart phone to control the prototype, too.

You can turn the LED on or off by pressing the “Turn On” and “Turn Off” buttons.

For controlling the motor you have 4 options

  • motor on
  • motor off
  • sinus curve (the motor will speed up and slow down according to a sinus curve)
  • motion controlled (more motion -> motor speeds up)

Summary

To build a vibrator prototype based on the ESP8266 MCU is very easy. You can use your Arduino IDE to upload scripts to the prototype. Then you can control the vibration motor through a browser. If you don’t want to use these external control options the vibrator prototype can be controlled by motion similar to the body interaction vibrator development board.

In this blog post series we will  explore other interesting features of the ESP8266:

  • the ESP8266 as an access point (no need for private or public access points)
  • over the air (OTA) uploading of sketches  (wireless – no USB connector needed)
  • MQTT protocol & server
  • Node-RED (visual IOT programming)
  • review of development boards for building IOT vibrators

Go to the second part of the tutorial.

%d bloggers like this: