## 3D position approximation of object using magnetometer and permanent magnet

Hey everyone,

I am currently using an Arduino Uno, a permanent magnet and a magnetometer to get the x, y and z coordinates of a metal object within a small rectangular box of known size. The magnetometer and permanent magnet are separated by 5cm, and the metal object moves between them (with the theory being that the metal object blocks the magnetic field from the permanent magnet, causing the readings measured by the magnetometer to change). To prove the concept, I used Matlab to take the magnetic field strength readings (which are output as x, y and z readings) at known distances, and create a calibration curve, in which I derived the equation (I only moved the metal object in one plane). This worked great, as long as the object is along the exact path I calibrated it for.

The problem is that the metal object can move anywhere within the box, and for example, movement only in the x plane also causes change in the y and z planes magnetic field readings. This causes the distance measurements to be wrong, unless the object follows the exact path it was calibrated for. So now I have moved to calibrating the position and magnetic field data in 3D, and this is where I am stuck. I am currently measuring the magnetic field data at different positions in the 3D plane, and storing this as a .mat file for another seperate code to use in real-time to find the position. The issue is that the readings are nowhere near accurate or even representative of distance.

I appreciate any help/suggestions. Cheers.

Calibration Code

% Initialize 3D grid of positions

x_positions = 0:2.5:5; % X Positions from 0cm to 5cm in steps of 2.5cm

y_positions = 0:2.5:7.5; % Y Positions from 0cm to 7.5cm in steps of 2.5cm

z_positions = 0:2.5:5; % Z Positions from 0cm to 10cm in steps of 2.5cm

% Note increment steps can be decreased, but only once the code is working

% accurately.

% Initialize 3D arrays for magnetic field measurements

Bx = zeros(length(y_positions), length(x_positions), length(z_positions));

By = zeros(length(y_positions), length(x_positions), length(z_positions));

Bz = zeros(length(y_positions), length(x_positions), length(z_positions));

% Set up serial connection

s = serial(‘COM4’);

set(s,’BaudRate’,115200);

s.InputBufferSize = 4096; % Increase input buffer size

fopen(s);

% Number of measurements to average

num_measurements = 100;

% Loop over all positions in the grid

for i = 1:length(x_positions)

for j = 1:length(y_positions)

for k = 1:length(z_positions)

% Print current position

fprintf(‘Current position: X = %.2f cm, Y = %.2f cm, Z = %.2f cmn’, x_positions(i), y_positions(j), z_positions(k));

% Wait for user to press Enter before taking measurements

input(‘Move needle to current position and press Enter’);

% Initialize arrays to store multiple measurements

magnetic_X = zeros(num_measurements, 1);

magnetic_Y = zeros(num_measurements, 1);

magnetic_Z = zeros(num_measurements, 1);

% Take multiple measurements

for m = 1:num_measurements

% Measure magnetic field at current position

line = fgets(s);

% Check if data contains ‘X:’, ‘Y:’, and ‘Z:’ labels

if contains(line, ‘X:’) && contains(line, ‘Y:’) && contains(line, ‘Z:’)

magnetic = sscanf(line, ‘X:%f, Y:%f, Z:%f’);

% Check if magnetic has 3 elements

if length(magnetic) == 3

% Store magnetic fields in arrays

magnetic_X(m) = magnetic(1);

magnetic_Y(m) = magnetic(2);

magnetic_Z(m) = magnetic(3);

else

fprintf(‘Unexpected data format: %sn’, line);

end

else

fprintf(‘Unexpected data format: %sn’, line);

end

end

% Average the measurements and store in Bx, By, Bz

Bx(j, i, k) = mean(magnetic_X);

By(j, i, k) = mean(magnetic_Y);

Bz(j, i, k) = mean(magnetic_Z);

end

end

end

% Close serial connection

fclose(s);

% Create a 3D grid for interpolation

[X, Y, Z] = meshgrid(x_positions, y_positions, z_positions);

% Flatten and concatenate the grid coordinates

X_flat = X(:);

Y_flat = Y(:);

Z_flat = Z(:);

% Flatten and concatenate the magnetic field measurements

Bx_flat = Bx(:);

By_flat = By(:);

Bz_flat = Bz(:);

% Combine the magnetic field measurements into a matrix

B_flat = [Bx_flat, By_flat, Bz_flat];

% Train three SVM models

mdl_x = fitrsvm(B_flat, X_flat);

mdl_y = fitrsvm(B_flat, Y_flat);

mdl_z = fitrsvm(B_flat, Z_flat);

% Save to a .mat file

save(‘C:\Users\calibration_data.mat’, ‘x_positions’, ‘y_positions’, ‘z_positions’, ‘Bx’, ‘By’, ‘Bz’, ‘mdl_x’, ‘mdl_y’, ‘mdl_z’);Hey everyone,

