Author Topic: DIY Digital Caliper  (Read 1115 times)

0 Members and 1 Guest are viewing this topic.

Offline MitkoDyakovTopic starter

  • Newbie
  • Posts: 9
  • Country: bg
DIY Digital Caliper
« on: April 22, 2024, 08:36:33 am »
Hey!

I am trying to design a digital caliper. So far I have got my hands on a couple of cheap calipers and a few papers and patents. I have create footprints for both the scale and the sensor board and seem to be working quite well. You can follow the build log (link in the bottom) for more details, also the footprints are available if you want to check them out too. 

https://hackaday.io/project/194778-diy-digital-caliper

The difficulties I am having now are connected with conditioning of the signal I am receiving. 

I used this schema to get a reading with my scope



The result is as follows:



Now from what I gather I need to amplify or at least buffer this signal, then transform it to a sine wave and then detect the zero crossing. Compare the phase shift to a base sine frequency to determine the direction and displacement.

1. Are my assumption of how the thing works correct at the first place?
2. What should I be looking for when designing the amplification circuit?
3. How do I choose R/C values for creating my sine? 
4. How do I detect zero crossing when my sine wave does not go negative?

Cheers,
M
 

Offline ali_asadzadeh

  • Super Contributor
  • ***
  • Posts: 1907
  • Country: ca
Re: DIY Digital Caliper
« Reply #1 on: April 22, 2024, 09:41:19 am »
Just following the project, I think you can either choose hardware zero cross detection, say you would make an op-amp comparator with the one side of op-amp set to mid VCC scale, which does not works perfectly or you could choose the second option which is to apply DSP algorithms to Detect Zero crossing, which needs reading the wave form with ADC and apply some math formulas to it, and extract zero crossing.
« Last Edit: April 22, 2024, 09:45:45 am by ali_asadzadeh »
ASiDesigner, Stands for Application specific intelligent devices
I'm a Digital Expert from 8-bits to 64-bits
 

Offline tszaboo

  • Super Contributor
  • ***
  • Posts: 7401
  • Country: nl
  • Current job: ATEX product design
Re: DIY Digital Caliper
« Reply #2 on: April 22, 2024, 10:32:34 am »
For a quadrature encoder, which things are based on, you need two signals. So I'm going to assume you are only showing one of the signals. I think some of the issue comes from the 22 MOhm value that you have on the board. A smaller value would probably make the signal cleaner.
Then about how to amplify the signal: Comparators. You feed the output of the opamp into a comparator with hysteresis (feedback resistor from  the output to the DC input).
 

Offline MitkoDyakovTopic starter

  • Newbie
  • Posts: 9
  • Country: bg
Re: DIY Digital Caliper
« Reply #3 on: April 22, 2024, 11:27:27 am »
For a quadrature encoder, which things are based on, you need two signals. So I'm going to assume you are only showing one of the signals. I think some of the issue comes from the 22 MOhm value that you have on the board. A smaller value would probably make the signal cleaner.
Then about how to amplify the signal: Comparators. You feed the output of the opamp into a comparator with hysteresis (feedback resistor from  the output to the DC input).



