Lesson 1. A servo: an angle by number

In pictures

After this lesson the canvas has a servo — a small motor with a horn that goes to a set angle and holds it. You set the angle with a number on four switches: 0 — the horn at 0°, 8 — at 90°, 15 — almost at 170°. In the next lesson we build an arm from such servos.


1.1. Idea: the angle is the pulse length

A servo listens to one pin, PWM. Short pulses come to it, one after another. The servo measures how long each pulse lasts and turns the horn:

  • a 0.5 ms pulse — 0°;
  • a 1.5 ms pulse — 90°;
  • a 2.5 ms pulse — 180°.

Between the pulses there is a pause; its length does not matter, as long as the pulses keep coming. This is how servos are driven in model planes, robots and 3D printers: one wire, and any angle.

window012345678910111213141516171819…PWM1number 04 windows = 0.5 ms0°PWM1number 812 windows = 1.5 ms90°PWM1number 1519 windows = 2.375 ms169°a frame is 256 windows = 32 ms, then it all repeats
A window is 0.125 ms (8 kHz clock). The pulse is on while the window number is less than “number + 4”: number 0 — 4 windows, 0.5 ms, horn at 0°; 8 — 12 windows, 1.5 ms, 90°; 15 — 19 windows, ≈ 169°.

1.2. Idea: cut time into windows

We measure the pulse length in windows. An 8 kHz clock ticks every 0.125 ms — that is one window. Two CD4029 counters in a chain count windows from 0 to 255 and start again. 256 windows make a frame 32 ms long: one pulse in each frame.

What we want. The pulse is on at the start of the frame, while the count is still small, and goes off at the right window:

  • PWM1 = 1 while the count is less than the pulse length in windows.

The CD4585, a 4-bit comparator, tells “less — greater” for two numbers. Our count has 8 bits, so there are two comparators in a chain: the low one compares the low 4 bits and passes “less” and “equal” to the high one, and the high one decides by its own bits, or, if they are equal, by the answer of the low one. That is how you compare long numbers on paper too: the high digits first, the low ones when the high ones are equal.

1.3. Idea: “number + 4”

The number on the switches is 0 to 15, but the pulse must start at 4 windows (0.5 ms = 0°). So the pulse length is number + 4 windows:

  • 0 → 4 windows = 0.5 ms = 0°;
  • each next unit adds one window, 0.125 ms, which is 11.25°;
  • 15 → 19 windows = 2.375 ms ≈ 169°.

Adding 4 means adding one to bit 2. Bits 0 and 1 do not change, and bit 2 with the carry is worked out like column addition:

A3 A2W2W3W4Example
0 01000 + 4 = 4
0 10104 + 4 = 8
1 01108 + 4 = 12
1 100112 + 4 = 16
  • W2 = NOT A2 — bit 2 flips: an inverter, CD4069.
  • W3 = A3 XOR A2 — bit 3 changes when a carry comes from bit 2: CD4070.
  • W4 = A3 AND A2 — the carry onwards, into bit 4: CD4081.

We get the number W4 W3 W2 A1 A0 — it goes to the comparators. Three gates instead of a whole adder: we always add the same number, so only the part of the adder needed for the four is left.

A3A2A1A0W3W4W2A1A0CD4070CD4081CD4069CD4585 ×2count < number + 4W4 W3 W2 A1 A0
“+4” is adding one to bit 2. Bit 2 flips (NOT), bit 3 changes when a carry comes from bit 2 (XOR), and the carry onwards, into bit 4, is when both bits are 1 (AND). Bits 0 and 1 pass as they are.

1.4. Build

A new project. The chips are ready-made, from the kit file arm-chips.json; their pins get labels (double-click a pin). Build and run in Fast (the engine button at the top).

Step 0. The chips into the library

If the library has no Arm folder yet: the import button in the library → the file arm-chips.json. The Arm folder appears — ten chips for the whole kit (and the parts they are built of inside).

Step 1. Sources

PartSettingLabel
PowerVCC
GroundGND
Clock8kHzCK
ButtonRESET
Input (switch)A0
Input (switch)A1
Input (switch)A2
Input (switch)A3

Step 2. The window counter: two CD4029

Clock — click its body until 8kHz. The PE pins of both counters go to RESET: the button sets them to 0.

