Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Aditya SiddheshwarRaghavendra N.VAmitabh Sharma
Created September 5, 2024

eTTS

A solution for assisting visually impaired individuals using Spatial Audio, and Text-to-Speech (TTS)

32
eTTS

Things used in this project

Story

Read more

Code

Spatial Audio

Python
Creates Spatial Audio which can be played on Bluetooth Earphones to indicate directions.
from pydub import AudioSegment
from pydub.playback import play

# Load your audio file
sound = AudioSegment.from_file("tic-tac-27828.mp3", format="mp3")

# Create spatial audio for each direction
sound_right = sound.pan(+1)  # Right
sound_left = sound.pan(-1)   # Left
sound_up = sound.apply_gain(10)  # Up (increase volume)
sound_down = sound.apply_gain(-10) # Down (decrease volume)

# Save the spatial audio files
sound_right.export("right.mp3", format="mp3")
sound_left.export("left.mp3", format="mp3")
sound_up.export("up.mp3", format="mp3")
sound_down.export("down.mp3", format="mp3")

ESP32 Xiao client + TTS + Notecard

Python
Takes image from Xiao, pass it to OCR and then give TTS output. Also sends this text to cloud through Notecard.
import cv2 # run this on Linux PC with opencv-python module

import easyocr

from gtts import gTTS
import pygame
import os

from collections import deque
import uuid

import json
import notecard
# Use PySerial on a desktop
import serial

COM_PORT = "COM9"
BAUD_RATE = 9600
port = serial.Serial(port=COM_PORT, baudrate=BAUD_RATE)
card = notecard.OpenSerial(port)
print("Notecard connected")

reader = easyocr.Reader(['en']) 
dropped = 0 # drop frames count

# Create a directory to store audio files
audio_dir = "temp_audio_files"
os.makedirs(audio_dir, exist_ok=True)

# Initialize a deque to act as our stack
word_stack = deque()

# Function to generate a unique filename
def get_unique_filename():
    return os.path.join(audio_dir, f"{uuid.uuid4()}.mp3")

# Function to process and play audio
def process_and_play_audio(text):
    filename = get_unique_filename()
    max_attempts = 3
    for attempt in range(max_attempts):
        try:
            tts = gTTS(text, lang='en')
            tts.save(filename)
            word_stack.append(filename)
            break
        except Exception as e:
            print(f"Attempt {attempt + 1} failed to save audio: {str(e)}")
            if attempt == max_attempts - 1:
                print("Failed to process audio after maximum attempts")
                return

# Function to play audio files from the stack
def play_audio_stack():
    while word_stack:
        try:
            filename = word_stack.popleft()
            pygame.mixer.music.load(filename)
            pygame.mixer.music.play()
            while pygame.mixer.music.get_busy():
                pygame.time.Clock().tick(10)
            pygame.mixer.music.unload()
            os.remove(filename)
        except Exception as e:
            print(f"Error playing or removing file: {str(e)}")

# Initialize pygame mixer
pygame.mixer.init()

#vid = cv2.VideoCapture('rtsp://ali78:Tvbfu781@192.168.4.44:80') # 

# 192.168.4.44 - esp32cam
#vid = cv2.VideoCapture('http://192.168.4.44/ali/Baba40Robrs') # open webcam capture

# 192.168.4.70 - XIAO esp32s3
vid = cv2.VideoCapture('http://192.168.72.49/xiao/password')  # open webcam capture

