Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

loadcell_part

from bluetooth import *
import threading
from matplotlib import pyplot as plt
from matplotlib import animation
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import time
import struct
import matplotlib
from matplotlib import font_manager
from datetime import datetime

# 사용자 및 환경 정보
USER_INFO = {
    "User": "Kang Jeongtae",
    "Age": 25,
    "Weight": 70,
    "Height": 175,
    "Gender": "Male",
    "Activity Level": "Regular Exercise"
}

ENVIRONMENT_INFO = {
    "Location": "Indoor",
    "Floor Type": "Wood",
    "Shoe Type": "Running Shoes",
    "Temperature": "22°C",
    "Humidity": "55%"
}

SENSOR_INFO = {
    "Sensor Model": "XYZ-1000",
    "Firmware Version": "v1.2.0",
    "Device ID": "123456789"
}

# 폰트 경로 설정
font_path = '/usr/share/fonts/truetype/msttcorefonts/times.ttf'
prop = font_manager.FontProperties(fname=font_path)
matplotlib.use("Qt5Agg")

global foot_total, foot_left, foot_right, client_sock1, client_sock2
foot_left = [0, 0, 0, 0]
foot_right = [0, 0, 0, 0]
max_retries = 10
retry_count = 0

def connect_device(mac_address):
    for _ in range(10):
        try:
            client_sock = BluetoothSocket(RFCOMM)
            client_sock.connect((mac_address, 1))
            print(f"Bluetooth connected to {mac_address}")
            return client_sock
        except BluetoothError as e:
            print(f"Bluetooth Error: {e}")
            time.sleep(1)
    print("Connection Timeout")
    sys.exit()

def initialize_log(file_name):
    with open(file_name, 'w') as f:
        f.write("# User Information\n")
        for key, value in USER_INFO.items():
            f.write(f"{key}: {value}\n")
        f.write("\n# Environment Information\n")
        for key, value in ENVIRONMENT_INFO.items():
            f.write(f"{key}: {value}\n")
        f.write("\n# Sensor Metadata\n")
        for key, value in SENSOR_INFO.items():
            f.write(f"{key}: {value}\n")
        f.write("\n# Measurement Data\n")
        f.write("# Timestamp | Side | Sensor 1 | Sensor 2 | Sensor 3 | Sensor 4\n")

def log_data(file_name, side, sensor_values):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open(file_name, 'a') as f:
        f.write(f"{timestamp} | {side} | {' | '.join(map(str, sensor_values))}\n")

def receive_data(sock, side, log_file):
    global foot_left, foot_right
    while True:
        try:
            data = sock.recv(1 + 4 * 4 + 1 + 1)  # 1(Header) + 16(float*4) + 1(Checksum) + 1(Footer)
            if len(data) != 19:
                print("Incomplete packet received")
                continue
            
            # Header/Footer 확인
            header, footer = data[0], data[-1]
            if header != 0xAA or footer != 0x55:
                print("Invalid Header/Footer")
                continue
            
            # 데이터와 체크섬 추출
            payload = data[1:17]  # 16 bytes (4 floats)
            received_checksum = data[17]
            
            # 체크섬 검증
            calculated_checksum = 0
            for b in payload:
                calculated_checksum ^= b
            
            if calculated_checksum != received_checksum:
                print("Checksum mismatch")
                continue
            
            # 4개의 float 데이터 언패킹
            sensor_values = struct.unpack('ffff', payload)
            if side == 'left':
                foot_left = sensor_values
            else:
                foot_right = sensor_values
            log_data(log_file, side, sensor_values)
            print(f"{side.capitalize()} Sensor Values: {sensor_values}")
        
        except Exception as e:
            print(f"Data receive error: {e}")
            break

log_file = "foot_pressure_log.txt"
initialize_log(log_file)

client_sock1 = connect_device("98:DA:60:04:CA:0C")
client_sock2 = connect_device("98:DA:60:07:D8:33")

device1 = threading.Thread(target=receive_data, args=(client_sock1, 'left', log_file))
device2 = threading.Thread(target=receive_data, args=(client_sock2, 'right', log_file))
device1.start()
device2.start()

fig = plt.figure()
plt.rc("font", family="times new roman")

# 왼쪽 센서 히트맵
ax1 = plt.subplot(221)
divider = make_axes_locatable(ax1)
cax1 = divider.append_axes('right', size='5%', pad=0.05)
line1 = ax1.matshow(np.zeros([2,2]), cmap='jet', vmin=0, vmax=30000)
ax1.axis('off')
plt.colorbar(line1, cax=cax1)

