喷气推进
 
火箭推力数据搜集装置教程
沙暴 2015-5-25
看到论坛越来越多人拥有火箭推力测试台,我也心动了,自己运用了刚刚过去半年在大学学习的单片机知识,买了一些传感器回来,自己也做了一个用来搜集推力数据的装置。我还弄了加速度和气压传感器,等火箭做好后作为航电用来搜集火箭飞行过程的加速度和飞行高度。今天在这里仅介绍推力搜集装置,另外两个我需要暑假回去测试后再发上来,因为还有很多不确定的。其实发这个帖是怀着一种愧疚的心情的,因为来科创有三年了,在这里学到了很多东西,但是发的帖却很少。
先来看两张图片,这是我弄好的三个传感器,分别是用于搜集推力、加速度和飞行高度数据的传感器。看上去很简单,主要是几个体积很小的模块和一个单片机系统
pic

pic



在科学试验中,对数据的采集是极其重要的。对于我们这群火箭爱好者来说,对数据的采集也很必要。通过采集火箭的推力数据,就能计算出比冲和其他一些东西,对于比较不同的火箭设计大有好处。下面就详细介绍怎样去做(仅介绍传感器系统制作和程序)。由于是在学校做的,刚做好不久,所以没法用火箭来测试,只有到暑假才能回家进一步试验,所以可能存在不足,希望大家在实验中自行去修正
pic

这个是我做好的推力传感器和金属发动机


下面是论坛其他网友的推力测试装置。
https://www.kechuang.org/t/58561
https://www.kechuang.org/t/67413
https://www.kechuang.org/t/71386


以下是详细的制作过程
材料和工具:干电池电池3节、电池盒、51单片机系统、应变式称重传感器、hx711模块、AT24C08、若干杜邦线、电烙铁等等;
在这里我附上几个链接吧,你们也完全可以到其他地方买
hx711模块:http://item.taobao.com/item.htm?spm=a1z09.2.9.91.Kj4xyW&id=27002972399&_u=5945jj4bec1


AT24C08
http://detail.tmall.com/item.htm?id=19128185719&spm=a1z09.2.9.107.dMorpb&_u=j210l9jm26d2
应变式称重传感器:http://detail.tmall.com/item.htm?id=39232825572&spm=a1z09.2.9.303.dMorpb&_u=j210l9jm4dc2
51单片机系统
http://detail.tmall.com/item.htm?id=39200262134&ali_refid=a3_420434_1006:1109360086:N:51%E5%8D%95%E7%89%87%E6%9C%BA%E6%9C%80%E5%B0%8F%E7%B3%BB%E7%BB%9F%E6%9D%BF:804b93427506b48c797248985146d2b5&ali_trackid=1_804b93427506b48c797248985146d2b5&spm=a230r.1.0.0.Mq0npP




电源:在这里我选择用31.5V的干电池作为单片机供电电源,实测电压在4.6V,一般51单片机供电电压在5V4.6V也可以工作.也可以用四节电池,不过要用稳压二极管把电压降到5V
pic



51单片机系统:在这里我用的是STC89C52单片机,51单片机在这里完全能够满足使用,它是整个装置的控制中心。上面链接的是一块51单片机系统板,把程序直接烧录进去,再供电就能 使用。说点题外话,学单片机很有用,很多很神奇的功能可以通过单片机去完成,现在真庆幸自己学了单片机,如果大家有时间的话,最好去学一下。单片机的厉害可能超出你想象。
pic




hx711模块:AD转换,将应变式称重传感器的电压信号转换成数字信号。采样频率设为80Hz,即一秒内可以采集80个推力数据。在这里设定采集时间为2秒,即一共采集160个推力数据。不过,如果买回来的板不经过处理,那么采样频率只有10Hz,为了能达到80Hz,需要做一点处理,就是将RATE脚置1
具体请见这篇贴子:https://www.kechuang.org/t/67413

不过有点奇怪的是,我用的这个模块的GND是需要和单片机的GND连接的,而上面这篇帖子却说不用,不知道为什么。
pic