PartPinLabel
TI CD4029BCLOCK
CI
BD
UD
PE
J1
J2
J3
J4
Q1
Q2
Q3
Q4
CO
CK
GND
VCC
VCC
RESET
GND
GND
GND
GND
C0
C1
C2
C3
CY
TI CD4029BCLOCK
CI
BD
UD
PE
J1
J2
J3
J4
Q1
Q2
Q3
Q4
CK
CY
VCC
VCC
RESET
GND
GND
GND
GND
C4
C5
C6
C7

Step 3. Number + 4: three gates

One gate of each chip is used; the inputs of the other gates go to GND (in lesson 2 the elbow takes them).

PartPinLabel
TI CD4069UBA
G
B
C
D
E
F
A2
W2
GND
GND
GND
GND
GND
TI CD4070BA
B
J
C
D
E
F
G
H
A3
A2
W3
GND
GND
GND
GND
GND
GND
TI CD4081BA
B
J
C
D
E
F
G
H
A3
A2
W4
GND
GND
GND
GND
GND
GND

Step 4. Compare: two CD4585 → the PWM1 pulse

PartPinLabel
TI CD4585BA0
A1
A2
A3
B0
B1
B2
B3
LTIN
EQIN
GTIN
LT
EQ
C0
C1
C2
C3
A0
A1
W2
W3
GND
VCC
VCC
LL
LE
TI CD4585BA0
A1
A2
A3
B0
B1
B2
B3
LTIN
EQIN
GTIN
LT
C4
C5
C6
C7
W4
GND
GND
GND
LL
LE
VCC
PWM1

Step 5. The servo

Menu Mechanics → Servo.

PartPinLabel
ServoPWMPWM1

Loose, do not group into a chip: in lesson 2 the second servo shares the clock, the counter and RESET with the first.

1.5. Check

  1. Turn the power on and press RESET once — the counters go to 0, the servo starts getting pulses.
  2. Switches A3 A2 A1 A0 = 0000 — the servo horn is at 0°.
  3. Set the numbers from the table — the horn turns: 11.25° for each unit of the number.
NumberSwitches A3 A2 A1 A0PulseAngle
00 0 0 00,5 ms0°
40 1 0 01,0 ms45°
81 0 0 01,5 ms90°
121 1 0 02,0 ms135°
151 1 1 12,375 ms169°

Lesson 1 paste (Cmd+I)

Paste into a new project. The chips from arm-chips.json are needed.

# Lesson 1 - a servo turned by a number: switches A3..A0, the servo goes to number x 11.25 degrees.# Paste into a new project. Chips: arm-chips.json. After power on press RESET once.# ---------- power ----------power(VCC)ground(GND)# ---------- clock 8 kHz, RESET ----------clock{hz=1}(CK)button(RESET)# ---------- shoulder number ----------input(A0)input(A1)input(A2)input(A3)# ---------- window counter: two CD4029, 0..255 ----------"TI CD4029B"(CLOCK=CK, CI=GND, BD=VCC, UD=VCC, PE=RESET, J1=GND, J2=GND, J3=GND, J4=GND, Q1=C0, Q2=C1, Q3=C2, Q4=C3, CO=CY)"TI CD4029B"(CLOCK=CK, CI=CY, BD=VCC, UD=VCC, PE=RESET, J1=GND, J2=GND, J3=GND, J4=GND, Q1=C4, Q2=C5, Q3=C6, Q4=C7)# ---------- +4 for the shoulder: one gate of CD4069, CD4070, CD4081 ----------"TI CD4069UB"(A=A2, G=W2, B=GND, C=GND, D=GND, E=GND, F=GND)"TI CD4070B"(A=A3, B=A2, J=W3, C=GND, D=GND, E=GND, F=GND, G=GND, H=GND)"TI CD4081B"(A=A3, B=A2, J=W4, C=GND, D=GND, E=GND, F=GND, G=GND, H=GND)# ---------- shoulder pulse: two CD4585, count < number + 4 -> PWM1 ----------"TI CD4585B"(A0=C0, A1=C1, A2=C2, A3=C3, B0=A0, B1=A1, B2=W2, B3=W3, LTIN=GND, EQIN=VCC, GTIN=VCC, LT=LL, EQ=LE)"TI CD4585B"(A0=C4, A1=C5, A2=C6, A3=C7, B0=W4, B1=GND, B2=GND, B3=GND, LTIN=LL, EQIN=LE, GTIN=VCC, LT=PWM1)# ---------- servo ----------mservo sh{rot=90}(PWM=PWM1)

Stuck? Something doesn't work →