The dotted line on the first row is the resultant sine wave if sense pad is located on top of all excitation pads. I call this the base frequency, mind you that it does not exists physically (you can't measure it with a scope). 

And depending which way you shift the caliper head the resulting sine wave you measure on the sense pad get phase shifted to the right or to the left.

So I don't have two signal in the sense that a quadrature encoder has, but rather one signal to measure to determine the phase shift.
 

Offline moffy

  • Super Contributor
  • ***
  • Posts: 1761
  • Country: au
Re: DIY Digital Caliper
« Reply #4 on: April 22, 2024, 12:25:23 pm »
You are talking about a sine wave but it looks like you are using a square wave for excitation is that the case?
 

Offline MitkoDyakovTopic starter

  • Newbie
  • Posts: 9
  • Country: bg
Re: DIY Digital Caliper
« Reply #5 on: April 22, 2024, 01:52:11 pm »
You are talking about a sine wave but it looks like you are using a square wave for excitation is that the case?

This is correct. The signals bellow are one of four pair of signal generated. Each pear is shifter 90 deg from the one before it. And inside the pair each signal is 180 degree shifted.



You can see that it is PWM with variable duty cycle. In my mind this is like digitizing the sine wave and encode the duty cycle corresponding to each sample point.


*in my case it does not go negative just goes to 0

 

Offline moffy

  • Super Contributor
  • ***
  • Posts: 1761
  • Country: au
Re: DIY Digital Caliper
« Reply #6 on: April 22, 2024, 08:09:13 pm »
That makes some sense, I think personally, that I would filter the PWM signal to sinusoidal before applying it to the sensor, that way you are only adding sine waves of a single frequency and you have a direct comparison between excitation and output without the need of phase shifting filters. You might need a  buffer amp, that's a small disadvantage but it would make problem solving much easier to visualise, even if it is only for development purposes.
 

Offline ali_asadzadeh

  • Super Contributor
  • ***
  • Posts: 1907
  • Country: ca
Re: DIY Digital Caliper
« Reply #7 on: April 23, 2024, 08:25:12 am »
MitkoDyakov would you please share kicad project files including schematic and PCB into the project repo, also for easier access please mention the GitHub repo in here too.

This is a working Zero crossing code that I have implemented before on some industrial equipment, it uses 64 samples per sine wave cycle to calculate the Zero crossing

Code: [Select]
#define ADC_samples 64

//we need two cycles to calculate the Frequency, ok!
short oldSamples[128];

const int BLOCK_SIZE =ADC_samples;
const int NUM_TAPS =32;
arm_fir_instance_q15 S;
q15_t firStateF32[BLOCK_SIZE + NUM_TAPS - 1];

q15_t firCoeffs32[NUM_TAPS] = {
       -1,     -2,      8,     39,     83,     97,     14,   -213,   -535,
     -762,   -596,    232,   1778,   3773,   5659,   6810,   6810,   5659,
     3773,   1778,    232,   -596,   -762,   -535,   -213,     14,     97,
       83,     39,      8,     -2,     -1
};


void init_myFilter(void){
/* Call FIR init function to initialize the instance structure. */
  arm_fir_init_q15(&S, NUM_TAPS, firCoeffs32, firStateF32, BLOCK_SIZE);
}

void dsp_zero_cross(short* input,int size,float* zero_1st,float* zero_2st, float* zero_3st)
{
int i;
float first_zero = 0,second_zero = 0,third_zero = 0;
    int index[4] = {0};
    int index_index = 0;
int x1 = 0;
int x2 = 0;
int x3 = 0;
short temp[ADC_samples];
//first copy from the last portion to the first portion
for(i=64;i<128;i++)
oldSamples[i-64] = oldSamples[i];
//now copy the input to the last portion
for(i=64;i<128;i++)
oldSamples[i]= input[i-64];


arm_fir_fast_q15(&S,oldSamples,temp,BLOCK_SIZE);
arm_fir_fast_q15(&S,oldSamples+64,temp,BLOCK_SIZE);


for (i = 1; i < size; i++)
  {
if((temp[i]<=0 && temp[i-1]>0) || (temp[i]>=0 && temp[i-1]<0))
    {
      index[index_index] = i;
      index_index++;
if(index_index == 4)
{
break;
}
    }
  }

  if(index_index == 0)
{
*zero_2st=-1;
    *zero_1st=-1;
*zero_3st=-1;
return;
}
  else if(index_index == 1)
{
*zero_2st=-1;
*zero_1st=-1;
*zero_3st=-1;
return;
}
  else if (index_index == 2)
  {
x1 = index[0];
x2 = index[1];
if((temp[x1 - 1] - temp[x1]) == 0 || (temp[x1 + 1] - temp[x1]) == 0 || (temp[x2 - 1] - temp[x2]) == 0  || (temp[x2 + 1] - temp[x2]) == 0 || x2 == (size - 1) || x1 == (size - 1))
{
*zero_2st=-1;
*zero_1st=-1;
*zero_3st=-1;
            return;
}
else
{
first_zero = ((float)(temp[x1] * temp[x1 + 1])/((float)(temp[x1 - 1] - temp[x1])*(float)(temp[x1 - 1] - temp[x1 + 1]))) * (x1 - 1);
first_zero += ((float)(temp[x1 - 1] * temp[x1 + 1])/((float)(temp[x1] - temp[x1 - 1])*(float)(temp[x1] - temp[x1+ 1]))) * (x1);
first_zero += ((float)(temp[x1 - 1] * temp[x1])/((float)(temp[x1 + 1] - temp[x1 - 1])*(float)(temp[x1 + 1] - temp[x1]))) * (x1 + 1);
////////////////////
second_zero = ((float)(temp[x2] * temp[x2 + 1])/((float)(temp[x2 - 1] - temp[x2])*(float)(temp[x2 - 1] - temp[x2 + 1]))) * (x2 - 1);
second_zero += ((float)(temp[x2 - 1] * temp[x2 + 1])/((float)(temp[x2] - temp[x2- 1])*(float)(temp[x2] - temp[x2 + 1]))) * (x2);
second_zero += ((float)(temp[x2 - 1] * temp[x2])/((float)(temp[x2 + 1] - temp[x2 - 1])*(float)(temp[x2 + 1] - temp[x2]))) * (x2 + 1);
*zero_1st = first_zero;
*zero_2st = second_zero;
*zero_3st=-1;
return;
}
  }
else if (index_index == 3)
{
x1 = index[0];
x2 = index[1];
x3 = index[2];
if((temp[x1 - 1] - temp[x1]) == 0 || (temp[x1 + 1] - temp[x1]) == 0 || (temp[x2 - 1] - temp[x2]) == 0  || (temp[x2 + 1] - temp[x2]) == 0|| (temp[x3 - 1] - temp[x3]) == 0  || (temp[x3 + 1] - temp[x3]) == 0 || x3 == (size - 1) || x2 == (size - 1) || x1 == (size - 1))
{
*zero_2st=-1;
*zero_1st=-1;
*zero_3st=-1;
            return;
}
else
{
first_zero = ((float)(temp[x1] * temp[x1 + 1])/((float)(temp[x1 - 1] - temp[x1])*(float)(temp[x1 - 1] - temp[x1 + 1]))) * (x1 - 1);
first_zero += ((float)(temp[x1 - 1] * temp[x1 + 1])/((float)(temp[x1] - temp[x1 - 1])*(float)(temp[x1] - temp[x1+ 1]))) * (x1);
first_zero += ((float)(temp[x1 - 1] * temp[x1])/((float)(temp[x1 + 1] - temp[x1 - 1])*(float)(temp[x1 + 1] - temp[x1]))) * (x1 + 1);
////////////////////
second_zero = ((float)(temp[x2] * temp[x2 + 1])/((float)(temp[x2 - 1] - temp[x2])*(float)(temp[x2 - 1] - temp[x2 + 1]))) * (x2 - 1);
second_zero += ((float)(temp[x2 - 1] * temp[x2 + 1])/((float)(temp[x2] - temp[x2- 1])*(float)(temp[x2] - temp[x2 + 1]))) * (x2);
second_zero += ((float)(temp[x2 - 1] * temp[x2])/((float)(temp[x2 + 1] - temp[x2 - 1])*(float)(temp[x2 + 1] - temp[x2]))) * (x2 + 1);
///////////////////
third_zero = ((float)(temp[x3] * temp[x3 + 1])/((float)(temp[x3 - 1] - temp[x3])*(float)(temp[x3 - 1] - temp[x3 + 1]))) * (x3 - 1);
third_zero += ((float)(temp[x3 - 1] * temp[x3 + 1])/((float)(temp[x3] - temp[x3 - 1])*(float)(temp[x3] - temp[x3+ 1]))) * (x3);
third_zero += ((float)(temp[x3 - 1] * temp[x3])/((float)(temp[x3 + 1] - temp[x3 - 1])*(float)(temp[x3 + 1] - temp[x3]))) * (x3 + 1);
*zero_1st = first_zero;
*zero_2st = second_zero;
*zero_3st= third_zero;
}
}

}

ASiDesigner, Stands for Application specific intelligent devices
I'm a Digital Expert from 8-bits to 64-bits
 

Offline MitkoDyakovTopic starter

  • Newbie
  • Posts: 9
  • Country: bg
Re: DIY Digital Caliper
« Reply #8 on: April 23, 2024, 07:35:37 pm »
You can find the all I have here: https://github.com/MitkoDyakov/BluePillCaliper/

Documents - are all written I could find on the subject, patents, paper, work done by others.
Hardware - the footprints for the t-scale and sensor and also gerbers and schematics
Software - I need to update that but, for the software I have written just the excitation of the pads and the display.

   

 

Offline ali_asadzadeh

  • Super Contributor
  • ***
  • Posts: 1907
  • Country: ca
Re: DIY Digital Caliper
« Reply #9 on: April 24, 2024, 09:49:01 am »
Quote
Hardware - the footprints for the t-scale and sensor and also gerbers and schematics
Thanks for sharing, But it would be nicer if you could share the Kickad files for schematics and PCB, since We can modify it easier.
ASiDesigner, Stands for Application specific intelligent devices
I'm a Digital Expert from 8-bits to 64-bits
 

Offline MitkoDyakovTopic starter

  • Newbie
  • Posts: 9
  • Country: bg
Re: DIY Digital Caliper
« Reply #10 on: April 25, 2024, 06:40:55 pm »
Quote
Hardware - the footprints for the t-scale and sensor and also gerbers and schematics
Thanks for sharing, But it would be nicer if you could share the Kickad files for schematics and PCB, since We can modify it easier.

You can find it in BluePillCaliper/Hardware /Footprints - KICA
 

Offline ali_asadzadeh

  • Super Contributor
  • ***
  • Posts: 1907
  • Country: ca
Re: DIY Digital Caliper
« Reply #11 on: April 27, 2024, 07:46:47 am »
Quote
You can find it in BluePillCaliper/Hardware /Footprints - KICA
There is only footprints, Kicad project files extensions is like this .kicad_pcb .kicad_pro .sch unless, I'm missing something :'(
ASiDesigner, Stands for Application specific intelligent devices
I'm a Digital Expert from 8-bits to 64-bits
 


Offline ali_asadzadeh

  • Super Contributor
  • ***
  • Posts: 1907
  • Country: ca
ASiDesigner, Stands for Application specific intelligent devices
I'm a Digital Expert from 8-bits to 64-bits
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf