Browse Source

Draw logo

master
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 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />
<module classpath="CMake" type="CPP_MODULE" version="4">
<component name="FacetManager">
<facet type="Python" name="Python facet">
<configuration sdkName="Python 2.7" />
</facet>
</component>
</module>

+ 93
- 0
helper/logo_svg_to_c.py View File

@@ -0,0 +1,93 @@
#!/usr/bin/env python

from svg.path import parse_path
from xml.dom import minidom
import pygame

SVGFILE = 'hacKNology_nurlogo_klein_notran.svg'

CFILE = 'logo.h'

# Define the colors we will use in RGB format
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

if __name__ == '__main__':
with open(SVGFILE) as f:
doc = minidom.parse(f)
path_strings = [path.getAttribute('d') for path in doc.getElementsByTagName('path')]
doc.unlink()
print(path_strings)
lines = []
minx, miny, maxx, maxy = None, None, None, None
for pathstr in path_strings:
obj = parse_path(pathstr)
line = []
for seg in obj:
print(seg.start, seg.end)
x1, y1 = seg.start.real, seg.start.imag
x2, y2 = seg.end.real, seg.end.imag
line.append([x1, y1, x2, y2])
if minx is None or x1 < minx:
minx = x1
if minx is None or x2 < minx:
minx = x2
if miny is None or y1 < miny:
miny = y1
if miny is None or y2 < miny:
miny = y2
if maxx is None or x1 > maxx:
maxx = x1
if maxx is None or x2 > maxx:
maxx = x2
if maxy is None or y1 > maxy:
maxy = y1
if maxy is None or y2 > maxy:
maxy = y2
lines.append(line)
for line in lines:
for seg in line:
seg[0], seg[1], seg[2], seg[3] = (seg[0] - minx) / (maxx - minx), (seg[1] - miny) / (maxy - miny), (
seg[2] - minx) / (maxx - minx), (seg[3] - miny) / (maxy - miny)

print(lines)

with open(CFILE, 'w') as f:
f.write('#ifndef __LOGO_H\n')
f.write('#define __LOGO_H\n\n')
f.write('const float logo[] = {')
lengths = []
linestrs = []
for line in lines:
segstrs = []
for seg in line:
segstrs.append("%f,%f,%f,%f" % (seg[0], seg[1], seg[2], seg[3],))
lengths.append("%d" % len(line))
linestrs.append(",".join(segstrs))
f.write(",".join(linestrs))
f.write("};\n")
f.write('const int logo_lines[] = {')
f.write(",".join(lengths))
f.write(",0};\n")
f.write('\n#endif')


pygame.init()
size = [400, 300]
screen = pygame.display.set_mode(size)

pygame.display.set_caption("Example code for the draw module")

clock = pygame.time.Clock()

done = False
while not done:
clock.tick(10)
screen.fill(WHITE)
for line in lines:
for seg in line:
pygame.draw.line(screen, GREEN, [seg[0]*400,seg[1]*300], [seg[2]*400, seg[3]*300], 5)
pygame.display.flip()

+ 253
- 28
main/laserpong_main.c View File

@@ -8,18 +8,30 @@
*/
#include <stdio.h>
#include <math.h>
#include <driver/gpio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "driver/ledc.h"
#include "logo.h"

#define GPIO_LEFTRIGHT GPIO_NUM_15
#define GPIO_UPDOWN GPIO_NUM_13
#define GPIO_LASER GPIO_NUM_4
#define GPIO_LASER_SEL GPIO_SEL_4

// some servo-specific constants, those also depend on the way the servos are attached to the horns
#define UPDOWN_STRAIGHT 2550
#define UPDOWN_DOWN 1280
#define LEFTRIGHT_LEFT 3200 // 3276
#define LEFTRIGHT_MIDDLE 1920
#define LEFTRIGHT_RIGHT 900
#define UPDOWN_STRAIGHT 2550 // -> 0 deg
#define UPDOWN_DOWN 1280 // -> 90 deg = pi/2
#define LEFTRIGHT_LEFT 3200 // max: 3276 -> -90 deg = -pi/2
#define LEFTRIGHT_MIDDLE 1920 // -> 0 deg
#define LEFTRIGHT_RIGHT 900 // -> 90 deg = pi/2

