HomeMadeGarbage
Published

BLE Toy Train Controlled by Smartphone

I made train controlled by smart phone using 100 ten toy train and BLE board.

AdvancedFull instructions provided20 hours2,420
BLE Toy Train Controlled by Smartphone

Things used in this project

Hardware components

100Yen Toy Train
×3
RedBear BLE Nano
×1
Motor Driver DRV8830
×1
SG90 Micro-servo motor
SG90 Micro-servo motor
×1
3.7 V LiPo Battery
×1

Software apps and online services

Arduino IDE
Arduino IDE
Android Studio
Android Studio

Story

Read more

Schematics

Diagram

Code

moterDriveBLEnano00.ino

Arduino
#include <Wire.h>
//#include "I2Cdev.h"
#include <BLE_API.h>
#include <Servo.h> 
 
Servo myservo; 
const int DRV8830 = 0x64;

int power = 0;
int angle = 0;
int rot = 0;

#define TXRX_BUF_LEN    20

BLE     ble;
Timeout timeout;                

static uint8_t rx_buf[TXRX_BUF_LEN];
static uint8_t rx_buf_num;

// The Nordic UART Service
static const uint8_t service1_uuid[]                = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_tx_uuid[]             = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t service1_rx_uuid[]             = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[]           = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};

uint8_t tx_value[TXRX_BUF_LEN] = {0,};
uint8_t rx_value[TXRX_BUF_LEN] = {0,};

int speed1 = 0;
int iniState = 0;
int angleRx_ini = 35;
int angleRx = angleRx_ini;

GattCharacteristic  characteristic1(service1_tx_uuid, tx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE );

GattCharacteristic  characteristic2(service1_rx_uuid, rx_value, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

GattCharacteristic *uartChars[] = {&characteristic1, &characteristic2};

GattService         uartService(service1_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));

// I2C motor driver I2C
//Reference
//http://makers-with-myson.blog.so-net.ne.jp/2014-05-15
void writeMotorResister(byte vset, byte data1){
  int vdata = vset << 2 | data1;
  Wire.beginTransmission(DRV8830);
  Wire.write(0x00);
  Wire.write(vdata);
  Wire.endTransmission(true);
  //delay(10);
}


void disconnectionCallBack(Gap::Handle_t handle, Gap::DisconnectionReason_t reason){
  Serial.println("Disconnected!");
  Serial.println("Restarting the advertising process");
  iniState = 0;
  ble.startAdvertising();
}

// data Rx
void writtenHandle(const GattWriteCallbackParams *Handler){
  uint8_t buf[TXRX_BUF_LEN];
  uint16_t bytesRead, index;

  //Serial.println("onDataWritten : ");
  if (Handler->handle == characteristic1.getValueAttribute().getHandle()) {
    ble.readCharacteristicValue(characteristic1.getValueAttribute().getHandle(), buf, &bytesRead);

    if (buf[0] == 'c') {
      iniState = 1;
      power = buf[1];
      angle = buf[2];
      rot = buf[3];
    }
  }
  speed1 = map(power, 0, 100, 5, 19);
  angleRx = map(angle, 0, 180, 0, angleRx_ini * 2);

  if (rot == 2){
    Serial.print("Forward  ");
  }
  if (rot == 1){
    Serial.print("Reverse  ");
  }
  Serial.print("power: ");
  Serial.print(power);
  Serial.print("  ");
  Serial.print("angle: ");
  Serial.println(angle);
}

//data Tx
void m_uart_rx_handle(){
  rx_buf_num = 1;
  rx_buf[0] = 's';
  ble.updateCharacteristicValue(characteristic2.getValueAttribute().getHandle(), rx_buf, rx_buf_num);   
  memset(rx_buf, 0x00,1);
  delay(500);
  Serial.println("Tx: s");
}

void setup() {   
  Wire.begin(D3, D2, 400000L);
  Serial.begin(250000);
  writeMotorResister(0x00, 0x00);
  //writeMotorResister(0x80, 0x00);
  BLEset();

  myservo.attach(D4);
  myservo.write(angleRx);
  
}

void loop() {
  //delay(300);
  if(iniState == 0){
    m_uart_rx_handle();
  }
  
  if (power >= 0 && power < 45){
    angleRx = angleRx_ini;
  }
  
  if (power == 0){
    writeMotorResister(0x00, 0x00);
  }else {
    writeMotorResister((byte)speed1, (byte)rot);
  }
  myservo.write(angleRx); 

  delay(15);
}



//BLE 
void BLEset() {
  ble.init();
  ble.onDisconnection(disconnectionCallBack);
  ble.onDataWritten(writtenHandle);
  
  // setup adv_data and srp_data
  ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
 
  ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                     (const uint8_t *)"motor", sizeof("motor") - 1);
  ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                     (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid_rev));
                
  // set adv_type
  ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);    
  // add service
  ble.addService(uartService);
  // set device name
  ble.setDeviceName((const uint8_t *)"Simple Chat");
  // set tx power,valid values are -40, -20, -16, -12, -8, -4, 0, 4
  ble.setTxPower(4);
  // set adv_interval, 100ms in multiples of 0.625ms.
  ble.setAdvertisingInterval(160);
  // set adv_timeout, in seconds
  ble.setAdvertisingTimeout(0);
  // start advertising
  ble.startAdvertising();

  Serial.println("Advertising Start!"); 
}

Ctl.java

Java
package com.redbear.moterDrive_BLEnano02;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import android.app.Activity;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;

import com.developwear.joystickview.JoystickView;

public class Ctl extends Activity {
	private final static String TAG = Ctl.class.getSimpleName();

	public static final String EXTRAS_DEVICE = "EXTRAS_DEVICE";
	private TextView tv = null;
	private JoystickView jsv;