skip_length = 50 # to avoid delay in processing
frame_counter = 0  
while True:
    ret, frame = vid.read() # get frame-by-frame
    #print(vid.isOpened(), ret)

    if frame is not None:
        frame_counter += 1

        if frame_counter % skip_length == 0: # skip every 
            ocr_results = reader.readtext(frame)
            for (bbox, text, prob) in ocr_results:
                (top_left, top_right, bottom_right, bottom_left) = bbox
                top_left = (int(top_left[0]), int(top_left[1]))
                bottom_right = (int(bottom_right[0]), int(bottom_right[1]))
                cv2.rectangle(frame, top_left, bottom_right, (0, 255, 0), 2)
                cv2.putText(frame, text, (top_left[0], top_left[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2, cv2.LINE_AA)
                
                # Construct a JSON Object to add a Note to the Notecard
                req = {"req": "note.add"}
                req["sync"] = True
                req["body"] = {"text": text}

                rsp = card.Transaction(req)
                print(rsp) # {"total":1}

                print(text)

                # Process and store audio file
                process_and_play_audio(text)

            

    # if frame is not None:
        if dropped > 0: dropped = 0 # reset

        # Play audio files from the stack
        play_audio_stack()
        cv2.imshow('Video-44',frame) # display frame

        if cv2.waitKey(22) & 0xFF == ord('q'): # press q to quit
            break
    else:
        dropped += 1
        if dropped > 100:
           print("Server is down")
           break

# Done, clear all resources
vid.release()
cv2.destroyAllWindows()

# Remove any remaining temporary files
for filename in os.listdir(audio_dir):
    try:
        os.remove(os.path.join(audio_dir, filename))
    except Exception as e:
        print(f"Error removing file {filename}: {str(e)}")

os.rmdir(audio_dir)

print("Video stop")

Nordic Record NFC

C/C++
Example: Tap on the NFC antenna with phone to blink.
/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <zephyr/kernel.h>
#include <zephyr/sys/reboot.h>

#include <nfc_t2t_lib.h>
#include <nfc/ndef/msg.h>
#include <nfc/ndef/text_rec.h>

#include <dk_buttons_and_leds.h>

#define MAX_REC_COUNT		3
#define NDEF_MSG_BUF_SIZE	128

#define NFC_FIELD_LED		DK_LED1

/* Text message in English with its language code. */
static const uint8_t en_payload[] = {
	'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'
};
static const uint8_t en_code[] = {'e', 'n'};

/* Text message in Norwegian with its language code. */
static const uint8_t no_payload[] = {
	'H', 'a', 'l', 'l', 'o', ' ', 'V', 'e', 'r', 'd', 'e', 'n', '!'
};
static const uint8_t no_code[] = {'N', 'O'};

/* Text message in Polish with its language code. */
static const uint8_t pl_payload[] = {
	'W', 'i', 't', 'a', 'j', ' ', 0xc5, 0x9a, 'w', 'i', 'e', 'c', 'i',
	'e', '!'
};
static const uint8_t pl_code[] = {'P', 'L'};

/* Buffer used to hold an NFC NDEF message. */
static uint8_t ndef_msg_buf[NDEF_MSG_BUF_SIZE];


static void nfc_callback(void *context,
			 nfc_t2t_event_t event,
			 const uint8_t *data,
			 size_t data_length)
{
	ARG_UNUSED(context);
	ARG_UNUSED(data);
	ARG_UNUSED(data_length);

	switch (event) {
	case NFC_T2T_EVENT_FIELD_ON:
		dk_set_led_on(NFC_FIELD_LED);
		break;
	case NFC_T2T_EVENT_FIELD_OFF:
		dk_set_led_off(NFC_FIELD_LED);
		break;
	default:
		break;
	}
}


/**
 * @brief Function for encoding the NDEF text message.
 */
static int welcome_msg_encode(uint8_t *buffer, uint32_t *len)
{
	int err;

	/* Create NFC NDEF text record description in English */
	NFC_NDEF_TEXT_RECORD_DESC_DEF(nfc_en_text_rec,
				      UTF_8,
				      en_code,
				      sizeof(en_code),
				      en_payload,
				      sizeof(en_payload));

	/* Create NFC NDEF text record description in Norwegian */
	NFC_NDEF_TEXT_RECORD_DESC_DEF(nfc_no_text_rec,
				      UTF_8,
				      no_code,
				      sizeof(no_code),
				      no_payload,
				      sizeof(no_payload));

	/* Create NFC NDEF text record description in Polish */
	NFC_NDEF_TEXT_RECORD_DESC_DEF(nfc_pl_text_rec,
				      UTF_8,
				      pl_code,
				      sizeof(pl_code),
				      pl_payload,
				      sizeof(pl_payload));

	/* Create NFC NDEF message description, capacity - MAX_REC_COUNT
	 * records
	 */
	NFC_NDEF_MSG_DEF(nfc_text_msg, MAX_REC_COUNT);

	/* Add text records to NDEF text message */
	err = nfc_ndef_msg_record_add(&NFC_NDEF_MSG(nfc_text_msg),
				   &NFC_NDEF_TEXT_RECORD_DESC(nfc_en_text_rec));
	if (err < 0) {
		printk("Cannot add first record!\n");
		return err;
	}
	err = nfc_ndef_msg_record_add(&NFC_NDEF_MSG(nfc_text_msg),
				   &NFC_NDEF_TEXT_RECORD_DESC(nfc_no_text_rec));
	if (err < 0) {
		printk("Cannot add second record!\n");
		return err;
	}
	err = nfc_ndef_msg_record_add(&NFC_NDEF_MSG(nfc_text_msg),
				   &NFC_NDEF_TEXT_RECORD_DESC(nfc_pl_text_rec));
	if (err < 0) {
		printk("Cannot add third record!\n");
		return err;
	}

	err = nfc_ndef_msg_encode(&NFC_NDEF_MSG(nfc_text_msg),
				      buffer,
				      len);
	if (err < 0) {
		printk("Cannot encode message!\n");
	}

	return err;
}


int main(void)
{
	uint32_t len = sizeof(ndef_msg_buf);

	printk("Starting NFC Text Record example\n");

	/* Configure LED-pins as outputs */
	if (dk_leds_init() < 0) {
		printk("Cannot init LEDs!\n");
		goto fail;
	}

	/* Set up NFC */
	if (nfc_t2t_setup(nfc_callback, NULL) < 0) {
		printk("Cannot setup NFC T2T library!\n");
		goto fail;
	}


	/* Encode welcome message */
	if (welcome_msg_encode(ndef_msg_buf, &len) < 0) {
		printk("Cannot encode message!\n");
		goto fail;
	}


	/* Set created message as the NFC payload */
	if (nfc_t2t_payload_set(ndef_msg_buf, len) < 0) {
		printk("Cannot set payload!\n");
		goto fail;
	}


	/* Start sensing NFC field */
	if (nfc_t2t_emulation_start() < 0) {
		printk("Cannot start emulation!\n");
		goto fail;
	}
	printk("NFC configuration done\n");

	return 0;

fail:
#if CONFIG_REBOOT
	sys_reboot(SYS_REBOOT_COLD);
#endif /* CONFIG_REBOOT */

	return -EIO;
}

Credits

Aditya Siddheshwar

Aditya Siddheshwar

1 project • 1 follower
Raghavendra N.V

Raghavendra N.V

4 projects • 3 followers
Amitabh Sharma

Amitabh Sharma

2 projects • 1 follower

Comments