// time to move to the desired position
#define MILLISECONDS_PER_DEGREE (100.0 / 60.0)
// we use 1280 as the required payload difference for 90 degrees, which is more or less correct
#define MILLISECONDS_PER_VALUE ((MILLISECONDS_PER_DEGREE*90.0)/1280.0)

/*
* The position of the laser relative to the projection surface is such that the laser is centered horizontally,
@@ -27,26 +39,202 @@
* the top edge
* The values that follow here are the dimensions of the surface and the distance of the laser (same unit)
* such that the corresponding angles for the corners can easily be computed.
*
* coordinates in screen space:
* (0,0) (mx/2,0) (mx,0)
* +-------------------------------------+ ^
* | | |
* | | SCREEN_HEIGHT
* | | |
* | | |
* +-------------------------------------+ v
* (0,my) (mx/2,my) (mx,my)
* <------- SCREEN_WIDTH ---------------->
*
* if resolution is set to 1, mx = SCREEN_WIDTH and my = SCREEN_HEIGHT
*/
// distance to the projection surface (all units are cm)
#define SCREEN_DISTANCE 100
#define SCREEN_WIDTH 100
#define SCREEN_HEIGHT 50

#define LEFTRIGHT_LEFT_ANGLE atan2(SCREEN_DISTANCE, SCREEN_WIDTH/2)
#define LEFTRIGHT_RIGHT_ANGLE (-LEFTRIGHT_LEFT_ANGLE)
#define UPDOWN_UP_ANGLE 0
#define UPDOWN_DOWN_ANGLE atan2(SCREEN_DISTANCE, SCREEN_HEIGHT)
// how many "pixels" per unit
#define SCREEN_LEFTRIGHT_RESOLUTION 1
#define SCREEN_UPDOWN_RESOLUTION 1

#define PADDLE_SIZE (SCREEN_HEIGHT/5)
#define BALL_SEGMENTS 4

/*
* Precomputed values for each coordinate
*/
uint32_t leftRightValues[SCREEN_WIDTH*SCREEN_LEFTRIGHT_RESOLUTION];
uint32_t upDownValues[SCREEN_HEIGHT*SCREEN_UPDOWN_RESOLUTION];

// current positions (values)
uint32_t currentLeftRightValue, currentUpDownValue;

void precompute_values()
{
double ang;
int i;
for(i=SCREEN_WIDTH*SCREEN_LEFTRIGHT_RESOLUTION/2-1; i>=0; --i) {
ang = -atan2(((double)i)/SCREEN_LEFTRIGHT_RESOLUTION, SCREEN_DISTANCE);
leftRightValues[(SCREEN_WIDTH/2)*SCREEN_LEFTRIGHT_RESOLUTION - 1 - i] = (uint32_t)(LEFTRIGHT_MIDDLE-((LEFTRIGHT_LEFT-LEFTRIGHT_MIDDLE)*ang/M_PI_2));
printf("leftright %d - %f\n", (SCREEN_WIDTH/2)*SCREEN_LEFTRIGHT_RESOLUTION - 1 - i, LEFTRIGHT_MIDDLE-((LEFTRIGHT_LEFT-LEFTRIGHT_MIDDLE)*ang/M_PI_2));
}
for(i=1; i<=SCREEN_WIDTH*SCREEN_LEFTRIGHT_RESOLUTION/2; i++) {
ang = atan2((double)i/SCREEN_LEFTRIGHT_RESOLUTION, SCREEN_DISTANCE);
leftRightValues[(SCREEN_WIDTH/2)*SCREEN_LEFTRIGHT_RESOLUTION + i - 1] = (uint32_t)(LEFTRIGHT_MIDDLE+((LEFTRIGHT_RIGHT-LEFTRIGHT_MIDDLE)*ang/M_PI_2));
printf("leftright %d - %f\n", (SCREEN_WIDTH/2)*SCREEN_LEFTRIGHT_RESOLUTION + i - 1, LEFTRIGHT_MIDDLE+((LEFTRIGHT_RIGHT-LEFTRIGHT_MIDDLE)*ang/M_PI_2));
}
for(i=0; i<SCREEN_HEIGHT*SCREEN_UPDOWN_RESOLUTION; i++) {
ang = atan2((double)i/SCREEN_LEFTRIGHT_RESOLUTION, SCREEN_DISTANCE);
upDownValues[i] = (uint32_t)(UPDOWN_STRAIGHT + ((UPDOWN_DOWN-UPDOWN_STRAIGHT)*ang/M_PI_2));
printf("updown %d - %f\n", i, UPDOWN_STRAIGHT + ((UPDOWN_DOWN-UPDOWN_STRAIGHT)*ang/M_PI_2));
}
}