def animate_left(i):
    global foot_left
    list1 = np.array([[foot_left[0], foot_left[1]], [foot_left[2], foot_left[3]]])
    line1.set_array(list1)
    return line1

# 오른쪽 센서 히트맵
ax2 = plt.subplot(222)
divider = make_axes_locatable(ax2)
cax2 = divider.append_axes('right', size='5%', pad=0.05)
line2 = ax2.matshow(np.zeros([2,2]), cmap='jet', vmin=0, vmax=30000)
ax2.axis('off')
plt.colorbar(line2, cax=cax2)

def animate_right(i):
    global foot_right
    list2 = np.array([[foot_right[0], foot_right[1]], [foot_right[2], foot_right[3]]])
    line2.set_array(list2)
    return line2

anim1 = animation.FuncAnimation(fig, animate_left, frames=1, interval=100)
anim2 = animation.FuncAnimation(fig, animate_right, frames=1, interval=100)

plt.tight_layout()
plt.show()
#include <HX711.h>

/*
 Example using the SparkFun HX711 breakout board with a scale
 By: Nathan Seidle
 SparkFun Electronics
 Date: November 19th, 2014
 License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

 This is the calibration sketch. Use it to determine the calibration_factor that the main example uses. It also
 outputs the zero_factor useful for projects that have a permanent mass on the scale in between power cycles.

 Setup your scale and start the sketch WITHOUT a weight on the scale
 Once readings are displayed place the weight on the scale
 Press +/- or a/z to adjust the calibration_factor until the output readings match the known weight
 Use this calibration_factor on the example sketch

 This example assumes pounds (lbs). If you prefer kilograms, change the Serial.print(" lbs"); line to kg. The
 calibration factor will be significantly different but it will be linearly related to lbs (1 lbs = 0.453592 kg).

 Your calibration factor may be very positive or very negative. It all depends on the setup of your scale system
 and the direction the sensors deflect from zero state
 This example code uses bogde's excellent library: https://github.com/bogde/HX711
 bogde's library is released under a GNU GENERAL PUBLIC LICENSE
 Arduino pin 2 -> HX711 CLK
 3 -> DOUT
 5V -> VCC
 GND -> GND

 Most any pin on the Arduino Uno will be compatible with DOUT/CLK.

 The HX711 board can be powered from 2.7V to 5V so the Arduino 5V power should be fine.

*/
// ============================== BLE 사용을 위한 헤더 선언 및 PIN 설정
#include <SoftwareSerial.h> // 소프트웨어를 통해 직렬 통신(Serial Communication)을 구현하는 라이브러리
#include <String.h> // 문자열 처리 라이브러리

SoftwareSerial bluetooth(2, 3); // 블루투스 모듈을 선언합니다.
// ============================== BLE

#include "HX711.h"

HX711 scale[4]; //HX711 scale(DOUT, CLK);
//double calibration_factor[4] = {-18350, -17550, -17350, -16550}; //-7050 worked for my 440lb max scale setup (back up!!!)
double calibration_factor[4] = {-15350, -15050, -14850, -14850}; //-7050 worked for my 440lb max scale setup (60kg set)
double loadcell_data[4] = {0};

void setup() {
  Serial.begin(9600);
  bluetooth.begin(9600);

  // scale's DOUT and SCK begin roof ( scale[0] <DOUT> 4, <SCK> 5 -> ... -> scale[3] 10, 11 )
  for(int begin_scales = 0; begin_scales < 4; begin_scales++ ){
    scale[begin_scales].begin((begin_scales+2)*2 /*LOADCELL_DOUT_PIN*/ , (begin_scales+2)*2+1 /*LOADCELL_SCK_PIN*/ );
  }

  // massage 1 // WILL EDIT... 
  Serial.println("HX711 calibration sketch");
  Serial.println("Remove all weight from scale");
  Serial.println("After readings begin, place known weight on scale");
  Serial.println("Press + or a to increase calibration factor");
  Serial.println("Press - or z to decrease calibration factor");

  // scale's scale data reset roof
  for(int reset_scales = 0; reset_scales < 4; reset_scales++){
    scale[reset_scales].set_scale(calibration_factor[reset_scales]);
    scale[reset_scales].tare(); //Reset the scale to 0
  }

  long zero_factor[4] = {0};
  for(int view = 0 ; view < 4 ; view++ ){
    zero_factor[view]=scale[view].read_average();
    Serial.print("Zero factor ["); Serial.print(view); Serial.print("] : "); //This can be used to remove the need to tare the scale. Useful in permanent scale projects.
    Serial.println(zero_factor[view]);
  }
  // delay(150);
}

