很好的教程,软件代码那一段很详细,很适合新手
(ps:插在单片机上的杜邦线可以在连接紧密后打一点热熔胶固定,可以防止许多因杜邦线松动而导致的问题)
UPD1:修正了单位
UPD2:修正了代码
在 kc 上有时会出现令人担忧的一幕:有些网友因为没有条件,使用砖头、石头、小土堆等可移动物进行试车。这不仅会导致无法知晓发动机的实际推力,更有可能会导致安全事故,机毁人伤。
为了避免以上问题,一个稳固的试车台就非常必要了。
这篇文章算是自己制作的一次日记。
试车台的主体框架使用铝型材这种方便连接、强度较高的材料制作,而推力采集部分使用 Arduino Uno 开发板和 hx711 制作。
先列出所需的材料和工具清单:
材料:
3030Q 铝型材 90 mm * 5
3030Q 铝型材 150 mm * 2
3030Q 铝型材 200 mm * 2(如果你觉得 200 mm 太短,可以适当加长)
3030 转向角件(套) * 4
3030 角码(套) * 4
3030 角槽(套) * 12
3030 铝型材 120mm 铝合金把手(套)(可选)
6mm 铝型材 T 母 * 2(以下两个直径需要根据你的传感器而定)
6mm 杯头螺丝 * 2(这个螺丝的长度需要根据你的传感器而定,稍后会讲)
不锈钢扎带/铁丝若干
国产 Arduino Uno * 1
hx711 模块 * 1
40/20 kg 称架 * 1(根据你设计的发动机推力选择,尽量买大的,不然很容易坏)
Micro SD 模块 * 1
Micro SD 卡 * 1(买 1GB 以下的,太大无法读取)
读卡器 * 1
杜邦线若干(可以买比较短的,方便)
工具:
电烙铁焊接套装
内六角扳手套装
十字螺丝刀
剪钳(可使用具有类似功能的工具替代)
Arduino Uno 方口数据线(可以使用部分打印机的数据线代替)
一台可以正常运行的电脑
3D 打印机及耗材(可选)
注意:以上名字后带“(套)”的紧固件需要你购买带螺丝、螺母的完整套件,一般商家有套装选项。
需要声明的是,本试车台的框架是参照的以太LYBing的方案(XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX)。
准备好了这些,就可以开始制作了。
如图,进行组装。
需要注意的是传感器的固定。你需要购买你的传感器高度(mm)+8mm左右的螺柱,可以长但不可以短。
将称架的两面亚克力拆下后,传感器侧面会有一个箭头,将箭头指向前方,使用 T 母和螺丝固定。在将亚克力顶面(不带防滑垫)装回即可。
固定时把你的铁丝/不锈钢扎带穿过角码两端的孔即可。
将称架连接线的端子用剪钳剪下,再用剪钳去除四根连接线的绝缘层。可以给每根数据线上锡(方便待会焊接)。
根据你的商家提供的资料,将四根不同颜色的线焊接到 hx711 上。我这里是红 E+ 黑 E- 白 A- 绿 A+。并将排针焊接在另一端。
用杜邦线连接 hx711、Micro SD 卡模块和 Arduino Uno,如图:
如果你使用的是 Arduino Nano 等其他开发板,请自行查阅文档。
然后我们要对可怜的 HX711 做一些小手术,以启动 80 Hz 采样。
如果你是如下这种,用剪钳去除红圈位置的铜箔,断开该引脚与地的连接。并用电烙铁给蓝色标注的两个引脚连锡。
如果你是下面这种,用老铁将红色位置的 0 欧电阻移到蓝色位置上。
原因如下:
我们刚刚所做的,其实就是给 RATE 脚接上高电平,使得其输出速率为 80Hz。
供电准备一个充电宝或者使用 DC 接口锂电池。
下载如下三个文件并放在同一目录下。
打开 Arudino IDE(XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 下载 Windows 版本)并打开这三个文件。
用数据线连接电脑和 Arduino,查找新出现的 COM 口,点击旁边的小铅笔。
输入“Arduino Uno”,选择并确定。
接下来进行校准。
将试车台以传感器所在底竖立。确保传感器上无其他物品。
打开 HX711.cpp,发现第六行有一句代码
#define GapValue 204204 即是校准因子,接下来记作 k。
取一个已知重量(g)的物品,重量记为 m,这里我拿我的小水杯,301 g。
打开串口监视器,波特率 115200。
打开 HX711_5kg.ino,上传代码,这里可以先不插卡。
IDE 会自动完成所需库的安装。
上传完成后等几秒钟使系统完成初始化。
在一个 5000 左右的数字后(系统校准用时 ms),应当会滚动输出大量三个一组的数据,如图:
这些三个一组的数据分别对应时间(s)重量(g)重量(N)
此时可以放上你的物品,观察重量(g)的输出,记为 w。重量可能会有波动,你可以选 10 个取平均值。
用 k*w/m 得到新的校准因子,将 HX711.cpp 第六行的 204 改为你的校准因子。
重新上传 HX711_5kg.ino 检查是否有效,你可以手动微调提升效果。
断电插入 MicroSD 卡,重启 Arduino,进行数据记录的测试。
初始化完毕后随便在台上按几下,然后再次断电,取出 MicroSD 卡用读卡器读取。
可以找到一个 data.txt 文件,打开结果应当如图。
左侧栏为时间,右侧栏为推力(N)
每次开机,Arduino 都会在该文件后追加本次的采集结果(为什么不是覆盖?要是采完误触就炸了。),以“-----”分割。
如果你的测试全部通过,恭喜你制作成功!
做个外壳,万一磕坏了怎么办!
PLA 打印上面文件即可,是用树状支撑。
但是我不推荐你用我的外壳(做得比较匆忙,甚至忘记了留引出传感器数据线的洞),因为我没有设计任何卡紧结构,你需要用热熔胶粘住。而且外壳并不美观。
Q:没有找到 Arduino 的端口/上传失败。
A:可以手动安装一下 CH340 驱动。将报错信息丢给大模型,它很快就会告诉你问题。
Q:传感器一直返回 0.00,对压力完全没有反应。
A:多半是接错了或连接不良,使用万用表(别告诉我你没有)检查端点之间的连接。如果确定没有接线问题,那就大胆认定传感器或 HX711 坏了(这两个如果操作不当很容易坏掉),我做的时候就遇到了坏的传感器,更换后立马工作。
Q:MicroSD 卡里没有数据。
A:串口里应该会返回“SD card failed!”的信息,很可能是接线问题,检查一下。如果不是,格式化一下 MicroSD。
最后,希望各位都能完成自己的研究!
很好的教程,软件代码那一段很详细,很适合新手
(ps:插在单片机上的杜邦线可以在连接紧密后打一点热熔胶固定,可以防止许多因杜邦线松动而导致的问题)
试车台骨架几近完成了
我觉得作者的压力传感器布置的位置有些别扭,我试着想一些方法来弥补,比如说在后面中空的部分,装一块金属板,让压力模块可以顶在板子上?
兄弟我刚发现你的代码有问题,sd卡里面的东西不对,其实右边的推力数据就是左边的时间,而且还多了一个点,只有串口数据是对的,不知是故意为之还是你没注意到,望作者答复
我看了一下HX711_5Kg.ino.cpp文件中的SD卡写入逻辑错误
在 loop() 函数中,SD卡数据写入部分存在重复写入时间( now )的问题,而未正确写入推力( force )
导致1. 重复写入时间:代码中先执行了 sdcard.print(now) ,随后又在同一行数据中再次写入 now ,导致推力列显示为时间。
2. 格式问题:时间和推力未指定小数位数,导致输出时出现多余的小数点和零(如 017.0170.00 )
已经帮你改好了,各位可以直接照抄我的代码
HX711_XXXXXXo.cpp:
#include <Arduino.h>
#include "HX711.h"
#include <SPI.h>
#include <SD.h>
float pretime = 0;
File sdcard;
const int cspin = 10; // SD卡片选引脚
bool isFirstWrite = true;
// 引脚定义(按实际接线)
#define HX711_SCK 2
#define HX711_DT 3
// 滤波参数(平衡稳定度和灵敏度)
const int numReadings = 5;
int readings[numReadings];
int readIndex = 0;
int total = 0;
void setup() {
Init_Hx711();
Get_Maopi(); // 读取空载零点(含安装应力)
delay(3000);
Serial.begin(115200);
Serial.println("HX711初始化完成 程序by-tian30");
// 初始化SD卡
pinMode(cspin, OUTPUT);
if (!SD.begin(cspin)) {
Serial.println("你还没有插SD卡哦!");
while (1);
}
Serial.println("SD卡就绪");
pretime = millis();
// 初始化滤波数组
for (int i = 0; i < numReadings; i++) {
readings[i] = 0;
}
}
void loop() {
// 首次写入表头
if (isFirstWrite) {
sdcard = SD.open("data.txt", FILE_WRITE);
if (sdcard) {
sdcard.println("Time(s)\tForce(N)");
sdcard.close();
isFirstWrite = false;
}
}
// 读取重量(带滤波)
total -= readings[readIndex];
readings[readIndex] = Get_Weight();
total += readings[readIndex];
readIndex = (readIndex + 1) % numReadings;
float weight = (float)total / numReadings;
if (weight < 0) weight = 0; // 负数归零
// 计算时间和推力
float now = (millis() - pretime) / 1000.0;
float force = weight / 1000.0 * 9.8;
// 写入SD卡
sdcard = SD.open("data.txt", FILE_WRITE);
if (sdcard) {
sdcard.print(now, 3);
sdcard.print("\t");
sdcard.println(force, 3);
sdcard.close();
}
// 串口输出
Serial.print(now, 3);
Serial.print("\t");
Serial.print(weight);
Serial.print("g\t");
Serial.print(force, 3);
Serial.println("N");
}
另外我加了一个滤波算法,防止数值一直乱跳,然后加了一个TF卡检测,如果你的TF卡有问题的话是识别不出来的,防止试车前出事
HX711.cpp:
#include "HX711.h"
long HX711_Buffer = 0;
long Weight_Maopi = 0; // 空载零点(自动读取)
long Weight_Shiwu = 0;
// 【必须校准!】按以下步骤修改:
// 1. 空载时上传代码,记录串口显示的重量值(如显示100g)
// 2. 放140g物体,记录显示值(如显示240g)
// 3. 计算:GapValue = 原GapValue * 140 / (240-100) → 示例:204*140/140=204
#define GapValue 204 // 替换为你的计算值
void Init_Hx711() {
pinMode(HX711_SCK, OUTPUT);
pinMode(HX711_DT, INPUT);
}
void Get_Maopi() {
Weight_Maopi = HX711_Read(); // 自动读取当前空载原始数据作为零点
}
long Get_Weight() {
HX711_Buffer = HX711_Read();
Weight_Shiwu = HX711_Buffer - Weight_Maopi; // 减去零点
Weight_Shiwu = (long)((float)Weight_Shiwu / GapValue); // 用校准因子计算
return Weight_Shiwu;
}
unsigned long HX711_Read(void) {
unsigned long count = 0;
unsigned char i = 0;
digitalWrite(HX711_DT, HIGH);
delayMicroseconds(1);
digitalWrite(HX711_SCK, LOW);
delayMicroseconds(1);
while (digitalRead(HX711_DT));
for (i = 0; i < 24; i++) {
digitalWrite(HX711_SCK, HIGH);
delayMicroseconds(1);
count = count << 1;
digitalWrite(HX711_SCK, LOW);
delayMicroseconds(1);
if (digitalRead(HX711_DT)) count++;
}
digitalWrite(HX711_SCK, HIGH);
delayMicroseconds(1);
count ^= 0x800000;
digitalWrite(HX711_SCK, LOW);
delayMicroseconds(1);
return count;
}
这里要注意一下必须要把GapValue值算出来,不能拍拍脑壳直接填
剩下的一个文件是头文件不用修改,TF卡中已经是左边时间,右边推力(g取9.8N/kg),如果你发现串口数据有时候一直跳一个固定数值(比如我的老显示1400g),可以试试直接采集并打印 HX711 原始数据,如果发现串口数据很稳定就可能是干扰问题(比如接地端连接不稳或没连接)还要注意连接线不可太长,不然HX711的信号会衰减,如果原始数据也乱跳那就是HX711或压力传感器坏了(建议先换一个HX711试试,因为之前对HXX711修改过,可能让你给改坏了)
另外我要和LZ说一下,不能犯这种小错误,如果我不发现别人照抄再去试车可就害人不浅啊,不过LZ你的教程接线部分和别的部分也挺详细(就是代码挺烂的)
引用ManGo_Mouse发表于17楼的内容哦哦发现了,我用的是我的一个旧版代码,交上去的代码可能在修改的时候多复制了一些代码,谢谢啦
哈哈哈
,原来是这样啊,那我的代码不就白写了
但是各位kcer如果做出来发现串口数据乱跳可以采用我的代码,因为加了滤波算法
哈哈哈😁,原来是这样啊,那我的代码不就白写了但是各位kcer如果做出来发现串口数据乱跳可以采用我的代码,因为加了滤波算法
新版代码,加入卡尔曼滤波算法,滤波效果相对更加优秀,只需更改原版的hx711XXXXO.ino,其他步骤同文
不过lz说“然后加了一个TF卡检测”,我代码里不本来就有一个检测吗……
hx711XXXXO.ino:
#include <Arduino.h>
#line 1 "C:\\Users\\Acer\\Desktop\\HX711_5Kg\\HX711_5Kg.ino"
#include "HX711.h"
#include <SPI.h>
#include <SD.h>
float pretime = 0;
File sdcard;
const int cspin = 10;
#line 10 "C:\\Users\\Acer\\Desktop\\HX711_5Kg\\HX711_5Kg.ino"
void setup();
#line 42 "C:\\Users\\Acer\\Desktop\\HX711_5Kg\\HX711_5Kg.ino"
void loop();
#line 10 "C:\\Users\\Acer\\Desktop\\HX711_5Kg\\HX711_5Kg.ino"
void setup()
{
Init_Hx711(); //初始化 hx711
delay(3000);
Get_Maopi(); //初始化毛皮
Serial.begin(115200);
Serial.println("HX711 done.");
pinMode (cspin, OUTPUT);
if (!SD.begin (cspin)) { // SD 初始化并检测
Serial.println("SD card failed!");
}
else {
Serial.print("SD card done.\n");
sdcard = SD.open ("data.txt", FILE_WRITE);
if (sdcard) { // 文件读写测试
Serial.println("Opened data.txt!");
sdcard.println("---------------------------------");
sdcard.println("0.00 0.00");
sdcard.close();
} else {
Serial.println("Error opening data.txt!");
}
Serial.println("Start-----------------");
}
pretime = millis ();
Serial.println (pretime);
}
const double Q = 0.001, R = 0.5;
// 过程噪声方差 q(0.001~1),观测噪声方差 r(1~10)
// 根据不同传感器需要调整这两个参数
double p = 1, k, lastp = 1, ans = 0;
// p 初始估计误差方差,k 卡尔曼增益,lastp上次估计误差方差,ans 上次估计值
double kalman (double val) { // 卡尔曼滤波
// 预测
p = lastp + Q;
// 更新
k = p / (p + R);
ans = ans + k * (val - ans);
lastp = (1 - k) * p;
return ans;
}
void loop() {
float weight = Get_Weight ();
float now = (millis() - pretime) / 1000;
if (weight < 0)
weight = 0;
weight = kalman (weight); // 卡尔曼滤波
float force = weight / 1000 * 9.8;
Serial.print (now);
Serial.print (" ");
Serial.print (weight);
Serial.print ("g");
Serial.print (" ");
Serial.print (force);
Serial.println ("N");
sdcard = SD.open ("data.txt", FILE_WRITE);
sdcard.print (now);
sdcard.print (" ");
sdcard.println (force);
sdcard.close ();
}
引用ManGo_Mouse发表于23楼的内容看了一下lz的代码是均值滤波(就是简单地对前后几个数取平均数),在一组数据整体偏高的时候就会有我说的情况,我还是写个卡尔曼滤波吧
没办法,本人能力就到这了,主要还是想把之前不能用的代码改好了
引用ManGo_Mouse发表于23楼的内容看了一下lz的代码是均值滤波(就是简单地对前后几个数取平均数),在一组数据整体偏高的时候就会有我说的情况,我还是写个卡尔曼滤波吧
对了,还有件事,想问一下LZ你的压力传感器和HX711容易坏吗,我的有一次刚试车完,在连接电脑测试发现串口数据怎么弄都是0,换了压力传感器就好了,还有次我都没动HX711就自己坏了,气死我了
引用ManGo_Mouse发表于24楼的内容新版代码,加入卡尔曼滤波算法,滤波效果相对更加优秀,只需更改原版的hx711XXXXO.ino,其他步骤同文不过lz说“然后加了一个TF卡检测”,我代码里不本来就有一个检测吗……hx711XXXXO....
回复检测问题:LZ你的代码中检测不到tf卡也能打开串口数据看相关数据,我的代码改了之后,如果检测不到TF卡,是不能查看任何数据的(其实也就是脱裤子放屁,多此一举)
另外非常感谢LZ新写的滤波代码,实测非常稳定