Closed weiying-chen closed 5 months ago
Does it help if you add critical_section
to your dependencies and copy the following file into your project? https://github.com/beeb/coffee-scale-app/blob/main/rs/src/critical_section.rs
Not seeing it in your example above.
Note that since your tare on startup, it's possible that you affect the load cell when providing power to your board and some of the readings are not in an unloaded state. You could check out my scale repo to see how I implemented a check for stability before taring. https://github.com/beeb/coffee-scale-app/blob/2e0c30409ef3bcbafa4e4cbbd71f1dcc0d413a50/rs/src/weight.rs#L92 (this assumes you've tuned your scaling factor to represent grams)
The first example above looks ok to me. It's reasonable to expect a variance in the range of 0.1g due to noise and environment.
I added the critical_section code:
use esp_idf_svc::hal::{
delay::{Delay, FreeRtos},
gpio::PinDriver,
peripherals::Peripherals,
};
use esp_idf_svc::hal::interrupt::{IsrCriticalSection, IsrCriticalSectionGuard};
use loadcell::{hx711::HX711, LoadCell};
use std::sync::Mutex;
static CS: IsrCriticalSection = IsrCriticalSection::new();
static CS_GUARD: Mutex<Option<IsrCriticalSectionGuard>> = Mutex::new(None);
pub struct EspCriticalSection {}
unsafe impl critical_section::Impl for EspCriticalSection {
unsafe fn acquire() {
let mut guard = CS_GUARD.lock().unwrap();
*guard = Some(CS.enter());
}
unsafe fn release(_token: ()) {
let mut guard = CS_GUARD.lock().unwrap();
*guard = None;
}
}
critical_section::set_impl!(EspCriticalSection);
fn main() {
esp_idf_svc::sys::link_patches();
esp_idf_svc::log::EspLogger::initialize_default();
let peripherals = Peripherals::take().unwrap();
let dt = PinDriver::input(peripherals.pins.gpio2).unwrap();
let sck = PinDriver::output(peripherals.pins.gpio3).unwrap();
let delay = Delay::new_default();
let mut load_sensor = HX711::new(sck, dt, delay);
load_sensor.tare(16);
load_sensor.set_scale(0.0043);
loop {
if load_sensor.is_ready() {
let reading = load_sensor.read_scaled().unwrap();
log::info!("Weight: {} g", reading); // Use this to get all the decimals
}
FreeRtos::delay_ms(1000u32);
}
}
I'm getting the same negative readings:
// 1 kg load cell:
(8145) rust_esp32c3_hx711: Weight: -0.15910001 g
I (9145) rust_esp32c3_hx711: Weight: 0.1333 g
I (10145) rust_esp32c3_hx711: Weight: -0.0215 g
// 2 kg load cell:
I (17765) rust_esp32c3_hx711: Weight: -4.4376 g
I (18765) rust_esp32c3_hx711: Weight: -4.214 g
I (19765) rust_esp32c3_hx711: Weight: -4.3473 g
But at least the readings are more stable, I think.
Okay, I'll check your repo and try to implement something. Thanks for the suggestion.
So, since my first example looks okay, I could just filter out the negative numbers?
I tried to incorporate your wait_stable
function:
use std::collections::VecDeque;
use esp_idf_svc::hal::{
delay::{Delay, Ets, FreeRtos},
gpio::{Gpio2, Gpio3, Input, Output, PinDriver},
peripherals::Peripherals,
};
use loadcell::{hx711::HX711, LoadCell};
mod critical_section;
const LOADCELL_STABLE_READINGS: usize = 10;
const LOADCELL_LOOP_DELAY_US: u32 = 10000;
const LOADCELL_READY_DELAY_US: u32 = 1000;
fn wait_stable(
load_sensor: &mut HX711<PinDriver<'_, Gpio3, Output>, PinDriver<'_, Gpio2, Input>, Delay>,
) {
let mut readings: VecDeque<f32> = VecDeque::with_capacity(LOADCELL_STABLE_READINGS);
loop {
while !load_sensor.is_ready() {
Ets::delay_us(LOADCELL_READY_DELAY_US)
}
let reading = load_sensor.read_scaled().expect("Failed to read scale");
log::info!("Waiting for stable weight: {:.4}", reading);
if readings.len() == LOADCELL_STABLE_READINGS {
readings.pop_front();
}
readings.push_back(reading);
if readings.len() == LOADCELL_STABLE_READINGS
&& readings.iter().all(|&x| (x - reading).abs() < 0.1)
{
break;
}
Ets::delay_us(LOADCELL_LOOP_DELAY_US); // Adjust delay as necessary
}
}
fn main() {
esp_idf_svc::sys::link_patches();
esp_idf_svc::log::EspLogger::initialize_default();
let peripherals = Peripherals::take().unwrap();
let dt = PinDriver::input(peripherals.pins.gpio2).unwrap();
let sck = PinDriver::output(peripherals.pins.gpio3).unwrap();
let delay = Delay::new_default();
let mut load_sensor = HX711::new(sck, dt, delay);
wait_stable(&mut load_sensor);
load_sensor.tare(16);
load_sensor.set_scale(0.0043);
loop {
if load_sensor.is_ready() {
let reading = load_sensor.read_scaled().unwrap();
log::info!("Weight: {} g", reading); // Use this to get all the decimals
}
FreeRtos::delay_ms(1000u32);
}
}
It gets stuck in this loop (I think it never finds a stable reading):
I (7386) rust_esp32c3_hx711: Waiting for stable weight: -1077.0000
I (7476) rust_esp32c3_hx711: Waiting for stable weight: -1077.0000
I (7576) rust_esp32c3_hx711: Waiting for stable weight: -1003.0000
I (7666) rust_esp32c3_hx711: Waiting for stable weight: -962.0000
I (7756) rust_esp32c3_hx711: Waiting for stable weight: -1034.0000
I (7846) rust_esp32c3_hx711: Waiting for stable weight: -1019.0000
I (7946) rust_esp32c3_hx711: Waiting for stable weight: -988.0000
I (8036) rust_esp32c3_hx711: Waiting for stable weight: -983.0000
I (8126) rust_esp32c3_hx711: Waiting for stable weight: -1052.0000
I (8216) rust_esp32c3_hx711: Waiting for stable weight: -1095.0000
I (8316) rust_esp32c3_hx711: Waiting for stable weight: -1052.0000
I (8406) rust_esp32c3_hx711: Waiting for stable weight: -1013.0000
I (8496) rust_esp32c3_hx711: Waiting for stable weight: -1094.0000
I (8586) rust_esp32c3_hx711: Waiting for stable weight: -1022.0000
I (8686) rust_esp32c3_hx711: Waiting for stable weight: -994.0000
I (8776) rust_esp32c3_hx711: Waiting for stable weight: -979.0000
If I remove wait_stable
, I get:
I (8225) rust_esp32c3_hx711: Weight: -5.6932 g
I (9225) rust_esp32c3_hx711: Weight: -5.7792 g
I (10225) rust_esp32c3_hx711: Weight: -5.8179 g
It assumes the readings are within 0.1g of each other. If your weight is more noisy, you might need to increase that tolerance.
Your scaling factor of 1.0 is probably wrong too
Ah, you're right. I changed the code:
load_sensor.set_scale(0.0043);
wait_stable(&mut load_sensor);
load_sensor.tare(16);
It gets stuck in:
I (30026) rust_esp32c3_hx711: Waiting for stable weight: -5.6889
I (30116) rust_esp32c3_hx711: Waiting for stable weight: -5.7663
I (30206) rust_esp32c3_hx711: Waiting for stable weight: -5.5513
I (30306) rust_esp32c3_hx711: Waiting for stable weight: -5.5384
I (30396) rust_esp32c3_hx711: Waiting for stable weight: -5.4997
I guess the readings never stabilize enough to break the loop. The loop does break if the threshold is 0.2 or 0.3, though. But I still get these readings without any load applied:
I (17436) rust_esp32c3_hx711: Weight: -5.7921004 g
I (18436) rust_esp32c3_hx711: Weight: -5.9469004 g
I (19436) rust_esp32c3_hx711: Weight: -6.0028 g
I (20436) rust_esp32c3_hx711: Weight: -5.8265004 g
I (21436) rust_esp32c3_hx711: Weight: -5.8265004 g
It feels like the tare
function isn't doing anything.
This is with my other load cell (it has small round platforms attached to it):
I (2846) rust_esp32c3_hx711: Waiting for stable weight: -415.8358
I (2936) rust_esp32c3_hx711: Waiting for stable weight: -415.8530
I (3016) rust_esp32c3_hx711: Waiting for stable weight: -415.8702
I (3106) rust_esp32c3_hx711: Waiting for stable weight: -415.6810
I (5536) rust_esp32c3_hx711: Weight: 0.19780001 g
I (6536) rust_esp32c3_hx711: Weight: 0.23220001 g
I (7536) rust_esp32c3_hx711: Weight: 0.2107 g
I (8536) rust_esp32c3_hx711: Weight: -0.0344 g
I (9536) rust_esp32c3_hx711: Weight: 0.064500004 g
I (10536) rust_esp32c3_hx711: Weight: -0.0516 g
Note: this load cell did pass the 0.1 threshold.
Looks good to me!
So you would just filter out the negative zeros? E.g. so the user doesn't see:
- 0 g
0 g
-0 g
0 g
I don't know your application but yeah if you want to avoid negative values you could. Or just make it so the rounding (if any) , ignores the sign for the zero value.
All right. Okay, thanks for all the help! And for being so responsive.
This is the code I'm using:
It doesn't matter what number I pass to
load_sensor.tare
, the value is never 0, and it's often negative:This is another load cell of mine (again, with no load applied):
Is there an issue with
tare
? Or maybe the issue is my load cell? Or I'm supposed to filter out the negative values by myself?