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