MIn
Created May 4, 2021

Slouching Detector Glasses

The slouching detector glasses is a smart wearable that works with PCs, Phones and Smart Watches to correct the users posture.

210

Things used in this project

Hardware components

nRF5340 Development Kit
Nordic Semiconductor nRF5340 Development Kit
nRF 5340 DK is useful to debug software since it has on-board SEGGER J-LINK debugger. It also convenient to connect sensor without soldering. We received free kit from Nordic Semiconductor.
×1
nRF52840 Multi-Protocol SoC
Nordic Semiconductor nRF52840 Multi-Protocol SoC
nrf52840 dongle. It's also free from Nordic Semiconductor
×1
6 DOF Sensor - MPU6050
DFRobot 6 DOF Sensor - MPU6050
it's also available on eBay, amazon.
×1
Jumper wires (generic)
Jumper wires (generic)
male to female jumper wires
×1

Software apps and online services

Nordic Semiconductor nRF Connect for Desktop
Nordic Semiconductor nRF Connect for Mobile
three.js
Putty
React JS
React Native
nRF Connect SDK
Nordic Semiconductor nRF Connect SDK
It can be installed from nRF connect for Desktop. It includes all the tools for developing and debugging firmware. Plus, SEGGER Embedded Studio with free license!

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Code

Motion Sensor

C/C++
for nRF5340 or nRF52840
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <sys/printk.h>
#include <sys/byteorder.h>
#include <zephyr.h>
#include <device.h>
#include <drivers/sensor.h>
#include <drivers/gpio.h>
#include <logging/log.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>

LOG_MODULE_REGISTER(main);
static int period_ms = 500;
static const struct device *mpu6050;
/* Prototype */
static ssize_t recv(struct bt_conn *conn,
					const struct bt_gatt_attr *attr, const void *buf,
					uint16_t len, uint16_t offset, uint8_t flags);

/* ST Custom Service  */
static struct bt_uuid_128 st_service_uuid = BT_UUID_INIT_128(
	0x00, 0x00, 0x25, 0x66, 0xdc, 0x38, 0x5c, 0xae,
	0xeb, 0x4a, 0xe5, 0x33, 0x24, 0x38, 0x67, 0x42);

/* ST  service */
static struct bt_uuid_128 service_name_uuid = BT_UUID_INIT_128(
	0x01, 0x00, 0x25, 0x66, 0xdc, 0x38, 0x5c, 0xae,
	0xeb, 0x4a, 0xe5, 0x33, 0x24, 0x38, 0x67, 0x42);

/* ST Notify button service */
static struct bt_uuid_128 but_notif_uuid = BT_UUID_INIT_128(
	0x02, 0x00, 0x25, 0x66, 0xdc, 0x38, 0x5c, 0xae,
	0xeb, 0x4a, 0xe5, 0x33, 0x24, 0x38, 0x67, 0x42);

static uint8_t vnd_value[] = { 'M', 'P', 'U', '6', '0', '5', '0' };

static ssize_t read_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr,
			void *buf, uint16_t len, uint16_t offset)
{
	const char *value = attr->user_data;

	return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
				 strlen(value));
}

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
#define ADV_LEN 12

/* Advertising data */
static uint8_t manuf_data[ADV_LEN] = {
	0x01 /*SKD version */,
	0x83 /* STM32WB - P2P Server 1 */,
	0x00 /* GROUP A Feature  */,
	0x00 /* GROUP A Feature */,
	0x00 /* GROUP B Feature */,
	0x00 /* GROUP B Feature */,
	0x00, /* BLE MAC start -MSB */
	0x00,
	0x00,
	0x00,
	0x00,
	0x00, /* BLE MAC stop */
};

static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	//BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
	// BT_DATA(BT_DATA_MANUFACTURER_DATA, manuf_data, ADV_LEN)
	BT_DATA_BYTES(BT_DATA_UUID128_ALL,
	0x00, 0x00, 0x25, 0x66, 0xdc, 0x38, 0x5c, 0xae,
	0xeb, 0x4a, 0xe5, 0x33, 0x24, 0x38, 0x67, 0x42),
	};

/* BLE connection */
struct bt_conn *conn;
/* Notification state */
volatile bool notify_enable;
int notify();

void my_work_handler(struct k_work *work)
{
	/* do the processing that needs to be done periodically */
	int err;
	if (conn)
	{
		if (notify_enable)
		{
			if (!mpu6050)
			{
				const char *const label = DT_LABEL(DT_INST(0, invensense_mpu6050));
				mpu6050 = device_get_binding(label);
			}
			if (!mpu6050)
			{
				printf("Failed to find sensor\n");
				return;
			}
			int rc = process_mpu6050(mpu6050);

			if (err)
			{
				LOG_ERR("Notify error: %d", err);
			}
			else
			{
				LOG_INF("Send notify ok");
			}
		}
		else
		{
			LOG_INF("Notify not enabled");
		}
	}
	else
	{
		LOG_INF("BLE not connected");
	}
}

K_WORK_DEFINE(my_work, my_work_handler);

void my_timer_handler(struct k_timer *dummy)
{
	k_work_submit(&my_work);
}

