Infineon Team
Published © MIT

Robotic Haptics by 3D Magnetic Sensor

Meet the robotic hand that feels your touch, thanks to Infineon’s 3D hall-effect sensors and the XMC1400 Kit 2Go!

IntermediateFull instructions provided7 hours445
Robotic Haptics by 3D Magnetic Sensor

Things used in this project

Hardware components

Infineon XMC1400 2GO KIT
Infineon XMC1400 2GO KIT
×1
Infineon XENSIV™ - TLE493D-W2B6 A0
Infineon XENSIV™ - TLE493D-W2B6 A0
×3

Software apps and online services

Arduino IDE
Arduino IDE
Thonny

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)
Magnets, Button
Magnets, Button

Story

Read more

Custom parts and enclosures

3D Hand by Openbionics-Mid hand-

File missing, please reupload.

Schematics

Schematics

Code

Visualization Code

Python
import serial
import time
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap

# Set up the serial line
ser = serial.Serial('COM8', 115200)  # Replace 'COM5' with your actual COM port
time.sleep(2)  # Wait for the connection to establish

# Example positions of the sensors on a hand (x, y coordinates)
sensor_positions = [(1, 6), (3.7, 8.8), (5.8, 9.2)] # Adjust these based on actual positions

# Load the image of the hand
hand_image = plt.imread('./hand_image1.png')  # Replace with the path to your hand image

# Create a figure and axis for plotting
fig, ax = plt.subplots()

# Display the hand image as the background
ax.imshow(hand_image, extent=(0, 10, 0, 10), alpha=0.7)  # Adjust the extent to match your heatmap size

# Create a custom colormap from light/transparent red to mid-red to very bright red
colors = [(1, 0, 0, 0.1), (1, 0, 0, 0.5), (1, 0, 0, 1)]  # Light/transparent red to mid-red to very bright red
n_bins = 100  # Discretize into 100 steps
cmap_name = 'light_to_bright_red'
cm = LinearSegmentedColormap.from_list(cmap_name, colors, N=n_bins)

def update_heatmap(sensor_values):
    # Clear the axis
    ax.clear()
    
    # Display the hand image again
    ax.imshow(hand_image, extent=(0, 10, 0, 10), alpha=0.5)
    
    # Set fixed min and max values for normalization
    data_min = 0
    data_max = 14
    
    # Convert sensor_values to a numpy array for vectorized operations
    sensor_values = np.array(sensor_values)
    
    # Normalize sensor values to [0, 1] for colormap
    normalized_values = (sensor_values - data_min) / (data_max - data_min)
    
    # Create a scatter plot with circles
    for (x, y), value in zip(sensor_positions, normalized_values):
        ax.scatter(x, y, color=cm(value), s=300, edgecolor='k')  # Increased size to 300 for larger circles
    
    plt.draw()
    plt.pause(0.01)  # Pause to allow the plot to update

# Real-time data reading and plotting
try:
    plt.ion()  # Turn on interactive mode
    while True:
        data = ser.readline().decode('utf-8').strip()  # Read the serial data
        if data:
            print(f"Received: {data}")
            sensor_values = list(map(float, data.split("\t")))  # Parse sensor values
            update_heatmap(sensor_values)
except KeyboardInterrupt:
    print("Exiting...")
finally:
    ser.close()  # Close the serial connection

Arduino code

Arduino
#include "TLx493D_inc.hpp"

using namespace ifx::tlx493d;

TLx493D_W2B6 dut1(Wire, TLx493D_IIC_ADDR_A0_e);
TLx493D_W2B6 dut2(Wire, TLx493D_IIC_ADDR_A0_e);
TLx493D_W2B6 dut3(Wire, TLx493D_IIC_ADDR_A0_e);

// Define the number of calibration samples
const int CALIBRATION_SAMPLES = 10;

// Offsets for calibration
double xOffset1 = 0, yOffset1 = 0, zOffset1 = 0;
double xOffset2 = 0, yOffset2 = 0, zOffset2 = 0;
double xOffset3 = 0, yOffset3 = 0, zOffset3 = 0;