应变式称重传感器:我选择的称重传感器的量程是40KG,你们根据自己的需要选择。40KG的精度在10g左右,这精度已经足够了。它内部有一电阻电桥,当推力使传感器发生形变时,电阻会相应的改变,通过电桥将电阻的变化转换成电压信号,再经过转换就能得到相应的值,转换就是要用到上面的hx711模块。
pic




应变式称重传感器在测试过程中要像图中这样竖直着放,我已经在程序中进行了一些简单的校准,可能不是很精确,因为在学校很多东西没法去试验
AT24C08:AT24C08是一个串行CMOS E2PROM, 内部含有1024个8位字节。在这里AT24C08的作用是将传感器采集回来的数据存储起来,火箭测试完后再将数据读取出来,这样就不需要在测试时连接电脑(避免在测试过程中要是发生爆炸,那电脑可能就遭殃了)。一共采集161个数据(有一个为没产生推力时的值,后面有讲),每个数据是一个长整型,所以AT24C08足够存储了.要注意的是,不要买现成的AT24C08的模块,因为现成的AT24C08模块存储速度是不够快的,所以要买我上面链接的那种AT24C08,同时要用2个10K电阻焊成一个简单电路才能用,电路图在下面讲
pic







下面就是整个装置的连接图:
pic




称重传感器和hx711的连接,也请看这里https://www.kechuang.org/t/67413




sbit HX711_DOUT=P2^6;
sbit HX711_SCK=P2^5;
sbit sda=P2^4;
sbit scl=P2^1;
sbit d1=P1^1;
这是在我的程序中定义的连接引脚。


hx711SCK脚和单片机的P2^5脚连接,DT脚和P2^6连接,模块的VCCGND分别和单片机的VCCGND连接。记住,有一点和上面的那位网友的连接不同的是我用的这个模块的GND是需要和单片机的GND连接的,而上面那位网友的帖子却说不用,你可以自己两种都试一下
pic




AT24C08的电路图也很简单,这里附上AT24C08的引脚图和连接图,
pic


这个是AT24C02的图,引脚和AT24C08一样。


pic


如果不明白请自己上网查看一下。由连接图可以看到,需要自备两个10K欧姆电阻,和一个8脚的插座,用来插上AT24C08的,同时要准备个电烙铁焊接,有5个引脚是要接单片机的GND的,还有1个引脚要接电源,2个引脚接单片机IO口(在我的程序中,SDA脚接单片机的P2^4SCL脚接单片机的P2^1)。

从上面还可以看到,我定义了单片机的P1^1脚:sbit d1=P1^1;在我用的这款51单片机系统中,P1^1脚是与一个发光二极管连接的,在程序中,我做了些设置。当你一开始接通电源时,会进入一个循环,数据是不会被存储在AT24C08中的,此时与P1^1脚连接的那个发光二极管会亮,如图,会有两个发光二极管亮(其中一个是指示单片机工作的,即你接通电源它就会亮)。如果在测试过程中,当你发现只有一个发光二极管亮(即电源指示灯亮),那就需要把电源和单片机断开,然后再连接,重复上面步骤,直到有两个二极管同时亮为止。当产生火箭推力时,程序会跳出循环,P1^1脚连接的那个发光二极管会熄灭,然后数据就会被存储起来。简单的说就是一开始时当两个发光二极管都亮时才证明正常工作,否则你需要把电源和单片机断开,然后再连接,直到有两个二极管同时亮为止。火箭产生推力时其中一个二极管会熄灭
pic

这就是两个二极管同时亮的效果,只有这样才说明正常工作。


下面就是我的程序,一共有两个程序:一个负责在火箭产生推力时搜集数据,另一个是火箭工作完后读取AT24C08中的数据。不过在这之前,你需要下载两个软件和一个驱动。首先装个ch341,它是一个USB转串口驱动。然后装keil uvision4:用于编译的软件。STC_ISP:用于烧录。keil uvision4和STC_ISP的具体运用就靠你们自己上网去搜,这里不介绍
第一个程序:
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit HX711_DOUT=P2^6;
sbit HX711_SCK=P2^5;
sbit sda=P2^4;
sbit scl=P2^1;
sbit d1=P1^1;
 