K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);

static void mpu_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
	ARG_UNUSED(attr);
	notify_enable = (value == BT_GATT_CCC_NOTIFY);
	LOG_INF("Notification %s", notify_enable ? "enabled" : "disabled");
	/* start periodic timer that expires once every second */
	if (notify_enable)
		k_timer_start(&my_timer, K_MSEC(period_ms), K_MSEC(period_ms));
	else
		k_timer_stop(&my_timer);
}

static ssize_t read_ct(struct bt_conn *conn, const struct bt_gatt_attr *attr,
					   void *buf, uint16_t len, uint16_t offset)
{
	const char *value = attr->user_data;
	LOG_INF("read notify freq: %d ms", period_ms);
	return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
							 sizeof(period_ms));
}

static ssize_t write_ct(struct bt_conn *conn, const struct bt_gatt_attr *attr,
						const void *buf, uint16_t len, uint16_t offset,
						uint8_t flags)
{
	uint8_t *value = attr->user_data;

	if (offset + len > sizeof(period_ms))
	{
		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
	}
	memset(value, 0, sizeof(period_ms));
	memcpy(value + offset, buf, len);
	LOG_INF("change notify freq: %d ms", period_ms);
        if (notify_enable && k_timer_remaining_get(&my_timer) > 0) {
            k_timer_stop(&my_timer);
            k_timer_start(&my_timer, K_MSEC(period_ms), K_MSEC(period_ms));
        } 
	return len;
}
/* The embedded board is acting as GATT server.
 * The ST BLE Android app is the BLE GATT client.
 */

/* ST BLE Sensor GATT services and characteristic */

BT_GATT_SERVICE_DEFINE(stsensor_svc,
BT_GATT_PRIMARY_SERVICE(&st_service_uuid),
BT_GATT_CHARACTERISTIC(&service_name_uuid.uuid,
		       BT_GATT_CHRC_READ,
		       BT_GATT_PERM_READ, read_vnd, NULL, vnd_value),
BT_GATT_CHARACTERISTIC(&but_notif_uuid.uuid, 
                        BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_WRITE,
                        BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
                        read_ct, write_ct, &period_ms),
BT_GATT_CCC(mpu_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), 
);


static void bt_ready(int err)
{
	if (err)
	{
		LOG_ERR("Bluetooth init failed (err %d)", err);
		return;
	}
	LOG_INF("Bluetooth initialized");
	/* Start advertising */
	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0);
	if (err)
	{
		LOG_ERR("Advertising failed to start (err %d)", err);
		return;
	}

	LOG_INF("Configuration mode: waiting connections...");
}

static void connected(struct bt_conn *connected, uint8_t err)
{
	if (err)
	{
		LOG_ERR("Connection failed (err %u)", err);
	}
	else
	{
		LOG_INF("Connected");
		if (!conn)
		{
			conn = bt_conn_ref(connected);
		}
	}
}

static void disconnected(struct bt_conn *disconn, uint8_t reason)
{
	if (conn)
	{
		bt_conn_unref(conn);
		conn = NULL;
	}

	LOG_INF("Disconnected (reason %u)", reason);
}

static struct bt_conn_cb conn_callbacks = {
	.connected = connected,
	.disconnected = disconnected,
};



int process_mpu6050(const struct device *dev)
{
	struct sensor_value temperature;
	struct sensor_value accel[3];
	struct sensor_value gyro[3];
	int rc = sensor_sample_fetch(dev);

	if (rc == 0)
	{
		rc = sensor_channel_get(dev, SENSOR_CHAN_ACCEL_XYZ,
								accel);
	}
	if (rc == 0)
	{
		rc = sensor_channel_get(dev, SENSOR_CHAN_GYRO_XYZ,
								gyro);
	}
	if (rc == 0)
	{
		rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP,
								&temperature);
	}
	if (rc == 0)
	{

                int8_t data[48];
                int pos=0;
                int len=sizeof(struct sensor_value);
    
                memcpy(&data[pos], &accel[0], len); pos+=len;
                memcpy(&data[pos], &accel[1], len); pos+=len;
                memcpy(&data[pos], &accel[2], len); pos+=len;
                memcpy(&data[pos], &gyro[0], len); pos+=len;
                memcpy(&data[pos], &gyro[1], len); pos+=len;
                memcpy(&data[pos], &gyro[2], len); pos+=len;
                bt_gatt_notify(NULL, &stsensor_svc.attrs[3], data, sizeof(data));

		//bt_gatt_notify(NULL, &stsensor_svc.attrs[3], &str, len);
	}
	else
	{
		printf("sample fetch/get failed: %d\n", rc);
		//char buf[] = "error";
		//bt_gatt_notify(NULL, &stsensor_svc.attrs[3], &buf, sizeof(buf));
	}

	return rc;
}



void main(void)
{
	int err;

	bt_conn_cb_register(&conn_callbacks);

	/* Initialize the Bluetooth Subsystem */
	err = bt_enable(bt_ready);
	if (err)
	{
		LOG_ERR("Bluetooth init failed (err %d)", err);
	}
}

web app

Credits

MIn

MIn

2 projects • 0 followers

Comments