void setup() {
    Serial.begin(115200);
    delay(3000);

    Serial.println("Starting setup...");

    dut1.setPowerPin(5, OUTPUT, INPUT, HIGH, LOW, 0, 250000);
    dut2.setPowerPin(4, OUTPUT, INPUT, HIGH, LOW, 0, 250000);
    dut3.setPowerPin(8, OUTPUT, INPUT, HIGH, LOW, 0, 250000);

    Serial.println("Power Pins set");

    if (dut1.begin(true, false, false, true)) {
        dut1.setIICAddress(TLx493D_IIC_ADDR_A2_e);
        dut1.printRegisters();
        Serial.println("DUT1 initialized");
    } else {
        Serial.println("DUT1 initialization failed");
    }

    if (dut2.begin()) {
        dut2.setIICAddress(TLx493D_IIC_ADDR_A1_e);
        dut2.printRegisters();
        Serial.println("DUT2 initialized");
    } else {
        Serial.println("DUT2 initialization failed");
    }

    if (dut3.begin()) {
        dut3.printRegisters();
        Serial.println("DUT3 initialized");
    } else {
        Serial.println("DUT3 initialization failed");
    }

    Serial.println("Setup done.");

    // Perform calibration
    calibrateSensors();

    Serial.println("Calibration completed.");
}

void calibrateSensors() {
    double sumX1 = 0, sumY1 = 0, sumZ1 = 0;
    double sumX2 = 0, sumY2 = 0, sumZ2 = 0;
    double sumX3 = 0, sumY3 = 0, sumZ3 = 0;

    for (int i = 0; i < CALIBRATION_SAMPLES; ++i) {
        double temp;
        double valX, valY, valZ;

        // Sensor 1
        dut1.getMagneticFieldAndTemperature(&valX, &valY, &valZ, &temp);
        sumX1 += valX;
        sumY1 += valY;
        sumZ1 += valZ;

        // Sensor 2
        dut2.getMagneticFieldAndTemperature(&valX, &valY, &valZ, &temp);
        sumX2 += valX;
        sumY2 += valY;
        sumZ2 += valZ;

        // Sensor 3
        dut3.getMagneticFieldAndTemperature(&valX, &valY, &valZ, &temp);
        sumX3 += valX;
        sumY3 += valY;
        sumZ3 += valZ;

        delay(10); // Adjust delay as needed
    }

    // Calculate average offsets
    xOffset1 = sumX1 / CALIBRATION_SAMPLES;
    yOffset1 = sumY1 / CALIBRATION_SAMPLES;
    zOffset1 = sumZ1 / CALIBRATION_SAMPLES;

    xOffset2 = sumX2 / CALIBRATION_SAMPLES;
    yOffset2 = sumY2 / CALIBRATION_SAMPLES;
    zOffset2 = sumZ2 / CALIBRATION_SAMPLES;

    xOffset3 = sumX3 / CALIBRATION_SAMPLES;
    yOffset3 = sumY3 / CALIBRATION_SAMPLES;
    zOffset3 = sumZ3 / CALIBRATION_SAMPLES;
}

void loop() {
    double temp1 = 0.0, temp2 = 0.0, temp3 = 0.0;
    double valX1 = 0, valY1 = 0, valZ1 = 0, valX2 = 0, valY2 = 0, valZ2 = 0, valX3 = 0, valY3 = 0, valZ3 = 0;

    dut1.getMagneticFieldAndTemperature(&valX1, &valY1, &valZ1, &temp1);
    dut2.getMagneticFieldAndTemperature(&valX2, &valY2, &valZ2, &temp2);
    dut3.getMagneticFieldAndTemperature(&valX3, &valY3, &valZ3, &temp3);

    // Apply offsets to get calibrated values
    valX1 -= xOffset1;
    valY1 -= yOffset1;
    valZ1 -= zOffset1;

    valX2 -= xOffset2;
    valY2 -= yOffset2;
    valZ2 -= zOffset2;

    valX3 -= xOffset3;
    valY3 -= yOffset3;
    valZ3 -= zOffset3;

    // Calculate the magnitude of the magnetic field for each sensor
    double mag1 = sqrt(pow(valX1, 2) + pow(valY1, 2) + pow(valZ1, 2));
    double mag2 = sqrt(pow(valX2, 2) + pow(valY2, 2) + pow(valZ2, 2));
    double mag3 = sqrt(pow(valX3, 2) + pow(valY3, 2) + pow(valZ3, 2));

    // Print the magnitudes for the Serial Plotter
    Serial.print(mag1); Serial.print("\t");
    Serial.print(mag2); Serial.print("\t");
    Serial.println(mag3);

    delay(300); // Adjust delay as needed
}

Credits

Infineon Team
100 projects • 157 followers
Contact
Thanks to openbionics.

Comments

Please log in or sign up to comment.