void delay(unsigned int k) 
{ 
    unsigned int i,j; 
    for(i=0;i<k;i++)
    { 
        for(j=0;j<100;j++) 
        {;}
    } 
}
 
void Delay__hx711_us(void)
{
    _nop_();
    _nop_();
}
void delays()
{;;}
 
void at_start()
{
    sda=1;
    delays();
    scl=1;
    delays();
    sda=0;
    delays();
}
 
void at_stop()
{
    sda=0;
    delays();
    scl=1;
    delays();
    sda=1;
    delays();
}
 
void at_respond()
{
    uchar i;
    scl=1;
    delays();
    while((sda==1)&&(i<250))
         i++;
    scl=0;
    delays();
}  
 
 
 
 
 
void at_write_byte(uchar i)
{
    uchar m;
    bit n;
    for(m=8;m>0;m--)
    {
      n=(bit)(i&0x80);
        scl=0;
      delays();
        sda=n;
        delays();
        scl=1;
      delays();
        i=i<<1;
    }
    scl=0;
    delays();
    sda=1;
    delays();
}
 
void at_write_address(uchar p,uchar address,uchar date)
{
    at_start();
    at_write_byte(p);
    at_respond();
    at_write_byte(address);
    at_respond();
    at_write_byte(date);
    at_respond();
    at_stop();
}
 
 
//****************************************************
 
ulong HX711_Read(void)     
{
    ulong count; 
    uchar i; 
    HX711_DOUT=1; 
    Delay__hx711_us();
    HX711_SCK=0; 
    count=0; 
    while(HX711_DOUT); 
    for(i=0;i<24;i++)
    { 
        HX711_SCK=1; 
        count=count<<1; 
        HX711_SCK=0; 
        if(HX711_DOUT)
        count++; 
    } 
    HX711_SCK=1; 
    count=count^0x800000;    
    Delay__hx711_us();
    HX711_SCK=0;  
    return(count);
}
 
 
 
void init()
{
    delay(1000);
    sda=1;
    delays();
    scl=1;
    delays();
}
 
 
void main()
{
  ulong temp;
  uchar m,n,i,b[4];
  init();
     
 
    for(m=0;m<20;m++)
    {
      temp=HX711_Read();
      temp=(ulong)((temp-8381000)*136/147);  
      delay(10);
    }   
     
 
    temp=HX711_Read();
    temp=(ulong)((temp-8381000)*136/147);   
    for(i=0;i<4;i++)                          
   {
       b[i]=(uchar)(temp&0xff);
       at_write_address(0xa0,240+i,b[i]);
       temp>>=8;
       delay(2);
   }
    delay(10);
     
 
    while(1)
    {
       temp=HX711_Read();
       temp=(ulong)((temp-8381000)*136/147);      
         d1=0;
         if(temp>7000)
         {  
           d1=1;
             break;
         }
    }
 
    n=0;
  for(m=0;m<60;m++) 
  {
      temp=HX711_Read();
      temp=(ulong)((temp-8381000)*136/147);       
      for(i=0;i<4;i++)                          
   {
       b[i]=(uchar)(temp&0xff);
       at_write_address(0xa0,n,b[i]);
       temp>>=8;
       delay(2);
         n++;
   }
  } 
     
 
  n=0;
  for(m=0;m<60;m++) 
  {
      temp=HX711_Read();
      temp=(ulong)((temp-8381000)*136/147);       
      for(i=0;i<4;i++)                           
   {
       b[i]=(uchar)(temp&0xff);
       at_write_address(0xa2,n,b[i]);
       temp>>=8;
       delay(2);
         n++;
   }
  } 
 
    n=0;
  for(m=0;m<40;m++) 
  {
      temp=HX711_Read();
      temp=(ulong)((temp-8381000)*136/147);       
      for(i=0;i<4;i++)                           
   {
       b[i]=(uchar)(temp&0xff);
       at_write_address(0xa4,n,b[i]);
       temp>>=8;
       delay(2);
         n++;
   }
  } 
  while(1);
}



