Simple Math Operations Giving Unexpected Outputs

Hey guys,

I am plotting a circle using two stepper motors. The X axis is relatively simple, stepping one step at a time. Here is the code I use to plot the circle:

void circle(int r){
  int r2 = sq(r);
  for (int i=1;i<r;i++){
    x.step(1);
    curx+=1;
    int yts = (sqrt(r2 - (curx * curx) ) );
    y.step(yts);
    cury += yts;
  }
}

I am a novice at this, and I suspect my problem has to do with the data type of int, and the limitations thereof. I have also tried using both long and signed long. Either way, I keep getting strange numbers for sq(300), usually between 25,000 and 35,000.

I understand that there is a maximum value for ints, but what data type should I be using to store numbers like 300^2: five digits?

long will do it. Just make sure that you use it everywhere you're currently using int.

You're a magician!

Your comment made me realize that I was declaring the radius as an integer (I didn't think it'd be a problem since the usable drawing area is only 1000 steps, so a theoretical maximum radius of 1000), but I assume that an operation between a long and an int returns an int.

Changing the data type for the radius to long fixed the issue, and everything is working as expected now.

Thanks!

You assume incorrectly. If you declare r2 as long, it will work out as well. The compiler uses the smallest available size so once you involve a long, it all turns into a long for the operator, then the sqrt returns a float and it gets truncated into an int to assign to yts. You did not specify what type curx is which could also impact the results. For example, if curx was uint8_t, then the
(curx * curx) portion could be done with 8 bit miltiplication which would be wrong and then the long result promoted to a long to subtract from r2...

Thanks for the reply.

I defined curx before setup as a long. I am, however, interested in what you said here:

sqrt returns a float and it gets truncated into an int to assign to yts.

Is this the nature of the sqrt() function? Is there a better way to go about this? Here is my updated code (although at the moment, it only draws 1/4 of a circle):

void circle(long r){
  Serial.println("Starting the circle.");
  long r2 = sq(r);
  Serial.println("Radius squared: ");
  Serial.println(r2);
  for (int i=0;i<r;i++){
    x.step(1);
    curx+=1;
    long expy = (sqrt(r2 - (sq(curx))))+1;
    y.step(expy-cury);
    cury = expy;
    Serial.println();
    Serial.print("  X: "+String(curx));
    Serial.print("  Y: "+String(cury));
  }
  delay(10000);
}

You don't need square roots at all, and everything can be done with integers, see Midpoint circle algorithm - Wikipedia.

see if this scketch meets your need.

float curx = 0;
float cury = 0;
const float pi = 3.141592;
const float rad = pi / 180;
//-------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  circle(300);
}
//-------------------------------------------------------------------
void loop() {
}
//-------------------------------------------------------------------
void circle(long r) {
  Serial.println("Starting the circle.");
  for (float i = 0; i < 90.3; i += 0.3)
  {
    curx = sin(i * rad);
    cury = cos(i * rad);
    Serial.print("  ang. " + String(i) + "  ");
    Serial.print("  X: " + String((curx * r),0));
    Serial.println("  Y: " + String((cury * r),0 ));
    delay(10000);
  }
}

Hey guys,

I'm working on plotting a circle using two stepper motors. One controls the X axis, the other controls the Y axis. Pretty simple setup.

Here's the section of my code that is intended to draw one quadrant of the circle:

void circle(long r){
  Serial.println("Starting the circle.");
  long r2 = sq(r);
  Serial.println("Radius squared: ");
  Serial.println(r2);
  for (int i=0;i<r;i++){
    x.step(1);
    curx+=1;
    long expy = (sqrt(r2 - (sq(curx))))+1;
    y.step(expy-cury);
    cury = expy;
    Serial.println();
    Serial.print("  X: "+String(curx));
    Serial.print("  Y: "+String(cury));
  }
  delay(10000);
}

The problem is that when I graph the outputted points, it's not circular, even though based on my understanding of the code, I feel like it should be.

I threw the datapoints in Excel just to visualize it, peradventure the machine I built was just imprecise. Plotting it in Excel confirmed the issue:

Is there something about the sqrt() function returning a float that could cause this much of an elongation in my circle?

I've been staring at this all afternoon, just need a different pair of eyes. TIA!

Okay, let me point out my own idiocy before anyone else gets the chance.

The Excel graph is not square. Here's an update:

Question still remains though. Here are the datapoints:

3	300
4	300
5	300
6	300
7	300
8	300
9	300
10	300
11	300
12	300
13	300
14	300
15	300
16	300
17	300
18	300
19	300
20	300
21	300
22	300
23	300
24	299
25	299
26	299
27	299
28	299
29	299
30	299
31	299
32	299
33	299
34	298
35	298
36	298
37	298
38	298
39	298
40	298
41	298
42	297
43	297
44	297
45	297
46	297
47	297
48	296
49	296
50	296
51	296
52	296
53	296
54	295
55	295
56	295
57	295
58	295
59	294
60	294
61	294
62	294
63	294
64	293
65	293
66	293
67	293
68	292
69	292
70	292
71	292
72	291
73	291
74	291
75	291
76	290
77	290
78	290
79	290
80	289
81	289
82	289
83	289
84	288
85	288
86	288
87	287
88	287
89	287
90	286
91	286
92	286
93	285
94	285
95	285
96	284
97	284
98	284
99	283
100	283
101	283
102	282
103	282
104	282
105	281
106	281
107	280
108	280
109	280
110	279
111	279
112	278
113	278
114	278
115	277
116	277
117	276
118	276
119	275
120	275
121	275
122	274
123	274
124	273
125	273
126	272
127	272
128	271
129	271
130	270
131	270
132	269
133	269
134	268
135	268
136	267
137	267
138	266
139	266
140	265
141	265
142	264
143	264
144	263
145	263
146	262
147	261
148	261
149	260
150	260
151	259
152	259
153	258
154	257
155	257
156	256
157	256
158	255
159	254
160	254
161	253
162	252
163	252
164	251
165	250
166	250
167	249
168	248
169	248
170	247
171	246
172	246
173	245
174	244
175	243
176	243
177	242
178	241
179	241
180	240
181	239
182	238
183	237
184	237
185	236
186	235
187	234
188	233
189	233
190	232
191	231
192	230
193	229
194	228
195	228
196	227
197	226
198	225
199	224
200	223
201	222
202	221
203	220
204	220
205	219
206	218
207	217
208	216
209	215
210	214
211	213
212	212
213	211
214	210
215	209
216	208
217	207
218	206
219	204
220	203
221	202
222	201
223	200
224	199
225	198
226	197
227	195
228	194
229	193
230	192
231	191
232	189
233	188
234	187
235	186
236	184
237	183
238	182
239	181
240	179
241	178
242	176
243	175
244	174
245	172
246	171
247	169
248	168
249	166
250	165
251	163
252	162
253	160
254	159
255	157
256	155
257	154
258	152
259	150
260	148
261	147
262	145
263	143
264	141
265	139
266	137
267	135
268	133
269	131
270	129
271	127
272	125
273	123
274	120
275	118
276	116
277	113
278	111
279	108
280	106
281	103
282	100
283	97
284	94
285	91
286	88
287	85
288	81
289	77
290	73
291	69
292	65
293	60
294	55
295	49
296	43
297	35
298	25
299	1
300	0

Here's one more example showing the irregularity:

As you can see, the points near (0, 300) are much more put together and evenly spaced than the points nearer (300, 0).

Your code is stepping through values of X in a linear way. The Y values are not going to be linear, because the circumference of a circle is not a line.

So I'm not sure what you think is unexpected about this. What did you want to happen? What's the problem with the code you have?

see if this scketch meets your need.

float curx = 0;
float cury = 0;
const float pi = 3.141592;
const float rad = pi / 180;
//-------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  circle(300);
}
//-------------------------------------------------------------------
void loop() {
}
//-------------------------------------------------------------------
void circle(long r) {
  Serial.println("Starting the circle.");
  for (float i = 0; i < 90.3; i += 0.3)
  {
    curx = sin(i * rad);
    cury = cos(i * rad);
    Serial.print("  ang. " + String(i) + "  ");
    Serial.print("  X: " + String((curx * r),0));
    Serial.println("  Y: " + String((cury * r),0 ));
    delay(10000);
  }
}

Topics on the same subject merged

Same here ...

You might want to research “Bresenham circle drawing algorithm”

Alright, I figured it out guys. TL;DR: I'm kind of an idiot.

PaulRB was mostly right, but to put it more simply: I'm generating this circle by stepping through values of X, one at a time. At x=0, y=radius of the circle, the Y values change very slowly, hence the smoothness. At x=radius, y=0, I'm still only stepping X by one value at a time, but Y changes more per value of X, giving it a choppier look.

The question I asked was essentially flawed from the start. Thanks everyone for the responses.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.