void GetLoadcellData(void){ // 로드셀 데이터 불러오기
  for(int cali = 0 ; cali < 4 ; cali++){
    loadcell_data[cali] = scale[cali].get_units()*0.453592; // 로드셀 데이터를 kg으로 환산하는 코드 밎 출력
    if(loadcell_data[cali]<0) loadcell_data[cali]=-loadcell_data[cali]; // 음수 값을 양수로 바꾸어주는 연산을 진행. 
  }
}

void ViewLoadcellPlotter(){ // 측정된 load 데이터를 IDE에서 플로터 형태로 모니터에 출력
  for(int serial_plotter = 0 ; serial_plotter < 4 ; serial_plotter++){
    Serial.print((loadcell_data[serial_plotter]));
    Serial.print(",");
  }
  Serial.println("");
}

/*
void BluetoothDataSend(void){ // [BLE] 블루투스로 FSR 데이터 값 보내기.
  // bluetooth.println(String(int(loadcell_data[0]*1000))+"@"+String(int(loadcell_data[1]*1000))+"@"+String(int(loadcell_data[2]*1000))+"@"+String(int(loadcell_data[3]*1000))+"@"); // 문자형으로 데이터를 보내고 있음.

  char dataToSend[50]; // 충분히 큰 배열 선언
  for(int i = 0; i < 4; i++) {
    sprintf(dataToSend + strlen(dataToSend), "%d@", int(loadcell_data[i] * 1000));
  }
  bluetooth.println(dataToSend);
  
}
*/

/*
void BluetoothDataSend(void) { 
  // BLE로 Raw Data 전송
  for (int i = 0; i < 4; i++) {
    float value = loadcell_data[i]; // 현재 센서 값
    bluetooth.write((uint8_t*)&value, sizeof(float)); // float 데이터를 Raw 바이너리로 전송
  }
}
*/

void BluetoothDataSend(void) { 
  uint8_t buffer[sizeof(float) * 4 + 2]; // 4개의 float + Header + Footer

  buffer[0] = 0xAA; // Header
  memcpy(&buffer[1], &loadcell_data[0], sizeof(float) * 4); // float 데이터 복사
  buffer[sizeof(float) * 4 + 1] = 0x55; // Footer

  // 버퍼를 한 번에 전송
  bluetooth.write(buffer, sizeof(buffer));
}


void BluetoothDataSend(void) { 
  uint8_t header = 0xAA;  // 패킷 시작
  uint8_t footer = 0x55;  // 패킷 끝

  bluetooth.write(&header, 1);  // 헤더 전송
  
  for (int i = 0; i < 4; i++) {
    float value = loadcell_data[i];
    bluetooth.write((uint8_t*)&value, sizeof(float));  // float 데이터를 RAW로 전송
  }

  uint8_t checksum = 0;
  for (int i = 0; i < 4; i++) {
    checksum ^= (uint8_t)(loadcell_data[i]);  // 간단한 XOR 체크섬
  }
  bluetooth.write(&checksum, 1);  // 체크섬 전송
  
  bluetooth.write(&footer, 1);  // 푸터 전송
}

void readLoadCell(int index) {
  loadcell_data[index] = scale[index].get_units()*0.453592;
}

int loopCount = 0;
unsigned long timeStart;
unsigned long timeEnd;

unsigned long lastReadTime[4] = {0, 0, 0, 0};
const unsigned long readInterval = 1; // 1ms 간격으로 데이터 읽기

void loop() {
  timeStart = millis();
  // GetLoadcellData(); // ============================== Loadcell 데이터 불러오기
  for (int i = 0; i < 4; i++) {
    if (millis() - lastReadTime[i] > readInterval) {
      readLoadCell(i);
      lastReadTime[i] = millis();
    }
  }
  timeEnd = millis();
  Serial.print(timeEnd-timeStart);
  Serial.println(" <- GetLoadcellData");

  // timeStart = millis();
  // ViewLoadcellPlotter(); // ============================== Loadcell 데이터를 Serial Plotter로 출력 함수
  // timeEnd = millis();
  // Serial.print(timeEnd-timeStart);
  // Serial.println(" <- ViewLoadcellPlotter");

  timeStart = millis();
  BluetoothDataSend(); // ============================== BLE 데이터 전송 코드
  timeEnd = millis();
  Serial.print(timeEnd-timeStart);
  Serial.println(" <- BluetoothDataSend");
}

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors