1+ /* *
2+ **************************************************
3+ *
4+ * @file Inkplate_6_MOTION_Accelerometer_Cube.ino
5+ * @brief This example will project a 3D cube with data from the accelerometer/gyroscope
6+ *
7+ * For info on how to quickly get started with Inkplate 6MOTION visit docs.inkplate.com
8+ *
9+ * @authors Borna Biro and Robert Soric for soldered.com
10+ * @date January 2025
11+ ***************************************************/
12+
13+ // Include the Inkplate Motion library
14+ #include < InkplateMotion.h>
15+
16+ Inkplate inkplate; // Create an Inkplate object
17+
18+ // Variables which are used for drawing the 3D Cube
19+ // Cube vertices
20+ float cube[8 ][3 ] = {{-1 , -1 , -1 }, {1 , -1 , -1 }, {1 , 1 , -1 }, {-1 , 1 , -1 }, {-1 , -1 , 1 }, {1 , -1 , 1 }, {1 , 1 , 1 }, {-1 , 1 , 1 }};
21+ // Cube edges
22+ int edges[12 ][2 ] = {
23+ {0 , 1 }, {1 , 2 }, {2 , 3 }, {3 , 0 }, // Bottom face
24+ {4 , 5 }, {5 , 6 }, {6 , 7 }, {7 , 4 }, // Top face
25+ {0 , 4 }, {1 , 5 }, {2 , 6 }, {3 , 7 } // Vertical edges
26+ };
27+ // This value multiplies the accelerometer readings to help project the cube in the orientation of the accelerometer
28+ // If you want accelerometer movements to have more effect on the cube's retation, increase this
29+ // And vice versa
30+ #define ANGLE_MODIFIER 0.008
31+
32+ // Variables for the angles at which the cube gets projected
33+ float angleX = 0 ;
34+ float angleY = 0 ;
35+ float angleZ = 0 ;
36+ // Also, remember the previous angles
37+ // This is just to calculate the average between the two in order to smooth out the movement
38+ float previousAngleX = 0 ;
39+ float previousAngleY = 0 ;
40+ float previousAngleZ = 0 ;
41+
42+ uint32_t previousTime;
43+
44+ // Setup code, runs only once
45+ void setup ()
46+ {
47+ inkplate.begin (); // Init Inkplate library (you should call this function ONLY ONCE)
48+ inkplate.display (); // Put clear image on display
49+
50+ // Set text size to be 2x larger than default (5x7px)
51+ inkplate.setTextSize (2 );
52+ inkplate.setTextColor (BLACK); // Set the text color to black also
53+
54+ // Turn on the lsm6dso32 peripheral
55+ inkplate.peripheralState (INKPLATE_PERIPHERAL_LSM6DSO32, true );
56+ delay (1000 ); // Wait a bit
57+
58+ // Try to init the acccelerometer
59+ if (!inkplate.lsm6dso32 .begin_I2C ())
60+ {
61+ // Print message to user and show it on Inkplate
62+ inkplate.println (" Couldn't init LSM6DSO32!" );
63+ inkplate.display ();
64+ while (true )
65+ ;
66+ }
67+
68+ // Gyroscope init successful!
69+ inkplate.println (" Init LSM6DSO32 OK!" );
70+ inkplate.display ();
71+ delay (1000 ); // Wait a bit so the user can see the message
72+
73+ // Let's configure it, and print config data to Inkplate
74+ // This is useful to see all the available options
75+ inkplate.lsm6dso32 .setAccelRange (LSM6DSO32_ACCEL_RANGE_16_G);
76+ inkplate.print (" Accelerometer range set to: " );
77+ switch (inkplate.lsm6dso32 .getAccelRange ())
78+ {
79+ case LSM6DSO32_ACCEL_RANGE_4_G:
80+ inkplate.println (" +-4G" );
81+ break ;
82+ case LSM6DSO32_ACCEL_RANGE_8_G:
83+ inkplate.println (" +-8G" );
84+ break ;
85+ case LSM6DSO32_ACCEL_RANGE_16_G:
86+ inkplate.println (" +-16G" );
87+ break ;
88+ case LSM6DSO32_ACCEL_RANGE_32_G:
89+ inkplate.println (" +-32G" );
90+ break ;
91+ }
92+
93+ inkplate.lsm6dso32 .setGyroRange (LSM6DS_GYRO_RANGE_500_DPS);
94+ inkplate.print (" Gyro range set to: " );
95+ switch (inkplate.lsm6dso32 .getGyroRange ())
96+ {
97+ case LSM6DS_GYRO_RANGE_125_DPS:
98+ inkplate.println (" 125 degrees/s" );
99+ break ;
100+ case LSM6DS_GYRO_RANGE_250_DPS:
101+ inkplate.println (" 250 degrees/s" );
102+ break ;
103+ case LSM6DS_GYRO_RANGE_500_DPS:
104+ inkplate.println (" 500 degrees/s" );
105+ break ;
106+ case LSM6DS_GYRO_RANGE_1000_DPS:
107+ inkplate.println (" 1000 degrees/s" );
108+ break ;
109+ case LSM6DS_GYRO_RANGE_2000_DPS:
110+ inkplate.println (" 2000 degrees/s" );
111+ break ;
112+ }
113+
114+ inkplate.lsm6dso32 .setAccelDataRate (LSM6DS_RATE_104_HZ);
115+ inkplate.print (" Accelerometer data rate set to: " );
116+ switch (inkplate.lsm6dso32 .getAccelDataRate ())
117+ {
118+ case LSM6DS_RATE_SHUTDOWN:
119+ inkplate.println (" 0 Hz" );
120+ break ;
121+ case LSM6DS_RATE_12_5_HZ:
122+ inkplate.println (" 12.5 Hz" );
123+ break ;
124+ case LSM6DS_RATE_26_HZ:
125+ inkplate.println (" 26 Hz" );
126+ break ;
127+ case LSM6DS_RATE_52_HZ:
128+ inkplate.println (" 52 Hz" );
129+ break ;
130+ case LSM6DS_RATE_104_HZ:
131+ inkplate.println (" 104 Hz" );
132+ break ;
133+ case LSM6DS_RATE_208_HZ:
134+ inkplate.println (" 208 Hz" );
135+ break ;
136+ case LSM6DS_RATE_416_HZ:
137+ inkplate.println (" 416 Hz" );
138+ break ;
139+ case LSM6DS_RATE_833_HZ:
140+ inkplate.println (" 833 Hz" );
141+ break ;
142+ case LSM6DS_RATE_1_66K_HZ:
143+ inkplate.println (" 1.66 KHz" );
144+ break ;
145+ case LSM6DS_RATE_3_33K_HZ:
146+ inkplate.println (" 3.33 KHz" );
147+ break ;
148+ case LSM6DS_RATE_6_66K_HZ:
149+ inkplate.println (" 6.66 KHz" );
150+ break ;
151+ }
152+
153+ // Show the config and wait so the user can see it
154+ inkplate.display ();
155+ delay (3000 );
156+ inkplate.clearDisplay (); // Clear what was previously on the screen
157+
158+ // Set 75 frames of partial updates for a full update
159+ inkplate.setFullUpdateTreshold (75 );
160+
161+ // Start measuring time
162+ previousTime = millis ();
163+ }
164+
165+ void loop ()
166+ {
167+ // First, clear what was previously in the frame buffer
168+ inkplate.clearDisplay ();
169+
170+ // Make sensor reading
171+ sensors_event_t accel;
172+ sensors_event_t gyro;
173+ sensors_event_t temp;
174+ inkplate.lsm6dso32 .getEvent (&accel, &gyro, &temp);
175+
176+ // Read values from the accelerometer (for display purposes)
177+ float accelX = accel.acceleration .x ;
178+ float accelY = accel.acceleration .y ;
179+ float accelZ = accel.acceleration .z ;
180+
181+ // Read values from the gyroscope
182+ float gyroX = gyro.gyro .x ;
183+ float gyroY = gyro.gyro .y ;
184+ float gyroZ = gyro.gyro .z ;
185+
186+ // Print accelerometer readings on the display
187+ inkplate.setCursor (10 , 630 );
188+ inkplate.print (" ACC X:" );
189+ inkplate.print (accelX, 4 );
190+ inkplate.setCursor (10 , 650 );
191+ inkplate.print (" ACC Y:" );
192+ inkplate.print (accelY, 4 );
193+ inkplate.setCursor (10 , 670 );
194+ inkplate.print (" ACC Z:" );
195+ inkplate.print (accelZ, 4 );
196+
197+ // Print gyroscope readings on the display also
198+ inkplate.setCursor (10 , 690 );
199+ inkplate.print (" GYRO X:" );
200+ inkplate.print (gyroX, 4 );
201+ inkplate.setCursor (10 , 710 );
202+ inkplate.print (" GYRO Y:" );
203+ inkplate.print (gyroY, 4 );
204+ inkplate.setCursor (10 , 730 );
205+ inkplate.print (" GYRO Z:" );
206+ inkplate.print (gyroZ, 4 );
207+
208+ // Calculate the time difference since the last loop
209+ unsigned long currentTime = millis ();
210+ float dt = (currentTime - previousTime) / 1000.0 ; // Convert ms to seconds
211+ previousTime = currentTime;
212+
213+ // Integrate gyroscope data to get angles
214+ angleX += gyroX * dt;
215+ angleY += gyroY * dt;
216+ angleZ += gyroZ * dt;
217+
218+ // Smoothing (average with previous angles)
219+ angleX = (angleX + previousAngleX) / 2 ;
220+ angleY = (angleY + previousAngleY) / 2 ;
221+ angleZ = (angleZ + previousAngleZ) / 2 ;
222+
223+ // Remember the values for the next loop
224+ previousAngleX = angleX;
225+ previousAngleY = angleY;
226+ previousAngleZ = angleZ;
227+
228+ // Let's project the cube's edges!
229+ for (int i = 0 ; i < 12 ; i++)
230+ {
231+ // Get the start and end vertices
232+ float *v1 = cube[edges[i][0 ]];
233+ float *v2 = cube[edges[i][1 ]];
234+
235+ // Rotate and project the vertices to 2D
236+ int x1, y1, x2, y2;
237+
238+ project (v1, angleX, angleY, angleZ, &x1, &y1);
239+ project (v2, angleX, angleY, angleZ, &x2, &y2);
240+
241+ // Draw the edge
242+ // Draw three lines, offset by one pixel each, to get a thick line effect
243+ inkplate.drawLine (x1, y1, x2, y2, BLACK);
244+ inkplate.drawLine (x1 + 1 , y1 + 1 , x2 + 1 , y2 + 1 , BLACK);
245+ inkplate.drawLine (x1 + 2 , y1 + 2 , x2 + 2 , y2 + 2 , BLACK);
246+ }
247+
248+ // Do partial (fast) update!
249+ inkplate.partialUpdate (true );
250+
251+ // Wait 1ms so the frame rate isn't too fast
252+ delay (1 );
253+ }
254+
255+ // This function projects 3D space onto 2D with a set rotation
256+ void project (float *v, float angleX, float angleY, float angleZ, int *x, int *y)
257+ {
258+ // Rotate the vertex around the X axis
259+ float xr = v[0 ];
260+ float yr = v[1 ] * cos (angleX) - v[2 ] * sin (angleX);
261+ float zr = v[1 ] * sin (angleX) + v[2 ] * cos (angleX);
262+
263+ // Rotate the vertex around the Y axis
264+ float xrr = xr * cos (angleY) + zr * sin (angleY);
265+ float yrr = yr;
266+ float zrr = -xr * sin (angleY) + zr * cos (angleY);
267+
268+ // Rotate the vertex around the Z axis
269+ float xrrr = xrr * cos (angleZ) - yrr * sin (angleZ);
270+ float yrrr = xrr * sin (angleZ) + yrr * cos (angleZ);
271+ float zrrr = zrr;
272+
273+ // Project the vertex to 2D
274+ float z = 4 / (4 + zrrr);
275+ *x = xrrr * z * 100 + inkplate.width () / 2 ;
276+ *y = yrrr * z * 100 + inkplate.height () / 2 ;
277+ }
0 commit comments