Browse Source

Draw logo

Thorsten Riess 1 year ago
parent
commit
e719aa29a9
4 changed files with 360 additions and 29 deletions
  1. 7
    1
      .idea/laserpong.iml
  2. 93
    0
      helper/logo_svg_to_c.py
  3. 253
    28
      main/laserpong_main.c
  4. 7
    0
      main/logo.h

+ 7
- 1
.idea/laserpong.iml View File

@@ -1,2 +1,8 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2
-<module classpath="CMake" type="CPP_MODULE" version="4" />
2
+<module classpath="CMake" type="CPP_MODULE" version="4">
3
+  <component name="FacetManager">
4
+    <facet type="Python" name="Python facet">
5
+      <configuration sdkName="Python 2.7" />
6
+    </facet>
7
+  </component>
8
+</module>

+ 93
- 0
helper/logo_svg_to_c.py View File

@@ -0,0 +1,93 @@
1
+#!/usr/bin/env python
2
+
3
+from svg.path import parse_path
4
+from xml.dom import minidom
5
+import pygame
6
+
7
+SVGFILE = 'hacKNology_nurlogo_klein_notran.svg'
8
+
9
+CFILE = 'logo.h'
10
+
11
+# Define the colors we will use in RGB format
12
+BLACK = (0, 0, 0)
13
+WHITE = (255, 255, 255)
14
+BLUE = (0, 0, 255)
15
+GREEN = (0, 255, 0)
16
+RED = (255, 0, 0)
17
+
18
+if __name__ == '__main__':
19
+    with open(SVGFILE) as f:
20
+        doc = minidom.parse(f)
21
+    path_strings = [path.getAttribute('d') for path in doc.getElementsByTagName('path')]
22
+    doc.unlink()
23
+    print(path_strings)
24
+    lines = []
25
+    minx, miny, maxx, maxy = None, None, None, None
26
+    for pathstr in path_strings:
27
+        obj = parse_path(pathstr)
28
+        line = []
29
+        for seg in obj:
30
+            print(seg.start, seg.end)
31
+            x1, y1 = seg.start.real, seg.start.imag
32
+            x2, y2 = seg.end.real, seg.end.imag
33
+            line.append([x1, y1, x2, y2])
34
+            if minx is None or x1 < minx:
35
+                minx = x1
36
+            if minx is None or x2 < minx:
37
+                minx = x2
38
+            if miny is None or y1 < miny:
39
+                miny = y1
40
+            if miny is None or y2 < miny:
41
+                miny = y2
42
+            if maxx is None or x1 > maxx:
43
+                maxx = x1
44
+            if maxx is None or x2 > maxx:
45
+                maxx = x2
46
+            if maxy is None or y1 > maxy:
47
+                maxy = y1
48
+            if maxy is None or y2 > maxy:
49
+                maxy = y2
50
+        lines.append(line)
51
+    for line in lines:
52
+        for seg in line:
53
+            seg[0], seg[1], seg[2], seg[3] = (seg[0] - minx) / (maxx - minx), (seg[1] - miny) / (maxy - miny), (
54
+                        seg[2] - minx) / (maxx - minx), (seg[3] - miny) / (maxy - miny)
55
+
56
+    print(lines)
57
+
58
+    with open(CFILE, 'w') as f:
59
+        f.write('#ifndef __LOGO_H\n')
60
+        f.write('#define __LOGO_H\n\n')
61
+        f.write('const float logo[] = {')
62
+        lengths = []
63
+        linestrs = []
64
+        for line in lines:
65
+            segstrs = []
66
+            for seg in line:
67
+                segstrs.append("%f,%f,%f,%f" % (seg[0], seg[1], seg[2], seg[3],))
68
+            lengths.append("%d" % len(line))
69
+            linestrs.append(",".join(segstrs))
70
+        f.write(",".join(linestrs))
71
+        f.write("};\n")
72
+        f.write('const int logo_lines[] = {')
73
+        f.write(",".join(lengths))
74
+        f.write(",0};\n")
75
+        f.write('\n#endif')
76
+
77
+
78
+    pygame.init()
79
+    size = [400, 300]
80
+    screen = pygame.display.set_mode(size)
81
+
82
+    pygame.display.set_caption("Example code for the draw module")
83
+
84
+    clock = pygame.time.Clock()
85
+
86
+    done = False
87
+    while not done:
88
+        clock.tick(10)
89
+        screen.fill(WHITE)
90
+        for line in lines:
91
+            for seg in line:
92
+                pygame.draw.line(screen, GREEN, [seg[0]*400,seg[1]*300], [seg[2]*400, seg[3]*300], 5)
93
+        pygame.display.flip()

+ 253
- 28
main/laserpong_main.c View File

@@ -8,18 +8,30 @@
8 8
 */
9 9
 #include <stdio.h>
10 10
 #include <math.h>
11
+#include <driver/gpio.h>
11 12
 #include "freertos/FreeRTOS.h"
12 13
 #include "freertos/task.h"
13 14
 #include "esp_system.h"
14 15
 #include "esp_spi_flash.h"
15 16
 #include "driver/ledc.h"
17
+#include "logo.h"
18
+
19
+#define GPIO_LEFTRIGHT GPIO_NUM_15
20
+#define GPIO_UPDOWN    GPIO_NUM_13
21
+#define GPIO_LASER     GPIO_NUM_4
22
+#define GPIO_LASER_SEL GPIO_SEL_4
16 23
 
17 24
 // some servo-specific constants, those also depend on the way the servos are attached to the horns
18
-#define UPDOWN_STRAIGHT  2550
19
-#define UPDOWN_DOWN      1280
20
-#define LEFTRIGHT_LEFT   3200 // 3276
21
-#define LEFTRIGHT_MIDDLE 1920
22
-#define LEFTRIGHT_RIGHT   900
25
+#define UPDOWN_STRAIGHT  2550 // -> 0 deg
26
+#define UPDOWN_DOWN      1280 // -> 90 deg = pi/2
27
+#define LEFTRIGHT_LEFT   3200 // max: 3276  -> -90 deg = -pi/2
28
+#define LEFTRIGHT_MIDDLE 1920 // -> 0 deg
29
+#define LEFTRIGHT_RIGHT   900 // -> 90 deg = pi/2
30
+
31
+// time to move to the desired position
32
+#define MILLISECONDS_PER_DEGREE (100.0 / 60.0)
33
+// we use 1280 as the required payload difference for 90 degrees, which is more or less correct
34
+#define MILLISECONDS_PER_VALUE ((MILLISECONDS_PER_DEGREE*90.0)/1280.0)
23 35
 
24 36
 /*
25 37
  * The position of the laser relative to the projection surface is such that the laser is centered horizontally,
@@ -27,26 +39,202 @@
27 39
  * the top edge
28 40
  * The values that follow here are the dimensions of the surface and the distance of the laser (same unit)
29 41
  * such that the corresponding angles for the corners can easily be computed.
42
+ *
43
+ * coordinates in screen space:
44
+ * (0,0)             (mx/2,0)            (mx,0)
45
+ * +-------------------------------------+  ^
46
+ * |                                     |  |
47
+ * |                                     |  SCREEN_HEIGHT
48
+ * |                                     |  |
49
+ * |                                     |  |
50
+ * +-------------------------------------+  v
51
+ * (0,my)            (mx/2,my)           (mx,my)
52
+ * <------- SCREEN_WIDTH ---------------->
53
+ *
54
+ * if resolution is set to 1, mx = SCREEN_WIDTH and my = SCREEN_HEIGHT
30 55
  */
31 56
 // distance to the projection surface (all units are cm)
32 57
 #define SCREEN_DISTANCE 100
33 58
 #define SCREEN_WIDTH    100
34 59
 #define SCREEN_HEIGHT    50
35 60
 
36
-#define LEFTRIGHT_LEFT_ANGLE  atan2(SCREEN_DISTANCE, SCREEN_WIDTH/2)
37
-#define LEFTRIGHT_RIGHT_ANGLE (-LEFTRIGHT_LEFT_ANGLE)
38
-#define UPDOWN_UP_ANGLE   0
39
-#define UPDOWN_DOWN_ANGLE atan2(SCREEN_DISTANCE, SCREEN_HEIGHT)
61
+// how many "pixels" per unit
62
+#define SCREEN_LEFTRIGHT_RESOLUTION 1
63
+#define SCREEN_UPDOWN_RESOLUTION 1
64
+
65
+#define PADDLE_SIZE (SCREEN_HEIGHT/5)
66
+#define BALL_SEGMENTS 4
67
+
68
+/*
69
+ * Precomputed values for each coordinate
70
+ */
71
+uint32_t leftRightValues[SCREEN_WIDTH*SCREEN_LEFTRIGHT_RESOLUTION];
72
+uint32_t upDownValues[SCREEN_HEIGHT*SCREEN_UPDOWN_RESOLUTION];
73
+
74
+// current positions (values)
75
+uint32_t currentLeftRightValue, currentUpDownValue;
76
+
77
+void precompute_values()
78
+{
79
+    double ang;
80
+    int i;
81
+    for(i=SCREEN_WIDTH*SCREEN_LEFTRIGHT_RESOLUTION/2-1; i>=0; --i) {
82
+        ang = -atan2(((double)i)/SCREEN_LEFTRIGHT_RESOLUTION, SCREEN_DISTANCE);
83
+        leftRightValues[(SCREEN_WIDTH/2)*SCREEN_LEFTRIGHT_RESOLUTION - 1 - i] = (uint32_t)(LEFTRIGHT_MIDDLE-((LEFTRIGHT_LEFT-LEFTRIGHT_MIDDLE)*ang/M_PI_2));
84
+        printf("leftright %d - %f\n", (SCREEN_WIDTH/2)*SCREEN_LEFTRIGHT_RESOLUTION - 1 - i, LEFTRIGHT_MIDDLE-((LEFTRIGHT_LEFT-LEFTRIGHT_MIDDLE)*ang/M_PI_2));
85
+    }
86
+    for(i=1; i<=SCREEN_WIDTH*SCREEN_LEFTRIGHT_RESOLUTION/2; i++) {
87
+        ang = atan2((double)i/SCREEN_LEFTRIGHT_RESOLUTION, SCREEN_DISTANCE);
88
+        leftRightValues[(SCREEN_WIDTH/2)*SCREEN_LEFTRIGHT_RESOLUTION + i - 1] = (uint32_t)(LEFTRIGHT_MIDDLE+((LEFTRIGHT_RIGHT-LEFTRIGHT_MIDDLE)*ang/M_PI_2));
89
+        printf("leftright %d - %f\n", (SCREEN_WIDTH/2)*SCREEN_LEFTRIGHT_RESOLUTION + i - 1, LEFTRIGHT_MIDDLE+((LEFTRIGHT_RIGHT-LEFTRIGHT_MIDDLE)*ang/M_PI_2));
90
+    }
91
+    for(i=0; i<SCREEN_HEIGHT*SCREEN_UPDOWN_RESOLUTION; i++) {
92
+        ang = atan2((double)i/SCREEN_LEFTRIGHT_RESOLUTION, SCREEN_DISTANCE);
93
+        upDownValues[i] = (uint32_t)(UPDOWN_STRAIGHT + ((UPDOWN_DOWN-UPDOWN_STRAIGHT)*ang/M_PI_2));
94
+        printf("updown %d - %f\n", i, UPDOWN_STRAIGHT + ((UPDOWN_DOWN-UPDOWN_STRAIGHT)*ang/M_PI_2));
95
+    }
96
+}
97
+
98
+void setPWM()
99
+{
100
+    // updown
101
+    ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, currentUpDownValue);
102
+    ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, currentLeftRightValue);
103
+    printf("Setting updown value to %d\n", currentUpDownValue);
104
+    printf("Setting leftright value to %d\n", currentLeftRightValue);
105
+    ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0);
106
+    ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1);
107
+}
108
+
109
+void go_to(uint8_t x, uint8_t y) {
110
+    uint32_t vdiff1 = abs(currentUpDownValue-upDownValues[y]);
111
+    uint32_t vdiff2 = abs(currentLeftRightValue-leftRightValues[x]);
112
+    uint32_t vdiff = (vdiff1 > vdiff2 ? vdiff1 : vdiff2);
113
+    uint32_t time = vdiff * MILLISECONDS_PER_VALUE;
114
+    time = 20 * (time / 20 + 1);
115
+    //if(time < 20) time = 20;  // 20 ms is the minimum for a 50hz pwm...
116
+    //if(time < 40) time = 40; // make sure we have at least 2 cycles
117
+    //if(time < 10) time = 10;
118
+    currentUpDownValue = upDownValues[y];
119
+    currentLeftRightValue = leftRightValues[x];
120
+    setPWM();
121
+    printf("Waiting for %d ms", time);
122
+    vTaskDelay(1.5 * time / portTICK_PERIOD_MS);
123
+}
124
+
125
+void laser_on()
126
+{
127
+    vTaskDelay(20 / portTICK_PERIOD_MS);
128
+    gpio_set_level(GPIO_LASER, 1);
129
+}
130
+
131
+void laser_off()
132
+{
133
+    gpio_set_level(GPIO_LASER, 0);
134
+    vTaskDelay(20 / portTICK_PERIOD_MS);
135
+}
40 136
 
41 137
 void draw_line()
42 138
 {
43
-//atan2()
139
+    for(int i=0; i<10; i++) {
140
+        go_to(0, 0);
141
+        go_to(0, SCREEN_HEIGHT - 1);
142
+    }
143
+}
144
+
145
+void draw_paddle(int side)
146
+{
147
+    uint8_t x = (side==0?0:(SCREEN_WIDTH-1));
148
+    uint8_t y = PADDLE_SIZE;
149
+
150
+    printf("Draw paddle\n");
151
+    go_to(x, y);
152
+    laser_on();
153
+    vTaskDelay(10 / portTICK_PERIOD_MS);
154
+    //for(int i=0;i<2;i++) {
155
+    go_to(x, y + PADDLE_SIZE);
156
+    vTaskDelay(10 / portTICK_PERIOD_MS);
157
+    go_to(x, y);
158
+    //}
159
+    laser_off();
160
+}
161
+
162
+void draw_ball()
163
+{
164
+    uint8_t x = SCREEN_WIDTH/2;
165
+    uint8_t y = SCREEN_HEIGHT/2;
166
+    printf("Draw ball");
167
+    go_to(x,y+1);
168
+    laser_on();
169
+    //go_to(x,y+1);
170
+    go_to(x+1,y);
171
+    go_to(x,y-1);
172
+    go_to(x-1,y);
173
+    go_to(x,y+1);
174
+    //vTaskDelay(50 / portTICK_PERIOD_MS);
175
+    //for(int i=0; i<BALL_SEGMENTS; i++) {
176
+    //    printf("go to %f %f", x + 5*acos(i * 2.0*M_PI / BALL_SEGMENTS), y + 5*asin(i* 2.0*M_PI / BALL_SEGMENTS));
177
+    //    go_to(x + 5*cos(i * 2.0*M_PI / BALL_SEGMENTS), y + 5*sin(i* 2.0*M_PI / BALL_SEGMENTS));
178
+    //}
179
+    //go_to(x,y);
180
+    laser_off();
181
+}
182
+
183
+void draw_frame()
184
+{
185
+    draw_paddle(0);
186
+    //vTaskDelay(1 / portTICK_PERIOD_MS);
187
+    draw_ball();
188
+    //vTaskDelay(1 / portTICK_PERIOD_MS);
189
+    draw_paddle(1);
190
+    draw_ball();
191
+}
192
+
193
+void draw_logo()
194
+{
195
+    int l;
196
+    int i=0,j;
197
+    int p=0;
198
+    float x,y;
199
+    while( (l=logo_lines[i++]) > 0) {
200
+        for(j=0;j<l;j++) {
201
+            x = (uint8_t)(logo[p++] * SCREEN_WIDTH);
202
+            y = (uint8_t)(logo[p++] * SCREEN_HEIGHT);
203
+            if(x >= SCREEN_WIDTH) x = SCREEN_WIDTH -1;
204
+            if(x<0) x = 0;
205
+            if(y>=SCREEN_HEIGHT) y = SCREEN_HEIGHT-1;
206
+            if(y<0) y = 0;
207
+            go_to(x,y);
208
+            if(j==0) laser_on();
209
+        }
210
+        laser_off();
211
+    }
44 212
 }
45 213
 
46 214
 void app_main()
47 215
 {
48 216
     printf("Hello world!\n");
49 217
 
218
+    precompute_values();
219
+
220
+    printf("Precompute done.");
221
+
222
+    gpio_config_t gpio_config_laser;
223
+    ledc_channel_config_t ledc_conf_leftright;
224
+    ledc_channel_config_t ledc_conf_updown;
225
+
226
+    /*
227
+     * configure the laser gpio as simple output
228
+     */
229
+    gpio_config_laser.pin_bit_mask = GPIO_LASER_SEL;
230
+    gpio_config_laser.mode = GPIO_MODE_OUTPUT;
231
+    gpio_config_laser.pull_up_en = GPIO_PULLUP_DISABLE;
232
+    gpio_config_laser.pull_down_en = GPIO_PULLDOWN_DISABLE;
233
+    gpio_config_laser.intr_type = GPIO_INTR_DISABLE;
234
+    gpio_config(&gpio_config_laser);
235
+
236
+    gpio_set_level(GPIO_NUM_4, 0);
237
+
50 238
     /*
51 239
      * According to the data sheet, the SG90 9g micro servos
52 240
      * operate at 0.1s / 60deg
@@ -65,27 +253,64 @@ void app_main()
65 253
     // 2nd servo up/down
66 254
     // 2550 - straight
67 255
     // 1280 - down
68
-    ledc_channel_config_t ledc_conf;
69
-    ledc_conf.channel = LEDC_CHANNEL_0;
70
-    ledc_conf.duty = UPDOWN_STRAIGHT; //900; //3276; //1638; // to 3276  // 0 - 2088 (actually a bit less than that)
71
-    ledc_conf.gpio_num = 13;
72
-    ledc_conf.intr_type = LEDC_INTR_DISABLE;
73
-    ledc_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
74
-    ledc_conf.timer_sel = LEDC_TIMER_0;
75
-    ledc_channel_config(&ledc_conf);
256
+    ledc_conf_updown.channel = LEDC_CHANNEL_0;
257
+    ledc_conf_updown.duty = UPDOWN_STRAIGHT; //900; //3276; //1638; // to 3276  // 0 - 2088 (actually a bit less than that)
258
+    ledc_conf_updown.gpio_num = GPIO_UPDOWN;
259
+    ledc_conf_updown.intr_type = LEDC_INTR_DISABLE;
260
+    ledc_conf_updown.speed_mode = LEDC_HIGH_SPEED_MODE;
261
+    ledc_conf_updown.timer_sel = LEDC_TIMER_0;
262
+    ledc_channel_config(&ledc_conf_updown);
76 263
 
77 264
     // first servo connected to ground
78 265
     // left-right
79 266
     // 3276 - 2000 - 900
80
-    ledc_channel_config_t ledc_conf2;
81
-    ledc_conf2.channel = LEDC_CHANNEL_1;
82
-    ledc_conf2.duty = LEFTRIGHT_LEFT; //900; //3276; //1638; // to 3276  // 0 - 2088 (actually a bit less than that)
83
-    ledc_conf2.gpio_num = 15;
84
-    ledc_conf2.intr_type = LEDC_INTR_DISABLE;
85
-    ledc_conf2.speed_mode = LEDC_HIGH_SPEED_MODE;
86
-    ledc_conf2.timer_sel = LEDC_TIMER_0;
87
-    ledc_channel_config(&ledc_conf2);
267
+    ledc_conf_leftright.channel = LEDC_CHANNEL_1;
268
+    ledc_conf_leftright.duty = LEFTRIGHT_MIDDLE; //900; //3276; //1638; // to 3276  // 0 - 2088 (actually a bit less than that)
269
+    ledc_conf_leftright.gpio_num = GPIO_LEFTRIGHT;
270
+    ledc_conf_leftright.intr_type = LEDC_INTR_DISABLE;
271
+    ledc_conf_leftright.speed_mode = LEDC_HIGH_SPEED_MODE;
272
+    ledc_conf_leftright.timer_sel = LEDC_TIMER_0;
273
+    ledc_channel_config(&ledc_conf_leftright);
274
+
275
+    while(1) {
276
+        //draw_frame();
277
+        draw_logo();
278
+        //vTaskDelay(1 / portTICK_PERIOD_MS);
279
+    }
280
+
281
+    go_to(0,0);
282
+
283
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
284
+
285
+    laser_on();
286
+    go_to(50,0);
287
+
288
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
289
+
290
+    //laser_off();
291
+    go_to(99,0);
292
+
293
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
294
+
295
+    laser_on();
296
+    go_to(99,25);
297
+
298
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
299
+
300
+    //laser_off();
301
+    go_to(50,25);
302
+
303
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
304
+
305
+    laser_on();
306
+    go_to(0,25);
307
+
308
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
309
+
88 310
 
311
+    draw_line();
312
+    laser_off();
313
+    //laser_off();
89 314
 
90 315
     /* Print chip information */
91 316
     esp_chip_info_t chip_info;
@@ -100,10 +325,10 @@ void app_main()
100 325
     printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
101 326
             (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
102 327
 
103
-    for (int i = 0; i < 6; i++) {
328
+    for (int i = 0; i < 1000; i++) {
104 329
         printf("Restarting in %d seconds...\n", i);
105 330
         vTaskDelay(1000 / portTICK_PERIOD_MS);
106
-        ledc_conf2.duty = LEFTRIGHT_LEFT - (i+1) * (LEFTRIGHT_LEFT - LEFTRIGHT_MIDDLE) / 6;
331
+        //ledc_conf2.duty = LEFTRIGHT_LEFT - (i+1) * (LEFTRIGHT_LEFT - LEFTRIGHT_MIDDLE) / 6;
107 332
         //ledc_channel_config(&ledc_conf2);
108 333
         //if(ledc_conf.duty > 1000) {
109 334
         //    ledc_conf.duty = 800;

+ 7
- 0
main/logo.h
File diff suppressed because it is too large
View File


Loading…
Cancel
Save