	private String mDeviceName;
	private String mDeviceAddress;
	private RBLService mBluetoothLeService;
	private Map<UUID, BluetoothGattCharacteristic> map = new HashMap<UUID, BluetoothGattCharacteristic>();

	private int bleState = 0;

	private final ServiceConnection mServiceConnection = new ServiceConnection() {

		@Override
		public void onServiceConnected(ComponentName componentName,
				IBinder service) {
			mBluetoothLeService = ((RBLService.LocalBinder) service)
					.getService();
			if (!mBluetoothLeService.initialize()) {
				Log.e(TAG, "Unable to initialize Bluetooth");
				finish();
			}

			// Automatically connects to the device upon successful start-up
			// initialization.
			mBluetoothLeService.connect(mDeviceAddress);
		}

		@Override
		public void onServiceDisconnected(ComponentName componentName) {

			mBluetoothLeService = null;
		}
	};

	private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			final String action = intent.getAction();

			if (RBLService.ACTION_GATT_DISCONNECTED.equals(action)) {
				tv.setText("Ready..");
				bleState = 0;
			} else if (RBLService.ACTION_GATT_SERVICES_DISCOVERED
					.equals(action)) {
				getGattService(mBluetoothLeService.getSupportedGattService());
			} else if (RBLService.ACTION_DATA_AVAILABLE.equals(action)) {
				//Data Rx
				byte[] RxData = intent.getByteArrayExtra(RBLService.EXTRA_DATA);
				if(RxData[0] == 's'){
					tv.setText("Start!!");
					bleState = 1;
				}
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.second);

		tv = (TextView) findViewById(R.id.textView);

		//Joy Stick
		//https://github.com/clkasd/JoystickView
		jsv = (JoystickView)findViewById(R.id.joystickview);
		jsv.setJoystickChangeListener(new JoystickView.JoystickChangeListener() {
			@Override
			public void onJoystickChanged(int power, int degree) {
				Log.v("power", String.valueOf(String.valueOf(power)));
				Log.v("degree", String.valueOf(String.valueOf(degree)));
				sendJoyStick(power, degree);
			}
		});

		Intent intent = getIntent();

		mDeviceAddress = intent.getStringExtra(Device.EXTRA_DEVICE_ADDRESS);
		mDeviceName = intent.getStringExtra(Device.EXTRA_DEVICE_NAME);

		getActionBar().setTitle(mDeviceName);
		getActionBar().setDisplayHomeAsUpEnabled(true);

		Intent gattServiceIntent = new Intent(this, RBLService.class);
		bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
	}

	@Override
	protected void onResume() {
		super.onResume();

		registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == android.R.id.home) {
			mBluetoothLeService.disconnect();
			mBluetoothLeService.close();

			System.exit(0);
		}

		return super.onOptionsItemSelected(item);
	}

	@Override
	protected void onStop() {
		super.onStop();

		unregisterReceiver(mGattUpdateReceiver);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();

		mBluetoothLeService.disconnect();
		mBluetoothLeService.close();

		System.exit(0);
	}

	private void getGattService(BluetoothGattService gattService) {
		if (gattService == null)
			return;

		BluetoothGattCharacteristic characteristic = gattService
				.getCharacteristic(RBLService.UUID_BLE_SHIELD_TX);
		map.put(characteristic.getUuid(), characteristic);

		BluetoothGattCharacteristic characteristicRx = gattService
				.getCharacteristic(RBLService.UUID_BLE_SHIELD_RX);
		mBluetoothLeService.setCharacteristicNotification(characteristicRx,
				true);
		mBluetoothLeService.readCharacteristic(characteristicRx);
	}

	private static IntentFilter makeGattUpdateIntentFilter() {
		final IntentFilter intentFilter = new IntentFilter();

		intentFilter.addAction(RBLService.ACTION_GATT_CONNECTED);
		intentFilter.addAction(RBLService.ACTION_GATT_DISCONNECTED);
		intentFilter.addAction(RBLService.ACTION_GATT_SERVICES_DISCOVERED);
		intentFilter.addAction(RBLService.ACTION_DATA_AVAILABLE);

		return intentFilter;
	}

	//Data Tx
	public void sendJoyStick(int pow, int deg){
		BluetoothGattCharacteristic characteristic = map
				.get(RBLService.UUID_BLE_SHIELD_TX);

		byte[] bytes = new byte[4];
		bytes[0]='c';
		bytes[1]=(byte)pow;
		bytes[2]=(byte)(Math.abs(deg)); //
		if(deg < 0){
			bytes[3] = 1; //
		}else{
			bytes[3] = 2; //
		}

		characteristic.setValue(bytes);

		if(bleState == 1){
			mBluetoothLeService.writeCharacteristic(characteristic);
		}
	}
}

second.xml

Java
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:weightSum="1">

    <TextView
        android:id="@+id/textView"
        android:layout_width="256dp"
        android:layout_height="50dp"
        android:scrollbars="vertical"
        android:textSize="30dp"
        android:text="Ready..." />

    <com.developwear.joystickview.JoystickView
        android:id="@+id/joystickview"
        android:layout_width="700px"
        android:layout_height="700px"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center_horizontal" />

</LinearLayout>

build.gradle (Module: app)

Java
apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.hmg.moterdrive_blenano02"
        minSdkVersion 21
        targetSdkVersion 21
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

dependencies {
    compile 'com.android.support:support-v4:21.0.0'
    compile 'com.developwear:joystickviewlib:1.0.1'
}

Credits

HomeMadeGarbage

HomeMadeGarbage

56 projects • 285 followers
We are family. hobby is D.I.Y!!

Comments