← Quay lại Blog
airobot-armai-perceptionresearch

Tactile Sensing: Cảm biến xúc giác cho robot manipulation

Tìm hiểu công nghệ cảm biến xúc giác — từ resistive, capacitive đến vision-based tactile và ứng dụng trong gắp vật thể mềm.

Nguyễn Anh Tuấn17 tháng 3, 202610 phút đọc
Tactile Sensing: Cảm biến xúc giác cho robot manipulation

Tại sao robot cần cảm biến xúc giác?

Cảm biến xúc giác (tactile sensing) là mảnh ghép còn thiếu để robot manipulation đạt được sự khéo léo như bàn tay người. Hãy nghĩ thử: bạn có thể nhặt quả trứng mà không bóp vỡ, cảm nhận được vải mượt hay thô — tất cả nhờ hàng nghìn mechanoreceptor trên da. Robot hiện tại chủ yếu dựa vào camera (vision) và force/torque sensor, nhưng thiếu thông tin cục bộ tại điểm tiếp xúc: hình dạng bề mặt, trượt (slip), và phân bố lực.

Bài viết này tổng hợp các công nghệ tactile sensing hiện đại, so sánh ưu nhược điểm, và hướng dẫn tích hợp vào hệ thống robot ROS 2.

Cảm biến xúc giác gắn trên gripper robot

Phân loại cảm biến xúc giác

1. Resistive (Điện trở)

Nguyên lý: Khi bị nén, vật liệu dẫn điện thay đổi điện trở. Đo sự thay đổi này để suy ra lực.

Ví dụ tiêu biểu: FSR (Force Sensing Resistor), Velostat-based sensor

Ưu điểm: Rẻ, dễ chế tạo, có thể làm mảng (array) lớn.

Nhược điểm: Hysteresis cao, drift theo thời gian, độ phân giải thấp.

# Đọc FSR sensor qua ADC (Arduino + Python Serial)
import serial
import struct

class FSRReader:
    def __init__(self, port='/dev/ttyUSB0', n_sensors=16):
        self.ser = serial.Serial(port, 115200, timeout=0.1)
        self.n_sensors = n_sensors

    def read_force_array(self):
        """Đọc mảng lực từ 4x4 FSR grid."""
        self.ser.write(b'R')  # Request reading
        data = self.ser.read(self.n_sensors * 2)
        if len(data) == self.n_sensors * 2:
            values = struct.unpack(f'<{self.n_sensors}H', data)
            # Chuyển ADC value (0-1023) sang Newton
            forces = [self.adc_to_newton(v) for v in values]
            return forces
        return None

    @staticmethod
    def adc_to_newton(adc_value, v_ref=3.3, r_ref=10000):
        """Chuyển đổi ADC sang lực (Newton) dựa trên datasheet FSR."""
        if adc_value < 10:
            return 0.0
        voltage = adc_value * v_ref / 1023.0
        resistance = r_ref * (v_ref / voltage - 1)
        # Xấp xỉ từ datasheet FSR 402
        force = 1.0 / (resistance / 1000.0)
        return min(force, 20.0)  # Giới hạn 20N

2. Capacitive (Điện dung)

Nguyên lý: Hai bản cực song song cách nhau bởi lớp dielectric mềm. Khi bị nén, khoảng cách giảm, điện dung tăng.

Ví dụ tiêu biểu: BioTac (SynTouch), DigiTacts

Ưu điểm: Độ nhạy cao, ít drift, đo được cả normal và shear force.

Nhược điểm: Dễ bị nhiễu EMI, cần mạch đọc phức tạp, đắt.

3. Piezoelectric (Áp điện)

Nguyên lý: Vật liệu piezoelectric (PVDF, PZT) sinh điện áp khi bị biến dạng.

Ưu điểm: Đáp ứng cực nhanh (microseconds), phát hiện rung động và slip tốt.

Nhược điểm: Chỉ đo thay đổi lực (dynamic), không đo lực tĩnh. Phù hợp cho phát hiện slip hơn là đo lực liên tục.

4. Vision-based Tactile (GelSight)

Nguyên lý: Camera bên trong nhìn lên bề mặt gel mềm được sơn phản xạ. Khi vật thể ép vào gel, camera chụp ảnh biến dạng — từ đó reconstruct hình dạng 3D và force distribution.

Ví dụ tiêu biểu: GelSight, DIGIT, GelSlim, Tactile

Ưu điểm: Độ phân giải spatial cực cao (sub-mm), đo được geometry + force + texture cùng lúc.

Nhược điểm: Kích thước lớn hơn các loại khác, tốc độ phụ thuộc camera framerate, cần xử lý ảnh.

GelSight sensor cho robot manipulation

Bảng so sánh các công nghệ

Đặc tính Resistive Capacitive Piezoelectric Vision-based
Độ phân giải Thấp (5-10mm) Trung bình (1-3mm) Trung bình (2-5mm) Cao (<0.1mm)
Tốc độ ~100 Hz ~1 kHz >10 kHz 30-60 Hz
Đo shear Không Hạn chế
Đo geometry Không Không Không
Giá thành Rất thấp Cao Trung bình Trung bình
Kích thước Mỏng Mỏng Mỏng Cồng kềnh
Ứng dụng chính Grasping basic Dexterous hand Slip detection Research, precision

Tích hợp với ROS 2

Custom message cho tactile data

# tactile_msgs/msg/TactileArray.msg
# (Tạo custom message trong ROS 2 package)

# Header
std_msgs/Header header

# Sensor metadata
string sensor_type          # "fsr", "capacitive", "gelsight"
uint32 rows                 # Số hàng taxel
uint32 cols                 # Số cột taxel

# Force data (row-major order)
float32[] forces            # Normal force mỗi taxel (Newton)
float32[] shear_x           # Shear force X (nếu có)
float32[] shear_y           # Shear force Y (nếu có)

# Contact detection
bool in_contact             # Có đang tiếp xúc không
float32 total_force         # Tổng lực (Newton)
geometry_msgs/Point center_of_pressure  # Tâm áp lực

Publisher node cho tactile sensor

import rclpy
from rclpy.node import Node
from std_msgs.msg import Header
import numpy as np

class TactileSensorNode(Node):
    def __init__(self):
        super().__init__('tactile_sensor')

        # Publisher
        self.pub = self.create_publisher(
            TactileArray, '/tactile/left_finger', 10
        )

        # Sensor reader
        self.sensor = FSRReader(port='/dev/ttyUSB0', n_sensors=16)

        # Timer: 50Hz
        self.timer = self.create_timer(0.02, self.publish_tactile)

        self.get_logger().info('Tactile sensor node started (50Hz)')

    def publish_tactile(self):
        forces = self.sensor.read_force_array()
        if forces is None:
            return

        msg = TactileArray()
        msg.header = Header()
        msg.header.stamp = self.get_clock().now().to_msg()
        msg.header.frame_id = 'left_finger_link'

        msg.sensor_type = 'fsr'
        msg.rows = 4
        msg.cols = 4
        msg.forces = [float(f) for f in forces]

        # Tính contact info
        total = sum(forces)
        msg.in_contact = total > 0.1  # Threshold 0.1N
        msg.total_force = float(total)

        # Center of pressure
        if msg.in_contact:
            force_grid = np.array(forces).reshape(4, 4)
            rows_idx, cols_idx = np.meshgrid(
                range(4), range(4), indexing='ij'
            )
            msg.center_of_pressure.x = float(
                np.sum(cols_idx * force_grid) / total
            )
            msg.center_of_pressure.y = float(
                np.sum(rows_idx * force_grid) / total
            )

        self.pub.publish(msg)

rclpy.init()
node = TactileSensorNode()
rclpy.spin(node)

Deep Learning cho Tactile Sensing

CNN trên GelSight images

Vision-based tactile sensor như GelSight tạo ra ảnh — và ảnh thì CNN xử lý rất tốt. Các bài toán phổ biến:

  1. Contact geometry estimation: Reconstruct 3D shape từ tactile image
  2. Slip detection: Phát hiện vật đang trượt trước khi rơi
  3. Material classification: Phân loại vật liệu (kim loại, nhựa, vải...)
  4. Grasp stability prediction: Dự đoán gắp có ổn định không
import torch
import torch.nn as nn
import torchvision.transforms as transforms

class TactileCNN(nn.Module):
    """
    CNN phân loại grasp stability từ GelSight image.
    Input: 224x224 RGB tactile image
    Output: probability of stable grasp
    """
    def __init__(self):
        super().__init__()

        self.features = nn.Sequential(
            # Block 1
            nn.Conv2d(3, 32, kernel_size=5, padding=2),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(2),

            # Block 2
            nn.Conv2d(32, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2),

            # Block 3
            nn.Conv2d(64, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.AdaptiveAvgPool2d((7, 7)),
        )

        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(128 * 7 * 7, 256),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(256, 1),
            nn.Sigmoid(),
        )

    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x

# Training pipeline
def train_tactile_model(train_loader, epochs=50, lr=1e-3):
    model = TactileCNN()
    optimizer = torch.optim.Adam(model.parameters(), lr=lr)
    criterion = nn.BCELoss()

    for epoch in range(epochs):
        model.train()
        total_loss = 0
        correct = 0
        total = 0

        for images, labels in train_loader:
            optimizer.zero_grad()
            outputs = model(images).squeeze()
            loss = criterion(outputs, labels.float())
            loss.backward()
            optimizer.step()

            total_loss += loss.item()
            predicted = (outputs > 0.5).long()
            correct += (predicted == labels).sum().item()
            total += labels.size(0)

        acc = correct / total * 100
        print(f'Epoch {epoch+1}/{epochs} — '
              f'Loss: {total_loss/len(train_loader):.4f}, '
              f'Acc: {acc:.1f}%')

    return model