I am currently using an Arduino Uno, a permanent magnet and a magnetometer to get the x, y and z coordinates of a metal object within a small rectangular box of known size. The magnetometer and permanent magnet are separated by 5cm, and the metal object moves between them (with the theory being that the metal object blocks the magnetic field from the permanent magnet, causing the readings measured by the magnetometer to change). To prove the concept, I used Matlab to take the magnetic field strength readings (which are output as x, y and z readings) at known distances, and create a calibration curve, in which I derived the equation (I only moved the metal object in one plane). This worked great, as long as the object is along the exact path I calibrated it for.

The problem is that the metal object can move anywhere within the box, and for example, movement only in the x plane also causes change in the y and z planes magnetic field readings. This causes the distance measurements to be wrong, unless the object follows the exact path it was calibrated for. So now I have moved to calibrating the position and magnetic field data in 3D, and this is where I am stuck. I am currently measuring the magnetic field data at different positions in the 3D plane, and storing this as a .mat file for another seperate code to use in real-time to find the position. The issue is that the readings are nowhere near accurate or even representative of distance.

I appreciate any help/suggestions. Cheers.

Calibration Code

% Initialize 3D grid of positions

x_positions = 0:2.5:5; % X Positions from 0cm to 5cm in steps of 2.5cm

y_positions = 0:2.5:7.5; % Y Positions from 0cm to 7.5cm in steps of 2.5cm

z_positions = 0:2.5:5; % Z Positions from 0cm to 10cm in steps of 2.5cm

% Note increment steps can be decreased, but only once the code is working

% accurately.

% Initialize 3D arrays for magnetic field measurements

Bx = zeros(length(y_positions), length(x_positions), length(z_positions));

By = zeros(length(y_positions), length(x_positions), length(z_positions));

Bz = zeros(length(y_positions), length(x_positions), length(z_positions));

% Set up serial connection

s = serial(‘COM4’);

set(s,’BaudRate’,115200);

s.InputBufferSize = 4096; % Increase input buffer size

fopen(s);

% Number of measurements to average

num_measurements = 100;

% Loop over all positions in the grid

for i = 1:length(x_positions)

for j = 1:length(y_positions)

for k = 1:length(z_positions)

% Print current position

fprintf(‘Current position: X = %.2f cm, Y = %.2f cm, Z = %.2f cmn’, x_positions(i), y_positions(j), z_positions(k));

% Wait for user to press Enter before taking measurements

input(‘Move needle to current position and press Enter’);

% Initialize arrays to store multiple measurements

magnetic_X = zeros(num_measurements, 1);

magnetic_Y = zeros(num_measurements, 1);

magnetic_Z = zeros(num_measurements, 1);

% Take multiple measurements

for m = 1:num_measurements

% Measure magnetic field at current position

line = fgets(s);

% Check if data contains ‘X:’, ‘Y:’, and ‘Z:’ labels

if contains(line, ‘X:’) && contains(line, ‘Y:’) && contains(line, ‘Z:’)

magnetic = sscanf(line, ‘X:%f, Y:%f, Z:%f’);

% Check if magnetic has 3 elements

if length(magnetic) == 3

% Store magnetic fields in arrays

magnetic_X(m) = magnetic(1);

magnetic_Y(m) = magnetic(2);

magnetic_Z(m) = magnetic(3);

else

fprintf(‘Unexpected data format: %sn’, line);

end

else

fprintf(‘Unexpected data format: %sn’, line);

end

end

% Average the measurements and store in Bx, By, Bz

Bx(j, i, k) = mean(magnetic_X);

By(j, i, k) = mean(magnetic_Y);

Bz(j, i, k) = mean(magnetic_Z);

end

end

end

% Close serial connection

fclose(s);

% Create a 3D grid for interpolation

[X, Y, Z] = meshgrid(x_positions, y_positions, z_positions);

% Flatten and concatenate the grid coordinates

X_flat = X(:);

Y_flat = Y(:);

Z_flat = Z(:);

% Flatten and concatenate the magnetic field measurements

Bx_flat = Bx(:);

By_flat = By(:);

Bz_flat = Bz(:);

% Combine the magnetic field measurements into a matrix

B_flat = [Bx_flat, By_flat, Bz_flat];

% Train three SVM models

mdl_x = fitrsvm(B_flat, X_flat);

mdl_y = fitrsvm(B_flat, Y_flat);

mdl_z = fitrsvm(B_flat, Z_flat);

% Save to a .mat file

save(‘C:\Users\calibration_data.mat’, ‘x_positions’, ‘y_positions’, ‘z_positions’, ‘Bx’, ‘By’, ‘Bz’, ‘mdl_x’, ‘mdl_y’, ‘mdl_z’); Hey everyone,

