forked from Cozomo-Laboratory/Cozmo-Lab
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReverse Engineering Clock.py
164 lines (163 loc) · 7.41 KB
/
Reverse Engineering Clock.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import datetime
import math
import sys
import time
try:
from PIL import Image, ImageDraw, ImageFont
except ImportError:
sys.exit("Cannot import from PIL. Do `pip3 install --user Pillow` to install")
import cozmo
SHOW_ANALOG_CLOCK = False
def make_text_image(text_to_draw, x, y, font=None):
'''Make a PIL.Image with the given text printed on it
Args:
text_to_draw (string): the text to draw to the image
x (int): x pixel location
y (int): y pixel location
font (PIL.ImageFont): the font to use
Returns:
:class:(`PIL.Image.Image`): a PIL image with the text drawn on it
'''
text_image = Image.new('RGBA', cozmo.oled_face.dimensions(), (0, 0, 0, 255))
dc = ImageDraw.Draw(text_image)
dc.text((x, y), text_to_draw, fill=(255, 255, 255, 255), font=font)
return text_image
_clock_font = None
try:
_clock_font = ImageFont.truetype("chintzy.ttf", 20)
except IOError:
try:
_clock_font = ImageFont.truetype("/Windows/Fonts/chintzy.ttf", 20)
except IOError:
pass
def draw_clock_hand(dc, cen_x, cen_y, circle_ratio, hand_length):
'''Draw a single clock hand (hours, minutes or seconds)
Args:
dc: (:class:`PIL.ImageDraw.ImageDraw`): drawing context to use
cen_x (float): x coordinate of center of hand
cen_y (float): y coordinate of center of hand
circle_ratio (float): ratio (from 0.0 to 1.0) that hand has travelled
hand_length (float): the length of the hand
'''
hand_angle = circle_ratio * math.pi * 2.0
vec_x = hand_length * math.sin(hand_angle)
vec_y = -hand_length * math.cos(hand_angle)
x_scalar = 2.0
hand_end_x = int(cen_x + (x_scalar * vec_x))
hand_end_y = int(cen_y + vec_y)
hand_width_ratio = 0.1
hand_end_x2 = int(cen_x - ((x_scalar * vec_y) * hand_width_ratio))
hand_end_y2 = int(cen_y + (vec_x * hand_width_ratio))
hand_end_x3 = int(cen_x + ((x_scalar * vec_y) * hand_width_ratio))
hand_end_y3 = int(cen_y - (vec_x * hand_width_ratio))
dc.polygon([(hand_end_x, hand_end_y), (hand_end_x2, hand_end_y2),
(hand_end_x3, hand_end_y3)], fill=(255, 255, 255, 255))
def make_clock_image(current_time):
'''Make a PIL.Image with the current time displayed on it
Args:
text_to_draw (:class:`datetime.time`): the time to display
Returns:
:class:(`PIL.Image.Image`): a PIL image with the time displayed on it
'''
time_text = time.strftime("%I:%M:%S %p")
if not SHOW_ANALOG_CLOCK:
return make_text_image(time_text, 8, 6, _clock_font)
clock_image = Image.new('RGBA', cozmo.oled_face.dimensions(), (0, 0, 0, 255))
dc = ImageDraw.Draw(clock_image)
text_height = 9
screen_width, screen_height = cozmo.oled_face.dimensions()
analog_width = screen_width
analog_height = screen_height - text_height
cen_x = analog_width * 0.5
cen_y = analog_height * 0.5
sec_hand_length = (analog_width if (analog_width < analog_height) else analog_height) * 0.5
min_hand_length = 0.85 * sec_hand_length
hour_hand_length = 0.7 * sec_hand_length
sec_ratio = current_time.second / 60.0
min_ratio = (current_time.minute + sec_ratio) / 60.0
hour_ratio = (current_time.hour + min_ratio) / 12.0
draw_clock_hand(dc, cen_x, cen_y, hour_ratio, hour_hand_length)
draw_clock_hand(dc, cen_x, cen_y, min_ratio, min_hand_length)
draw_clock_hand(dc, cen_x, cen_y, sec_ratio, sec_hand_length)
x = 32
y = screen_height - text_height
dc.text((x, y), time_text, fill=(255, 255, 255, 255), font=None)
return clock_image
def convert_to_time_int(in_value, time_unit):
'''Convert in_value to an int and ensure it is in the valid range for that time unit
(e.g. 0..23 for hours)'''
max_for_time_unit = {'hours': 23, 'minutes': 59, 'seconds': 59}
max_val = max_for_time_unit[time_unit]
try:
int_val = int(in_value)
except ValueError:
raise ValueError("%s value '%s' is not an int" % (time_unit, in_value))
if int_val < 0:
raise ValueError("%s value %s is negative" % (time_unit, int_val))
if int_val > max_val:
raise ValueError("%s value %s exceeded %s" % (time_unit, int_val, max_val))
return int_val
def extract_time_from_args():
''' Extract a (24-hour-clock) user-specified time from the command-line
Supports colon and space separators - e.g. all 3 of "11 22 33", "11:22:33" and "11 22:33"
would map to the same time.
The seconds value is optional and defaults to 0 if not provided.'''
split_time_args = []
for i in range(1, len(sys.argv)):
arg = sys.argv[i]
split_args = arg.split(':')
for split_arg in split_args:
split_time_args.append(split_arg)
if len(split_time_args) >= 2:
try:
hours = convert_to_time_int(split_time_args[0], 'hours')
minutes = convert_to_time_int(split_time_args[1], 'minutes')
seconds = 0
if len(split_time_args) >= 3:
seconds = convert_to_time_int(split_time_args[2], 'seconds')
return datetime.time(hours, minutes, seconds)
except ValueError as e:
print("ValueError %s" % e)
return None
def get_in_position(robot: cozmo.robot.Robot):
'''If necessary, Move Cozmo's Head and Lift to make it easy to see Cozmo's face'''
if (robot.lift_height.distance_mm > 45) or (robot.head_angle.degrees < 40):
with robot.perform_off_charger():
lift_action = robot.set_lift_height(0.0, in_parallel=True)
head_action = robot.set_head_angle(cozmo.robot.MAX_HEAD_ANGLE,
in_parallel=True)
lift_action.wait_for_completed()
head_action.wait_for_completed()
def alarm_clock(robot: cozmo.robot.Robot):
'''The core of the alarm_clock program'''
alarm_time = extract_time_from_args()
if alarm_time:
print("Alarm set for %s" % alarm_time)
else:
print("No Alarm time provided. Usage example: 'alarm_clock.py 17:23' to set alarm for 5:23 PM. (Input uses the 24-hour clock.)")
print("Press CTRL-C to quit")
get_in_position(robot)
was_before_alarm_time = False
last_displayed_time = None
while True:
current_time = datetime.datetime.now().time()
do_alarm = False
if alarm_time:
is_before_alarm_time = current_time < alarm_time
do_alarm = was_before_alarm_time and not is_before_alarm_time
was_before_alarm_time = is_before_alarm_time
if do_alarm:
robot.abort_all_actions()
with robot.perform_off_charger():
short_time_string = str(current_time.hour) + ":" + str(current_time.minute)
robot.say_text("Wake up lazy human! it's " + short_time_string).wait_for_completed()
else:
if (last_displayed_time is None) or (current_time.second != last_displayed_time.second):
clock_image = make_clock_image(current_time)
oled_face_data = cozmo.oled_face.convert_image_to_screen_data(clock_image)
# display for 1 second
robot.display_oled_face_image(oled_face_data, 1000.0)
last_displayed_time = current_time
time.sleep(0.1)
cozmo.robot.Robot.drive_off_charger_on_connect = False
cozmo.run_program(alarm_clock)