# Load Cell

Load cells measure force/weight to detect object presence, evaluate structural loading, or monitor mechanical stress. The system supports dual load cell configuration.

### Hardware Specifications

<table id="bkmrk-parametervaluesensor"><colgroup><col></col><col></col></colgroup><tbody><tr><th>Parameter

</th><th>Value

</th></tr><tr><td>Sensor Count

</td><td>2 (independent)

</td></tr><tr><td>Interface

</td><td>Analog ADC

</td></tr><tr><td>Measurement

</td><td>Force (Newtons) / Mass (grams)

</td></tr><tr><td>Update Rate

</td><td>Configurable

</td></tr></tbody></table>

## Data Structure

```c
typedef struct {
    // Raw Reading
    int32_t raw_counts;                 // ADC value from sensor
    
    // Converted Measurements
    float force_newtons;                // Force in Newtons (N)
    float mass_grams;                   // Equivalent mass in grams (g)
    
    // Calibration Parameters
    float scale_newtons_per_count;      // Conversion factor (N/count)
    int32_t tare_offset_counts;         // Zero-load ADC offset
    
    // Status
    bool is_calibrated;                 // Calibration valid flag
} load_cell_data_t;
```

## Initialization

### Initialize Load Cells

```c
load_cell_data_t load_cell_data[2];  // Support 2 sensors

for (size_t i = 0; i < 2; i++) {
    load_cell_sensor_init(&load_cell_data[i]);
}
```

### Poll Load Cell Sensor

```c
result_t lc_result = poll_load_cell_sensor(&load_cell_data[0]);

if (lc_result == RESULT_OK) {
    float force = load_cell_data[0].force_newtons;
    float mass = load_cell_data[0].mass_grams;
    int32_t raw = load_cell_data[0].raw_counts;
}
```

## Data Access Functions

```c
// Get force in Newtons
result_t load_cell_get_force_newtons(
    const load_cell_data_t *data,
    float *force_newtons
);

// Get mass in grams (estimated)
result_t load_cell_get_mass_grams(
    const load_cell_data_t *data,
    float *mass_grams
);

// Get raw ADC counts
result_t load_cell_get_raw_counts(
    const load_cell_data_t *data,
    int32_t *raw_counts
);

// Get calibration parameters
result_t load_cell_get_calibration(
    const load_cell_data_t *data,
    float *scale_newtons_per_count,
    int32_t *tare_offset_counts
);

// Verify sensor validity
result_t load_cell_sensor_is_valid(
    const load_cell_data_t *data,
    bool *is_valid
);
```

## Calibration Procedure

### Two-Step Calibration

#### Step 1: Tare (Zero Load)

```
1. Remove all load from sensor
2. Measure ADC value: ADC_zero
3. Set tare_offset_counts = ADC_zero
```

#### Step 2: Span (Known Weight)

```
1. Place known weight on sensor
2. Measure ADC value: ADC_loaded
3. Know reference force: F_ref (Newtons)

4. Calculate scale:
   scale = (F_ref - 0.0) / (ADC_loaded - ADC_zero)
   
5. Set scale_newtons_per_count = scale
```

### Measurement Formulas

```c
// Raw force calculation
Force = (raw_counts - tare_offset_counts) × scale_newtons_per_count

// Mass conversion (approximate)
Mass_grams = (Force_newtons / 9.81) × 1000
           ≈ Force_newtons × 102.04
```

## Dual Sensor Management

### Configuration Example

```c
// Initialize both sensors
for (size_t i = 0; i < 2; i++) {
    load_cell_sensor_init(&load_cell_data[i]);
}

// Poll both in sequence
poll_load_cell_sensor(&load_cell_data[0]);
poll_load_cell_sensor(&load_cell_data[1]);

// Access by index
float load_0 = load_cell_data[0].force_newtons;
float load_1 = load_cell_data[1].force_newtons;
```

## Protobuf Message Format

```protobuf
message SensorBoardLoadCellInfo {
    uint32 sensor_index;         // 0 or 1
    float force_newtons;
    float mass_grams;
    SensorState state;
    LoadCellErrorCode error_code;
}
```

## Unit Conversions

<table id="bkmrk-fromtofactornewtonsk"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr><th>From

</th><th>To

</th><th>Factor

</th></tr><tr><td>Newtons

</td><td>kilograms-force (kgf)

</td><td>÷ 9.81

</td></tr><tr><td>Newtons

</td><td>pounds-force (lbf)

</td><td>÷ 4.448

</td></tr><tr><td>grams

</td><td>kilograms

</td><td>÷ 1000

</td></tr></tbody></table>

### Manual Unit Conversion Example

```c
// Convert to pounds-force
float force_lbf = load_cell_data[0].force_newtons / 4.448f;

// Convert to kilograms
float mass_kg = load_cell_data[0].mass_grams / 1000.0f;
```

## Typical Specifications

<table id="bkmrk-load-cell-typemax-lo"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr><th>Load Cell Type

</th><th>Max Load

</th><th>Accuracy

</th></tr><tr><td>Strain gauge (±50N)

</td><td>50N

</td><td>±0.1%

</td></tr><tr><td>Load cell (±100N)

</td><td>100N

</td><td>±0.05%

</td></tr><tr><td>Heavy duty (±1000N)

</td><td>1000N

</td><td>±0.1%

</td></tr></tbody></table>

## Integration Notes

- Supports up to 2 independent load cell sensors
- Hardware-specific ADC implementation
- Force conversion via linear scaling model
- Tare offset corrects for sensor mechanical zero
- Real-time monitoring of structural loads
- Each sensor maintains separate calibration
- Independent error reporting per sensor