I am currently using an Arduino Uno, a permanent magnet and a magnetometer to get the x, y and z coordinates of a metal object within a small rectangular box of known size. The magnetometer and permanent magnet are separated by 5cm, and the metal object moves between them (with the theory being that the metal object blocks the magnetic field from the permanent magnet, causing the readings measured by the magnetometer to change). To prove the concept, I used Matlab to take the magnetic field strength readings (which are output as x, y and z readings) at known distances, and create a calibration curve, in which I derived the equation (I only moved the metal object in one plane). This worked great, as long as the object is along the exact path I calibrated it for.

The problem is that the metal object can move anywhere within the box, and for example, movement only in the x plane also causes change in the y and z planes magnetic field readings. This causes the distance measurements to be wrong, unless the object follows the exact path it was calibrated for. So now I have moved to calibrating the position and magnetic field data in 3D, and this is where I am stuck. I am currently measuring the magnetic field data at different positions in the 3D plane, and storing this as a .mat file for another seperate code to use in real-time to find the position. The issue is that the readings are nowhere near accurate or even representative of distance.

I appreciate any help/suggestions. Cheers.

Calibration Code

% Initialize 3D grid of positions

x_positions = 0:2.5:5; % X Positions from 0cm to 5cm in steps of 2.5cm

y_positions = 0:2.5:7.5; % Y Positions from 0cm to 7.5cm in steps of 2.5cm

z_positions = 0:2.5:5; % Z Positions from 0cm to 10cm in steps of 2.5cm

% Note increment steps can be decreased, but only once the code is working

% accurately.

% Initialize 3D arrays for magnetic field measurements

Bx = zeros(length(y_positions), length(x_positions), length(z_positions));

By = zeros(length(y_positions), length(x_positions), length(z_positions));

Bz = zeros(length(y_positions), length(x_positions), length(z_positions));

% Set up serial connection

s = serial(‘COM4’);

set(s,’BaudRate’,115200);

s.InputBufferSize = 4096; % Increase input buffer size

fopen(s);

% Number of measurements to average

num_measurements = 100;

% Loop over all positions in the grid

for i = 1:length(x_positions)

for j = 1:length(y_positions)

for k = 1:length(z_positions)

% Print current position

fprintf(‘Current position: X = %.2f cm, Y = %.2f cm, Z = %.2f cmn’, x_positions(i), y_positions(j), z_positions(k));

% Wait for user to press Enter before taking measurements

input(‘Move needle to current position and press Enter’);

% Initialize arrays to store multiple measurements

magnetic_X = zeros(num_measurements, 1);

magnetic_Y = zeros(num_measurements, 1);

magnetic_Z = zeros(num_measurements, 1);

% Take multiple measurements

for m = 1:num_measurements

% Measure magnetic field at current position

line = fgets(s);

% Check if data contains ‘X:’, ‘Y:’, and ‘Z:’ labels

if contains(line, ‘X:’) && contains(line, ‘Y:’) && contains(line, ‘Z:’)

magnetic = sscanf(line, ‘X:%f, Y:%f, Z:%f’);

% Check if magnetic has 3 elements

if length(magnetic) == 3

% Store magnetic fields in arrays

magnetic_X(m) = magnetic(1);

magnetic_Y(m) = magnetic(2);

magnetic_Z(m) = magnetic(3);

else

fprintf(‘Unexpected data format: %sn’, line);

end

else

fprintf(‘Unexpected data format: %sn’, line);

end

end

% Average the measurements and store in Bx, By, Bz

Bx(j, i, k) = mean(magnetic_X);

By(j, i, k) = mean(magnetic_Y);

Bz(j, i, k) = mean(magnetic_Z);

end

end

end

% Close serial connection

fclose(s);

% Create a 3D grid for interpolation

[X, Y, Z] = meshgrid(x_positions, y_positions, z_positions);

% Flatten and concatenate the grid coordinates

X_flat = X(:);

Y_flat = Y(:);

Z_flat = Z(:);

% Flatten and concatenate the magnetic field measurements

Bx_flat = Bx(:);

By_flat = By(:);

Bz_flat = Bz(:);

% Combine the magnetic field measurements into a matrix

B_flat = [Bx_flat, By_flat, Bz_flat];

% Train three SVM models

mdl_x = fitrsvm(B_flat, X_flat);

mdl_y = fitrsvm(B_flat, Y_flat);

mdl_z = fitrsvm(B_flat, Z_flat);

% Save to a .mat file

save(‘C:\Users\calibration_data.mat’, ‘x_positions’, ‘y_positions’, ‘z_positions’, ‘Bx’, ‘By’, ‘Bz’, ‘mdl_x’, ‘mdl_y’, ‘mdl_z’); signal processing, 3d, machine learning, arduino, magnetometer MATLAB Answers — New Questions