JeVoisBase  1.21
JeVois Smart Embedded Machine Vision Toolkit Base Modules
Share this page:
Loading...
Searching...
No Matches
DemoIMU.C
Go to the documentation of this file.
1// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2//
3// JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4// California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5//
6// This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7// redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8// Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10// License for more details. You should have received a copy of the GNU General Public License along with this program;
11// if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12//
13// Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14// Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16/*! \file */
17
18#include <jevois/Core/Module.H>
20#include <jevois/Debug/Timer.H>
21
23#include <linux/videodev2.h>
24#include <list>
25
26// icon by icons8
27
28static jevois::ParameterCategory const ParamCateg("DemoIMU Options");
29
30//! Parameter \relates DemoIMU
31JEVOIS_DECLARE_PARAMETER(afac, float, "Factor applied to acceleration values for display, or 0 to not display",
32 100.0F, ParamCateg);
33
34//! Parameter \relates DemoIMU
35JEVOIS_DECLARE_PARAMETER(gfac, float, "Factor applied to gyroscope values for display, or 0 to not display",
36 0.5F, ParamCateg);
37
38//! Parameter \relates DemoIMU
39JEVOIS_DECLARE_PARAMETER(mfac, float, "Factor applied to magnetometer values for display, or 0 to not display",
40 3.0F, ParamCateg);
41
42//! Plot raw IMU readings on top of video
43/*! As an optional hardware upgrade, one can install a global shutter sensor into JeVois (an OnSemi AR0135 1.2MP), which
44 also includes on its custom circuit board for JeVois an inertial measurement unit (IMU). The IMU is a
45 9-degrees-of-freedom (9DOF) TDK InvenSense ICM-20948 (with 3-axis accelerometer, 3-axis gyroscope, and 3-axis
46 magnetometer). This IMU also includes a digital motion processing unit (small programmable processor inside the IMU
47 chip), which allows it to compute and filter Euler angles or quaternions directly inside the IMU chip.
48
49 This module only works with optional JeVois sensors that include an IMU! The base JeVois-A33 smart camera does not
50 have an onboard IMU.
51
52 \youtube{MFGpN_Vp7mg}
53
54 This module demonstrates the RAW and FIFO modes of the IMU.
55
56 The specifications of this chip are quite impressive:
57 - 3-axis 16-bit accelerometer with full-range sensitivity selectable to +/-2g, +/-4g, +/-8g, and +/-16g.
58 - Accelerometer data rate from 4 Hz to 1125 Hz.
59 - 3-axis 16-bit gyroscope with full-range sensitivity selectable to +/-250dps (degrees/s), +/-500dps,
60 +/-1000dps, and +/-2000dps.
61 - Gyroscope data rate from 4 Hz to 1125 Hz.
62 - 3-axis 16-bit magnetometer (compass) with wide range of +/-4900uT (micro Tesla).
63 - Magnetometer data rates 10 Hz, 20 Hz, 50 Hz, or 100 Hz.
64 - 16-bit temperature sensor with readout rate of up to 8 kHz.
65 - RAW data mode (get current sensor values at any time), buffered (FIFO) data mode (sensor values accumulate into
66 a FIFO at a fixed rate), and digital motion processing mode (DMP; raw data is processed on-chip).
67 - On-chip digital motion processor (DMP) can compute, inside the IMU chip itself:
68 + quaternion 6 (uses accel + gyro),
69 + quaternion 9 (uses accel + gyro + compass),
70 + geomag quaternion (uses accel + compass),
71 + flip/pickup detection,
72 + step detection and counting,
73 + basic activity recognition: drive, walk, run, bike, tilt, still.
74
75 With quaternions computed on-chip, with an algorithm that gets sensor data at a highly accurate, fixed rate, and
76 applies various calibrations, drift corrections, and compensations on the fly, one gets highly accurate real-time
77 estimate of the sensor's pose in the 3D world and of how it is moving.
78
79 Note that communication with the IMU is over a 400kHz I2C bus, which may limit data readout rate depending on
80 which data is requested from the IMU.
81
82 This IMU has 3 basic modes of operation (parameter mode, which can only be set in params.cfg):
83
84 - RAW: One can access the latest raw sensor data at any time using the getRaw() or get() functions. This is the
85 simplest mode of operation. One disadvantage is that if you are not calling get() at a perfectly regular
86 interval, there will be some time jitter in your readouts. The IMU does not provide any time stamps for its
87 data.
88
89 - FIFO: In this mode, data from the sensor is piled up into a 1 kbyte FIFO buffer at a precise, constant rate
90 (when all three of accelerometer, gyroscope, and magnetometer are on, the gyro rate determines the FIFO
91 buffering rate). Main advantage is that you can then read out the data without having to worry about calling
92 getRaw() or get() at a highly precise interval. But you need to be careful that the FIFO can fill up and
93 overflow very quickly when using high sensor data rates.
94
95 - DMP: In this mode, data is captured from the sensor at an accurate, fixed rate, and is fed to the on-chip
96 digital motion processor (DMP). The DMP then computes quaternions, activity recognition, etc and pushes data
97 packets into the FIFO as results from these algorithms become available.
98
99 @author Laurent Itti
100
101 @videomapping YUYV 640 512 30.0 YUYV 640 480 30.0 JeVois DemoIMU
102 @email itti\@usc.edu
103 @address University of Southern California, HNB-07A, 3641 Watt Way, Los Angeles, CA 90089-2520, USA
104 @copyright Copyright (C) 2018 by Laurent Itti, iLab and the University of Southern California
105 @mainurl http://jevois.org
106 @supporturl http://jevois.org/doc
107 @otherurl http://iLab.usc.edu
108 @license GPL v3
109 @distribution Unrestricted
110 @restrictions None
111 \ingroup modules */
112class DemoIMU : public jevois::Module, public jevois::Parameter<afac, gfac, mfac>
113{
114 public:
115 //! Constructor
116 DemoIMU(std::string const & instance) : jevois::Module(instance)
117 { itsIMU = addSubComponent<jevois::ICM20948>("imu"); }
118
119 //! Virtual destructor for safe inheritance
120 virtual ~DemoIMU() { }
121
122 //! Processing function
123 virtual void process(jevois::InputFrame && inframe, jevois::OutputFrame && outframe) override
124 {
125 // Wait for next available camera image:
126 jevois::RawImage const inimg = inframe.get(true);
127 unsigned int const w = inimg.width, h = inimg.height;
128
129 // Wait for an image from our gadget driver into which we will put our results:
130 jevois::RawImage outimg = outframe.get();
131
132 // Enforce that the input and output formats and image sizes match:
133 outimg.require("output", w, h + 32, inimg.fmt);
134
135 // Just copy the pixel data over:
136 memcpy(outimg.pixelsw<void>(), inimg.pixels<void>(), std::min(inimg.buf->length(), outimg.buf->length()));
138
139 // Let camera know we are done processing the input image:
140 inframe.done();
141
142 // Get one or more IMU readings:
143 jevois::IMUdata d = itsIMU->get();
145 jevois::sformat("Accel: x=%+06.2fg y=%+06.2fg z=%+06.2fg Magn: %+09.2fuT %+09.2fuT %+09.2fuT",
146 d.ax(), d.ay(), d.az(), d.mx(), d.my(), d.mz()),
147 3, h + 3, jevois::yuyv::White);
148
150 jevois::sformat("Gyro: x=%+07.1fdps y=%+07.1fdps z=%+07.1fdps Temp: %05.1fC %s",
151 d.gx(), d.gy(), d.gz(), d.temp(), d.magovf ? "Magn overflow" : " "),
152 3, h + 15, jevois::yuyv::White);
153
154 itsIMUdata.push_front(d);
155
156 // In FIFO mode at high data rates, we may have more samples in the FIFO; read a bunch:
157 while (itsIMU->dataReady() > 32) itsIMUdata.push_front(itsIMU->get());
158
159 // Only keep as much data as we can display:
160 while (itsIMUdata.size() > w/2) itsIMUdata.pop_back();
161
162 // Plot the IMU data:
163 float const hh = h * 0.5F; int x = w - 1;
164 // Plot so that positive values go up (so, negate all values):
165 float const a = -afac::get(); float const g = -gfac::get(); float const m = -mfac::get();
166 jevois::IMUdata const * pd = nullptr;
167
168 for (jevois::IMUdata const & dd : itsIMUdata)
169 {
170 if (pd)
171 {
172 if (a)
173 {
174 jevois::rawimage::drawLine(outimg, x + 2, pd->ax()*a + hh, x, dd.ax()*a + hh, 1, jevois::yuyv::DarkGreen);
175 jevois::rawimage::drawLine(outimg, x + 2, pd->ay()*a + hh, x, dd.ay()*a + hh, 1, jevois::yuyv::MedGreen);
176 jevois::rawimage::drawLine(outimg, x + 2, pd->az()*a + hh, x, dd.az()*a + hh, 1, jevois::yuyv::LightGreen);
177 }
178
179 if (g)
180 {
181 jevois::rawimage::drawLine(outimg, x + 2, pd->gx()*g + hh, x, dd.gx()*g + hh, 1, jevois::yuyv::DarkPink);
182 jevois::rawimage::drawLine(outimg, x + 2, pd->gy()*g + hh, x, dd.gy()*g + hh, 1, jevois::yuyv::MedPink);
183 jevois::rawimage::drawLine(outimg, x + 2, pd->gz()*g + hh, x, dd.gz()*g + hh, 1, jevois::yuyv::LightPink);
184 }
185
186 if (m)
187 {
188 jevois::rawimage::drawLine(outimg, x + 2, pd->mx()*m + hh, x, dd.mx()*m + hh, 1, jevois::yuyv::DarkTeal);
189 jevois::rawimage::drawLine(outimg, x + 2, pd->my()*m + hh, x, dd.my()*m + hh, 1, jevois::yuyv::MedTeal);
190 jevois::rawimage::drawLine(outimg, x + 2, pd->mz()*m + hh, x, dd.mz()*m + hh, 1, jevois::yuyv::LightTeal);
191 }
192
193 }
194 pd = &dd;
195 x -= 2;
196 }
197
198 // Send the output image with our processing results to the host over USB:
199 outframe.send();
200 }
201
202#ifdef JEVOIS_PRO
203 //! Processing function with GUI output
204 virtual void process(jevois::InputFrame && inframe, jevois::GUIhelper & helper) override
205 {
206 static jevois::Timer timer("processing", 100, LOG_DEBUG);
207
208 // Start the GUI frame:
209 unsigned short winw, winh;
210 helper.startFrame(winw, winh);
211
212 // Draw the camera frame:
213 int x = 0, y = 0; unsigned short iw = 0, ih = 0;
214 helper.drawInputFrame("camera", inframe, x, y, iw, ih);
215 helper.itext("JeVois-Pro Inertial Measurement Unit (IMU)");
216
217 // Let camera know we are done processing the input image:
218 inframe.done();
219
220 timer.start();
221
222 // Get one or more IMU readings:
223 jevois::IMUdata d = itsIMU->get();
224 helper.itext(jevois::sformat("Accel: x=%+06.2fg y=%+06.2fg z=%+06.2fg "
225 "Magn: %+09.2fuT %+09.2fuT %+09.2fuT",
226 d.ax(), d.ay(), d.az(), d.mx(), d.my(), d.mz()));
227
228 helper.itext(jevois::sformat("Gyro: x=%+07.1fdps y=%+07.1fdps z=%+07.1fdps Temp: %05.1fC %s",
229 d.gx(), d.gy(), d.gz(), d.temp(), d.magovf ? "Magn overflow" : " "));
230
231 itsIMUdata.push_front(d);
232
233 // In FIFO mode at high data rates, we may have more samples in the FIFO; read a bunch:
234 while (itsIMU->dataReady() > 32) itsIMUdata.push_front(itsIMU->get());
235
236 // Only keep as much data as we can display:
237 int const count = 300;
238 while (itsIMUdata.size() > count) itsIMUdata.pop_back();
239
240 float ax[count] = {}, ay[count] = {}, az[count] = {};
241 float gx[count] = {}, gy[count] = {}, gz[count] = {};
242 float mx[count] = {}, my[count] = {}, mz[count] = {};
243
244 // Plot so that positive values go up (so, negate all values):
245 float const a = -afac::get(); float const g = -gfac::get(); float const m = -mfac::get();
246
247 for (int i = count - 1; jevois::IMUdata const & dd : itsIMUdata)
248 {
249 if (a) { ax[i] = dd.ax() * a; ay[i] = dd.ay() * a; az[i] = dd.az() * a; }
250 if (g) { gx[i] = dd.gx() * g; gy[i] = dd.gy() * g; gz[i] = dd.gz() * g; }
251 if (m) { mx[i] = dd.mx() * m; my[i] = dd.my() * m; mz[i] = dd.mz() * m; }
252 --i;
253 }
254
255 // Draw the data:
256 if (ImGui::Begin("IMU data"))
257 {
258 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - 10.0F);
259 ImGui::Text("Acceleration X, Y, Z:");
260 ImGui::PlotLines("##AccelX", ax, count, 0, "Accel X", -100, 100);
261 ImGui::PlotLines("##AccelY", ay, count, 0, "Accel Y", -100, 100);
262 ImGui::PlotLines("##AccelZ", az, count, 0, "Accel Z", -100, 100);
263 ImGui::Separator();
264 ImGui::Text("Gyroscope X, Y, Z:");
265 ImGui::PlotLines("##GyroX", gx, count, 0, "Gyro X", -100, 100);
266 ImGui::PlotLines("##GyroY", gy, count, 0, "Gyro Y", -100, 100);
267 ImGui::PlotLines("##GyroZ", gz, count, 0, "Gyro Z", -100, 100);
268 ImGui::Separator();
269 ImGui::Text("Magnetometer X, Y, Z:");
270 ImGui::PlotLines("##MagnX", mx, count, 0, "Magn X", -100, 100);
271 ImGui::PlotLines("##MagnY", my, count, 0, "Magn Y", -100, 100);
272 ImGui::PlotLines("##MagnZ", mz, count, 0, "Magn Z", -100, 100);
273 ImGui::PopItemWidth();
274 }
275 ImGui::End();
276
277 // Show processing fps:
278 std::string const & fpscpu = timer.stop();
279 helper.iinfo(inframe, fpscpu, winw, winh);
280
281 // Render the image and GUI:
282 helper.endFrame();
283 }
284#endif
285
286 private:
287 std::shared_ptr<jevois::ICM20948> itsIMU;
288 std::list<jevois::IMUdata> itsIMUdata;
289};
290
291// Allow the module to be loaded as a shared object (.so) file:
JEVOIS_REGISTER_MODULE(ArUcoBlob)
int h
Plot raw IMU readings on top of video.
Definition DemoIMU.C:113
virtual ~DemoIMU()
Virtual destructor for safe inheritance.
Definition DemoIMU.C:120
JEVOIS_DECLARE_PARAMETER(gfac, float, "Factor applied to gyroscope values for display, or 0 to not display", 0.5F, ParamCateg)
Parameter.
JEVOIS_DECLARE_PARAMETER(mfac, float, "Factor applied to magnetometer values for display, or 0 to not display", 3.0F, ParamCateg)
Parameter.
DemoIMU(std::string const &instance)
Constructor.
Definition DemoIMU.C:116
JEVOIS_DECLARE_PARAMETER(afac, float, "Factor applied to acceleration values for display, or 0 to not display", 100.0F, ParamCateg)
Parameter.
virtual void process(jevois::InputFrame &&inframe, jevois::GUIhelper &helper) override
Processing function with GUI output.
Definition DemoIMU.C:204
virtual void process(jevois::InputFrame &&inframe, jevois::OutputFrame &&outframe) override
Processing function.
Definition DemoIMU.C:123
friend friend class Module
void drawInputFrame(char const *name, InputFrame const &frame, int &x, int &y, unsigned short &w, unsigned short &h, bool noalias=false, bool casync=false)
bool startFrame(unsigned short &w, unsigned short &h)
void iinfo(jevois::InputFrame const &inframe, std::string const &fpscpu, unsigned short winw=0, unsigned short winh=0)
void itext(char const *txt, ImU32 const &col=IM_COL32_BLACK_TRANS, int line=-1)
unsigned int fmt
T const * pixels() const
unsigned int width
unsigned int height
void require(char const *info, unsigned int w, unsigned int h, unsigned int f) const
std::shared_ptr< VideoBuf > buf
std::string const & stop(double *seconds)
void writeText(RawImage &img, std::string const &txt, int x, int y, unsigned int col, Font font=Font6x10)
void drawFilledRect(RawImage &img, int x, int y, unsigned int w, unsigned int h, unsigned int col)
void drawLine(RawImage &img, int x1, int y1, int x2, int y2, unsigned int thick, unsigned int col)
std::string sformat(char const *fmt,...) __attribute__((format(__printf__
unsigned short constexpr Black
unsigned short constexpr LightPink
unsigned short constexpr White
unsigned short constexpr DarkTeal
unsigned short constexpr LightTeal
unsigned short constexpr MedGreen
unsigned short constexpr DarkPink
unsigned short constexpr DarkGreen
unsigned short constexpr LightGreen
unsigned short constexpr MedPink
unsigned short constexpr MedTeal
float & temp()