void setPWM()
{
// updown
ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, currentUpDownValue);
ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, currentLeftRightValue);
printf("Setting updown value to %d\n", currentUpDownValue);
printf("Setting leftright value to %d\n", currentLeftRightValue);
ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0);
ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1);
}

void go_to(uint8_t x, uint8_t y) {
uint32_t vdiff1 = abs(currentUpDownValue-upDownValues[y]);
uint32_t vdiff2 = abs(currentLeftRightValue-leftRightValues[x]);
uint32_t vdiff = (vdiff1 > vdiff2 ? vdiff1 : vdiff2);
uint32_t time = vdiff * MILLISECONDS_PER_VALUE;
time = 20 * (time / 20 + 1);
//if(time < 20) time = 20; // 20 ms is the minimum for a 50hz pwm...
//if(time < 40) time = 40; // make sure we have at least 2 cycles
//if(time < 10) time = 10;
currentUpDownValue = upDownValues[y];
currentLeftRightValue = leftRightValues[x];
setPWM();
printf("Waiting for %d ms", time);
vTaskDelay(1.5 * time / portTICK_PERIOD_MS);
}

void laser_on()
{
vTaskDelay(20 / portTICK_PERIOD_MS);
gpio_set_level(GPIO_LASER, 1);
}

void laser_off()
{
gpio_set_level(GPIO_LASER, 0);
vTaskDelay(20 / portTICK_PERIOD_MS);
}

void draw_line()
{
//atan2()
for(int i=0; i<10; i++) {
go_to(0, 0);
go_to(0, SCREEN_HEIGHT - 1);
}
}

void draw_paddle(int side)
{
uint8_t x = (side==0?0:(SCREEN_WIDTH-1));
uint8_t y = PADDLE_SIZE;

printf("Draw paddle\n");
go_to(x, y);
laser_on();
vTaskDelay(10 / portTICK_PERIOD_MS);
//for(int i=0;i<2;i++) {
go_to(x, y + PADDLE_SIZE);
vTaskDelay(10 / portTICK_PERIOD_MS);
go_to(x, y);
//}
laser_off();
}

void draw_ball()
{
uint8_t x = SCREEN_WIDTH/2;
uint8_t y = SCREEN_HEIGHT/2;
printf("Draw ball");
go_to(x,y+1);
laser_on();
//go_to(x,y+1);
go_to(x+1,y);
go_to(x,y-1);
go_to(x-1,y);
go_to(x,y+1);
//vTaskDelay(50 / portTICK_PERIOD_MS);
//for(int i=0; i<BALL_SEGMENTS; i++) {
// 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));
// go_to(x + 5*cos(i * 2.0*M_PI / BALL_SEGMENTS), y + 5*sin(i* 2.0*M_PI / BALL_SEGMENTS));
//}
//go_to(x,y);
laser_off();
}

void draw_frame()
{
draw_paddle(0);
//vTaskDelay(1 / portTICK_PERIOD_MS);
draw_ball();
//vTaskDelay(1 / portTICK_PERIOD_MS);
draw_paddle(1);
draw_ball();
}

void draw_logo()
{
int l;
int i=0,j;
int p=0;
float x,y;
while( (l=logo_lines[i++]) > 0) {
for(j=0;j<l;j++) {
x = (uint8_t)(logo[p++] * SCREEN_WIDTH);
y = (uint8_t)(logo[p++] * SCREEN_HEIGHT);
if(x >= SCREEN_WIDTH) x = SCREEN_WIDTH -1;
if(x<0) x = 0;
if(y>=SCREEN_HEIGHT) y = SCREEN_HEIGHT-1;
if(y<0) y = 0;
go_to(x,y);
if(j==0) laser_on();
}
laser_off();
}
}