Transfer Learning với pre-trained models

Một kỹ thuật hiệu quả khi ít data: dùng ResNet pre-trained trên ImageNet, fine-tune trên tactile images. Mặc dù domain khác nhau hoàn toàn, các feature low-level (edges, textures) vẫn hữu ích.

import torchvision.models as models

def create_tactile_classifier(num_classes=2):
    """Fine-tune ResNet18 cho tactile classification."""
    model = models.resnet18(pretrained=True)

    # Freeze early layers
    for param in list(model.parameters())[:-20]:
        param.requires_grad = False

    # Thay classifier head
    model.fc = nn.Sequential(
        nn.Linear(512, 128),
        nn.ReLU(),
        nn.Dropout(0.3),
        nn.Linear(128, num_classes),
    )
    return model

Nghiên cứu mới nhất

Các công trình gần đây đáng chú ý trong lĩnh vực tactile sensing:

Deep learning xử lý dữ liệu cảm biến cho robot

Ứng dụng: Gắp vật thể mềm

Thách thức

Gắp vật mềm (rau quả, bánh mì, linh kiện điện tử mềm) khó hơn vật cứng nhiều:

Giải pháp: Tactile-based grasp controller

class TactileGraspController:
    """
    Controller gắp vật mềm dựa trên tactile feedback.
    Tăng lực từ từ cho đến khi detect stable contact.
    """
    def __init__(self, gripper, tactile_sensor):
        self.gripper = gripper
        self.sensor = tactile_sensor

        # Thông số
        self.force_increment = 0.1    # Newton mỗi bước
        self.max_force = 5.0          # Newton tối đa
        self.stable_threshold = 0.5   # Newton tối thiểu
        self.slip_threshold = 0.3     # Ngưỡng phát hiện trượt

    def adaptive_grasp(self, target_force=2.0):
        """
        Gắp adaptive: tăng lực từ từ, dừng khi đủ ổn định.
        """
        current_force = 0.0

        while current_force < self.max_force:
            # Tăng lực gripper
            current_force += self.force_increment
            self.gripper.set_force(current_force)

            # Đợi ổn định (50ms)
            import time
            time.sleep(0.05)

            # Đọc tactile
            tactile_data = self.sensor.read_force_array()
            total_contact = sum(tactile_data)

            # Kiểm tra đã đủ lực chưa
            if total_contact >= target_force:
                print(f'Stable grasp at {current_force:.1f}N '
                      f'(contact: {total_contact:.1f}N)')
                return True

        print('WARNING: Max force reached without stable grasp')
        return False

    def monitor_slip(self, callback_on_slip):
        """
        Giám sát slip liên tục.
        Khi phát hiện trượt, gọi callback để tăng lực.
        """
        prev_forces = None

        while True:
            forces = self.sensor.read_force_array()
            if prev_forces is not None:
                # Tính force change rate
                delta = np.array(forces) - np.array(prev_forces)
                change_rate = np.linalg.norm(delta)

                if change_rate > self.slip_threshold:
                    print(f'Slip detected! Change rate: {change_rate:.2f}')
                    callback_on_slip()

            prev_forces = forces
            time.sleep(0.02)  # 50 Hz

Hướng phát triển tương lai

Tactile sensing đang phát triển rất nhanh với một số xu hướng nổi bật:

Nếu bạn muốn xây dựng robot arm có khả năng manipulation, bước đầu tiên là hiểu inverse kinematics để điều khiển chính xác vị trí gripper. Sau đó, thêm tactile sensing để gripper "cảm nhận" được vật thể.

Bài viết liên quan

Bài viết liên quan

IROS 2026: Papers navigation và manipulation đáng theo dõi
researchconferencerobotics

IROS 2026: Papers navigation và manipulation đáng theo dõi

Phân tích papers nổi bật về autonomous navigation và manipulation — chuẩn bị cho IROS 2026 Pittsburgh.

2/4/20267 phút đọc
Sim-to-Real Transfer: Train simulation, chạy thực tế
ai-perceptionresearchrobotics

Sim-to-Real Transfer: Train simulation, chạy thực tế

Kỹ thuật chuyển đổi mô hình từ simulation sang robot thật — domain randomization, system identification và best practices.

1/4/202612 phút đọc
IROS 2026 Preview: Những gì đáng chờ đợi
researchconferencerobotics

IROS 2026 Preview: Những gì đáng chờ đợi

IROS 2026 Pittsburgh — preview workshops, competitions và nghiên cứu navigation, manipulation hàng đầu.

30/3/20267 phút đọc