Principle
We usually use a general mathematical equation to calculate the velocity:
If we want to calculate the velocity of the rotary encoder, the changed position should be changed radian.
Implementation
The BISS communication protocol is usually used for reading position information from the encoder. At present We don't need to consider the details of BISS, we only need to know there is a sample frequency to fetch the encoding information. In our application, the sample frequency is:
The general solution uses an array in VHDL to store consecutive position information, then let the latest position minus the oldest position, and finally divide the period elapsed.
Confirm the number of elements of the array
Actually, we can choose the number of elements arbitrarily, but in our application, we need to simulate the scenario that 26 elements are collected at the frequency of 2000 HZ because our algorithm engineer thought the velocity calculated under this case is good, and our system control frequency is 2000HZ. Therefore the velocity calculation equation is below:
If we want to completely mimic the computation above, we have to know how many times the system control frequency over the encoder sample frequency. This number is calculated below:
Then we use this number to multiply 25, the result is our array's size. It equals 168.
The VHDL implementation
Firstly I define a constant to indicate the number of elements in an array:
constant Buffer_Size : integer := 169;
Then we build the array type and then instantiate it.
type encoder_buffer is array (0 to Buffer_Size) of std_logic_vector(31 downto 0);
signal buffer_position : encoder_buffer := (others => (others => '0'));
The main part of calculating velocity is below:
VELOCITY_CALCULATE : process (CLK)
constant full_range : integer := 2**Encoder_BitWidth;
constant one_quater_full_range : integer := 2**(Encoder_BitWidth - 2);
constant three_quater_full_range : integer := 3*(2**(Encoder_BitWidth - 2));
variable velocity_integer : integer := 0;
variable current_p : integer := 0;
variable previous_p : integer := 0;
begin
if (CLK'event and CLK = '1') then
if sig_biss_latching_falling = '1' then
l_encoder: for i in 0 to (Buffer_Size - 1) loop
buffer_position(i + 1) <= buffer_position(i);
end loop;
buffer_position(0) <= sig_position;
current_p := to_integer(unsigned(buffer_position(0)));
previous_p := to_integer(unsigned(buffer_position(Buffer_Size)));
if current_p < one_quater_full_range and previous_p > three_quater_full_range then
velocity_integer := current_p - previous_p + full_range;
elsif current_p > three_quater_full_range and previous_p < one_quater_full_range then
velocity_integer := current_p - previous_p - full_range;
else
velocity_integer := current_p - previous_p;
end if;
sig_veloctiy <= std_logic_vector(to_signed(velocity_integer*80, 32));
end if;
end if;
end process;