void app_main()
{
printf("Hello world!\n");

precompute_values();

printf("Precompute done.");

gpio_config_t gpio_config_laser;
ledc_channel_config_t ledc_conf_leftright;
ledc_channel_config_t ledc_conf_updown;

/*
* configure the laser gpio as simple output
*/
gpio_config_laser.pin_bit_mask = GPIO_LASER_SEL;
gpio_config_laser.mode = GPIO_MODE_OUTPUT;
gpio_config_laser.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config_laser.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config_laser.intr_type = GPIO_INTR_DISABLE;
gpio_config(&gpio_config_laser);

gpio_set_level(GPIO_NUM_4, 0);

/*
* According to the data sheet, the SG90 9g micro servos
* operate at 0.1s / 60deg
@@ -65,27 +253,64 @@ void app_main()
// 2nd servo up/down
// 2550 - straight
// 1280 - down
ledc_channel_config_t ledc_conf;
ledc_conf.channel = LEDC_CHANNEL_0;
ledc_conf.duty = UPDOWN_STRAIGHT; //900; //3276; //1638; // to 3276 // 0 - 2088 (actually a bit less than that)
ledc_conf.gpio_num = 13;
ledc_conf.intr_type = LEDC_INTR_DISABLE;
ledc_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
ledc_conf.timer_sel = LEDC_TIMER_0;
ledc_channel_config(&ledc_conf);
ledc_conf_updown.channel = LEDC_CHANNEL_0;
ledc_conf_updown.duty = UPDOWN_STRAIGHT; //900; //3276; //1638; // to 3276 // 0 - 2088 (actually a bit less than that)
ledc_conf_updown.gpio_num = GPIO_UPDOWN;
ledc_conf_updown.intr_type = LEDC_INTR_DISABLE;
ledc_conf_updown.speed_mode = LEDC_HIGH_SPEED_MODE;
ledc_conf_updown.timer_sel = LEDC_TIMER_0;
ledc_channel_config(&ledc_conf_updown);

// first servo connected to ground
// left-right
// 3276 - 2000 - 900
ledc_channel_config_t ledc_conf2;
ledc_conf2.channel = LEDC_CHANNEL_1;
ledc_conf2.duty = LEFTRIGHT_LEFT; //900; //3276; //1638; // to 3276 // 0 - 2088 (actually a bit less than that)
ledc_conf2.gpio_num = 15;
ledc_conf2.intr_type = LEDC_INTR_DISABLE;
ledc_conf2.speed_mode = LEDC_HIGH_SPEED_MODE;
ledc_conf2.timer_sel = LEDC_TIMER_0;
ledc_channel_config(&ledc_conf2);
ledc_conf_leftright.channel = LEDC_CHANNEL_1;
ledc_conf_leftright.duty = LEFTRIGHT_MIDDLE; //900; //3276; //1638; // to 3276 // 0 - 2088 (actually a bit less than that)
ledc_conf_leftright.gpio_num = GPIO_LEFTRIGHT;
ledc_conf_leftright.intr_type = LEDC_INTR_DISABLE;
ledc_conf_leftright.speed_mode = LEDC_HIGH_SPEED_MODE;
ledc_conf_leftright.timer_sel = LEDC_TIMER_0;
ledc_channel_config(&ledc_conf_leftright);

while(1) {
//draw_frame();
draw_logo();
//vTaskDelay(1 / portTICK_PERIOD_MS);
}

go_to(0,0);

vTaskDelay(5000 / portTICK_PERIOD_MS);

laser_on();
go_to(50,0);

vTaskDelay(5000 / portTICK_PERIOD_MS);

//laser_off();
go_to(99,0);

vTaskDelay(5000 / portTICK_PERIOD_MS);

laser_on();
go_to(99,25);

vTaskDelay(5000 / portTICK_PERIOD_MS);

//laser_off();
go_to(50,25);

vTaskDelay(5000 / portTICK_PERIOD_MS);

laser_on();
go_to(0,25);

vTaskDelay(5000 / portTICK_PERIOD_MS);


draw_line();
laser_off();
//laser_off();

/* Print chip information */
esp_chip_info_t chip_info;
@@ -100,10 +325,10 @@ void app_main()
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

for (int i = 0; i < 6; i++) {
for (int i = 0; i < 1000; i++) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
ledc_conf2.duty = LEFTRIGHT_LEFT - (i+1) * (LEFTRIGHT_LEFT - LEFTRIGHT_MIDDLE) / 6;
//ledc_conf2.duty = LEFTRIGHT_LEFT - (i+1) * (LEFTRIGHT_LEFT - LEFTRIGHT_MIDDLE) / 6;
//ledc_channel_config(&ledc_conf2);
//if(ledc_conf.duty > 1000) {
// ledc_conf.duty = 800;

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


Loading…
Cancel
Save