本来是有注释的,但发到论坛上就变乱码,然后就把注释删了。
首先进行初始化,然后进入一个循环,单片机会一直检测是否产生推力。当产生推力时,就会跳出循环,接着把传感器采集回来的数据存储在AT24C08中。经过用一个定时器计时,采集和存储数据的时间在2秒左右,也就是说你的火箭的工作时间需要在2秒内才能采集到火箭整个推力过程的完整数据。你也可以根据自己需求,只需要简单改一下延时函数,就可以获得不同的采集和存储数据的时间。
你需要做的是把这个程序下载到keil
uvision4
上,编译,然后用STC_ISP烧录到单片机上。烧录完后,当用来测试火箭时,只需要按下单片机系统的电源就行。
注意的是,称重传感器要尽量保持竖直,并且在按下单片机开关后就不能去动它,否则很容易就会跳出循环,记录的数据就是完全没用的数据。这就是为什么我要设置上面讲到发光二极管,如果一直只有一个发光二极管亮而不是两个,可能就是因为你的称重传感器放置时不够竖直

还有另一点,温度对传感器是有一定影响的,在室内我开着空调和没开,得出来的数据有细微的误差,这点误差和火箭的推力比起来不算什么,但对我程序中的那个while循环是有很大影响的。如果做好了的装置一直只有一个发光二极管亮而不是两个,另外一个原因就是温度的影响,可能是温度低了。
为此,如果你发现一直只有一个发光二极管亮,或许就需要改一下程序中所有的:‘’temp=(ulong)((temp-8381000)*136/147);   //校准‘’这一条,可以将8381000改成更小的数,比如改成8378000。如果还是不行,就把它改成更大的数。同时*136/147是我的传感器用来校准的,因为我发现直接从传感器得出的推力值和实践是有点不一样了(做法是把传感器横着放,然后绑着重物得出一个数值,再用一个精确的电子秤测量重物的质量,两者的比值就是这个值。不过由于我的程序是适用于竖直放置时的,所以当你横着放时要把误差考虑进去,即减去横着放时传感器得到的数据。可能每个传感器的这个值会有差异,所以需要你们自己去测试修正,然后把我程序中的这个值改掉就行)。
同时,我是设定推力大于70克才搜集数据的,所以一般你们看到的搜集到的数据前几个应该是大于70克的。


第二个程序:
#include<REG52.H> 
#include<math.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sbit sda=P2^4;
sbit scl=P2^1;
 
 
void delay(unsigned int k) 
{ 
    unsigned int i,j; 
    for(i=0;i<k;i++)
    { 
      for(j=0;j<121;j++) 
      {;}
        } 
}
void delays()
{;;}
 
 
void start()
{
    sda=1;
    delays();
    scl=1;
    delays();
    sda=0;
    delays();
}
 
 
void stop()
{
    sda=0;
    delays();
    scl=1;
    delays();
    sda=1;
    delays();
}
 
 
void respond()
{
    uchar i;
    scl=1;
    delays();
    while((sda==1)&&(i<250))
         i++;
    scl=0;
    delays();
} 
 
 
void write_byte(uchar i)
{
    uchar m;
    bit n;
    for(m=8;m>0;m--)
    {
      n=(bit)(i&0x80);
        scl=0;
      delays();
        sda=n;
        delays();
        scl=1;
      delays();
        i=i<<1;
    }
    scl=0;
    delays();
    sda=1;
    delays();
}
 
 
uchar read_byte()
{
  uchar k,l;
    scl=0;
    delays();
    sda=1;
    delays();
    for(l=8;l>0;l--)
    {
      scl=1;
      delays();
      k=(k<<1)|sda;
        scl=0;
      delays();
    }
    return k;
}
uchar read_address(uchar p,uchar address)
{
    uchar da;
    start();
    write_byte(p);
    respond();
    write_byte(address);
    respond();
    start();
    write_byte(p+1);
    respond();
    da=read_byte();
    stop();
    return da;
}
 
 
void init()
{
    delay(1000);
    sda=1;
    delays();
    scl=1;
    delays();
    TMOD=0x20;
    TH1=0xfd;
    TL1=0xfd;
    TR1=1;
    SM0=0;
    SM1=1;
}
 
 
void conver(ulong temp)
{
  uchar yi,qw,bw,sw,wan,qian,bai;
    yi=temp%1000000000/100000000+0x30;
    if(yi!=0x30)
    {
      SBUF=yi;
      while(!TI);
      TI=0;
  }     
    qw=temp%100000000/10000000+0x30;
    if(qw!=0x30)
    {
      SBUF=qw;
      while(!TI);
      TI=0;
  } 
  if(qw==0x30)
    {
      if(yi!=0x30)
      {
        SBUF=qw;
        while(!TI);
        TI=0;
        }   
  }     
    bw=temp%10000000/1000000+0x30;
    if(bw!=0x30)
    {
      SBUF=bw;
      while(!TI);
      TI=0;
  } 
  if(bw==0x30)
    {
      if(yi!=0x30||qw!=0x30)
      {
        SBUF=bw;
        while(!TI);
        TI=0;
        }   
  }     
    sw=temp%1000000/100000+0x30;
    if(sw!=0x30)
    {
      SBUF=sw;
      while(!TI);
      TI=0;
  } 
  if(sw==0x30)
    {
      if(yi!=0x30||qw!=0x30||bw!=0x30)
      {
        SBUF=sw;
        while(!TI);
        TI=0;
        }   
  }     
 
  wan=temp%100000/10000+0x30;
    if(wan!=0x30)
    {
      SBUF=wan;
      while(!TI);
      TI=0;
  } 
  if(wan==0x30)
    {
      if(yi!=0x30||qw!=0x30||bw!=0x30||sw!=0x30)
      {
        SBUF=wan;
        while(!TI);
        TI=0;
        }   
  }         
    qian=temp%10000/1000+0x30;
    if(qian!=0x30)
    {
      SBUF=qian;
      while(!TI);
      TI=0;
  } 
  if(qian==0x30)
    {
      if(yi!=0x30||qw!=0x30||bw!=0x30||sw!=0x30||wan!=0x30)
      {
        SBUF=qian;
        while(!TI);
        TI=0;
        }   
  }             
    bai=temp%1000/100+0x30;
    SBUF=bai;
    while(!TI);
    TI=0;
    SBUF=' ';
    while(!TI);
    TI=0;  
}
 
void main()
{
    ulong f;
        uchar i;
    init();
        SBUF='F';
        while(!TI);
        TI=0; 
        SBUF=':';
        while(!TI);
        TI=0; 
        SBUF=' ';
        while(!TI);
        TI=0; 
        delay(5);
         
         
     f=(read_address(0xa0,243)*16777216)+(read_address(0xa0,242)*65536)+(read_address(0xa0,241)*256)+read_address(0xa0,240);
     delay(10);
     conver(f);
     SBUF='/';
     while(!TI);
     TI=0; 
     SBUF=' ';
     while(!TI);
     TI=0; 
     delay(5);
      
         
     for(i=0;i<240;i+=4)
     {
            f=(read_address(0xa0,i+3)*16777216)+(read_address(0xa0,i+2)*65536)+(read_address(0xa0,i+1)*256)+read_address(0xa0,i);
            delay(10);
            conver(f);
     }
     for(i=0;i<240;i+=4)
     {
            f=(read_address(0xa2,i+3)*16777216)+(read_address(0xa2,i+2)*65536)+(read_address(0xa2,i+1)*256)+read_address(0xa2,i);
            delay(10);
            conver(f);
     }
     for(i=0;i<160;i+=4)
     {
            f=(read_address(0xa4,i+3)*16777216)+(read_address(0xa4,i+2)*65536)+(read_address(0xa4,i+1)*256)+read_address(0xa4,i);
            delay(10);
            conver(f);
     }
     while(1);
}

第二个程序是读取AT24C08中的数据,并经过一些适当的转换和修正,得出推力数据,然后就会向串口发送数据。一共会发送161个推力数据到电脑上。


你要做的是把第二个程序编译并烧录进去单片机。在火箭推力测试完后,可以把hx711和单片机的线拆下来,但AT24C08和单片机的线不要弄下来,因为这个程序用到。烧录前要打开串口助手,STC_ISP是自戴串口助手的,在STC_ISP右边点击串口助手,然后在上面选择‘字符格式显示’、‘下载后打开串口’、COM那里和你在STC_ISP左边的COM选择是一样的,在我的电脑是COM5,但在你的电脑是不一样的,不会设置就上网查。在串口那里就可以看到发回来的数据,记住,发回来的数据的单位是克。
pic


这便是STC_ISP自戴的串口助手


pic


这是我用手推那个称重传感器时的力的数据,直接发送到串口上,一共有161个数据。一开始的是‘F:’,即力。第一个数据‘15’可以看到它和其他数据是用‘/’隔开的,这个数据是火箭没产生推力时的传感器传回来的力的数据,这个数据主要是用来校准的,因为由于温度和传感器放置的竖直程度会造成偏差。处理数据时需要用每一个数据减去这个初始的数据才是真正的推力数据。
还要说一点是,当你从反方向推那个传感器时,会得到个超大的值,是错误的,这靠你们自己去判断
如果要计算比冲,可以用一个叫maple的数学软件,它可以用来计算积分,这是我大学物理 老师告诉我的,但我还没时间去学。因为实在是挺忙的。我是机械专业的,现在要学SolidWorks,一个机械绘图软件,还要弄单片机,有很多东西要看,还有作业,所以说我的大学并不轻松啊。
最后说一下我的这个推力装置的优点:
1.    成本低,成本在100块钱左右(没有支架)
2.    测试时不用和电脑相连,数据直接存在AT24C08中。
3.    得到的数据只需要做一个简单的减法,即减去初始的值,就得到真实的推力。
然后应该也就没了,就暂时告一段落。加速度传感器和气压传感器应该只能是在暑假后才能发上来。如果有错误或建议,请指出。

[修改于 4 年前 - 2015-05-25 20:19:30]

+1  学术分    虎哥   2015-05-25   讲解详细,原理描述清晰
2015-5-25 17:11:25
沙暴(作者)
1楼
终于弄完,累

[修改于 4 年前 - 2015-05-25 20:21:02]

折叠评论
加载评论中,请稍候...
折叠评论
2015-5-27 22:23:34
2015-5-27 22:23:34
沙暴(作者)
2楼
没想到这么久,竟然一个回复也没有
折叠评论
加载评论中,请稍候...
折叠评论
3楼
暖暖~[s:27]
折叠评论
加载评论中,请稍候...
折叠评论
2015-5-28 01:43:50
4楼
楼主很牛逼。

这个帖子可以看作KC推力计的51单片机实现,原理都是完全相同的。
提一点:
数据出来之后,比冲的积分可以用excel来做嘛,所有的采样点加起来,除以采样频率就行了。
折叠评论
加载评论中,请稍候...
折叠评论
2015-5-29 06:59:00
2015-5-29 06:59:00
沙暴(作者)
5楼
数据出来之后,比冲的积分可以用excel来做嘛,所有的采样点加起来,除以采样频率就行了。
多谢,你的话使我恍然大悟,这种做法用了微积分的思想
折叠评论
加载评论中,请稍候...
折叠评论
6楼
顶一下
折叠评论
加载评论中,请稍候...
折叠评论
2015-5-30 17:16:58
2015-5-30 17:16:58
7楼
很不错,学习了!



其实那三个帖子基本就是同一个东西...
折叠评论
加载评论中,请稍候...
折叠评论
2015-5-31 10:20:22
8楼
其实,,,,买个采集卡,,,一切都搞定了。。
折叠评论
加载评论中,请稍候...
折叠评论
9楼
还要标定。。
折叠评论
加载评论中,请稍候...
折叠评论
沙暴(作者)
10楼
其实,,,,买个采集卡,,,一切都搞定了。。
采集卡是什么
折叠评论
加载评论中,请稍候...
折叠评论
2015-6-4 15:23:38
2015-6-4 15:23:38
11楼
厉害!加油!学习了。
折叠评论
加载评论中,请稍候...
折叠评论
2015-6-25 15:49:38
2015-6-25 15:49:38
12楼
楼主牛[s::lol]
折叠评论
加载评论中,请稍候...
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

{{submitted?"":"投诉"}}
请选择违规类型:
{{reason.description}}
支持的图片格式:jpg, jpeg, png