Skip to content

Commit

Permalink
Merge pull request #619 from RPi-Distro/robot_curve2
Browse files Browse the repository at this point in the history
Continuation of #306
  • Loading branch information
waveform80 committed Feb 19, 2018
2 parents 339fb1b + a98a601 commit e6a30f0
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 25 deletions.
58 changes: 51 additions & 7 deletions gpiozero/boards.py
Original file line number Diff line number Diff line change
Expand Up @@ -1199,27 +1199,71 @@ def value(self):
def value(self, value):
self.left_motor.value, self.right_motor.value = value

def forward(self, speed=1):
def forward(self, speed=1, **kwargs):
"""
Drive the robot forward by running both motors forward.
:param float speed:
Speed at which to drive the motors, as a value between 0 (stopped)
and 1 (full speed). The default is 1.
"""
self.left_motor.forward(speed)
self.right_motor.forward(speed)
def backward(self, speed=1):
:param float curve_left:
The amount to curve left while moving forwards, by driving the
left motor at a slower speed. Maximum ``curve_left`` is 1, the
default is 0 (no curve). This parameter can only be specified as a
keyword parameter, and is mutually exclusive with ``curve_right``.
:param float curve_right:
The amount to curve right while moving forwards, by driving the
right motor at a slower speed. Maximum ``curve_right`` is 1, the
default is 0 (no curve). This parameter can only be specified as a
keyword parameter, and is mutually exclusive with ``curve_left``.
"""
curve_left = kwargs.pop('curve_left', 0)
curve_right = kwargs.pop('curve_right', 0)
if kwargs:
raise TypeError('unexpected argument %s' % kwargs.popitem()[0])
if not 0 <= curve_left <= 1:
raise ValueError('curve_left must be between 0 and 1')
if not 0 <= curve_right <= 1:
raise ValueError('curve_right must be between 0 and 1')
if curve_left != 0 and curve_right != 0:
raise ValueError('curve_left and curve_right can\'t be used at the same time')
self.left_motor.forward(speed * (1 - curve_left))
self.right_motor.forward(speed * (1 - curve_right))

def backward(self, speed=1, **kwargs):
"""
Drive the robot backward by running both motors backward.
:param float speed:
Speed at which to drive the motors, as a value between 0 (stopped)
and 1 (full speed). The default is 1.
:param float curve_left:
The amount to curve left while moving backwards, by driving the
left motor at a slower speed. Maximum ``curve_left`` is 1, the
default is 0 (no curve). This parameter can only be specified as a
keyword parameter, and is mutually exclusive with ``curve_right``.
:param float curve_right:
The amount to curve right while moving backwards, by driving the
right motor at a slower speed. Maximum ``curve_right`` is 1, the
default is 0 (no curve). This parameter can only be specified as a
keyword parameter, and is mutually exclusive with ``curve_left``.
"""
self.left_motor.backward(speed)
self.right_motor.backward(speed)
curve_left = kwargs.pop('curve_left', 0)
curve_right = kwargs.pop('curve_right', 0)
if kwargs:
raise TypeError('unexpected argument %s' % kwargs.popitem()[0])
if not 0 <= curve_left <= 1:
raise ValueError('curve_left must be between 0 and 1')
if not 0 <= curve_right <= 1:
raise ValueError('curve_right must be between 0 and 1')
if curve_left != 0 and curve_right != 0:
raise ValueError('curve_left and curve_right can\'t be used at the same time')
self.left_motor.backward(speed * (1 - curve_left))
self.right_motor.backward(speed * (1 - curve_right))

def left(self, speed=1):
"""
Expand Down
146 changes: 128 additions & 18 deletions tests/test_boards.py
Original file line number Diff line number Diff line change
Expand Up @@ -724,38 +724,148 @@ def test_traffic_hat():

def test_robot():
pins = [Device.pin_factory.pin(n) for n in (2, 3, 4, 5)]
def check_pins_and_value(robot, expected_value):
# Ensure both forward and back pins aren't both driven simultaneously
assert pins[0].state == 0 or pins[1].state == 0
assert pins[2].state == 0 or pins[3].state == 0
assert robot.value == (pins[0].state - pins[1].state, pins[2].state - pins[3].state) == expected_value
with Robot((2, 3), (4, 5)) as robot:
assert (
[device.pin for device in robot.left_motor] +
[device.pin for device in robot.right_motor]) == pins
assert robot.value == (0, 0)
check_pins_and_value(robot, (0, 0))
robot.forward()
assert [pin.state for pin in pins] == [1, 0, 1, 0]
assert robot.value == (1, 1)
check_pins_and_value(robot, (1, 1))
robot.backward()
assert [pin.state for pin in pins] == [0, 1, 0, 1]
assert robot.value == (-1, -1)
check_pins_and_value(robot, (-1, -1))
robot.forward(0)
check_pins_and_value(robot, (0, 0))
robot.forward(0.5)
assert [pin.state for pin in pins] == [0.5, 0, 0.5, 0]
assert robot.value == (0.5, 0.5)
check_pins_and_value(robot, (0.5, 0.5))
robot.forward(1)
check_pins_and_value(robot, (1, 1))
robot.forward(curve_right=0)
check_pins_and_value(robot, (1, 1))
robot.forward(curve_left=0)
check_pins_and_value(robot, (1, 1))
robot.forward(curve_left=0, curve_right=0)
check_pins_and_value(robot, (1, 1))
robot.forward(curve_right=1)
check_pins_and_value(robot, (1, 0))
robot.forward(curve_left=1)
check_pins_and_value(robot, (0, 1))
robot.forward(0.5, curve_right=1)
check_pins_and_value(robot, (0.5, 0))
robot.forward(0.5, curve_left=1)
check_pins_and_value(robot, (0, 0.5))
robot.forward(curve_right=0.5)
check_pins_and_value(robot, (1, 0.5))
robot.forward(curve_left=0.5)
check_pins_and_value(robot, (0.5, 1))
robot.forward(0.5, curve_right=0.5)
check_pins_and_value(robot, (0.5, 0.25))
robot.forward(0.5, curve_left=0.5)
check_pins_and_value(robot, (0.25, 0.5))
with pytest.raises(ValueError):
robot.forward(-1)
with pytest.raises(ValueError):
robot.forward(2)
with pytest.raises(ValueError):
robot.forward(curve_left=-1)
with pytest.raises(ValueError):
robot.forward(curve_left=2)
with pytest.raises(ValueError):
robot.forward(curve_right=-1)
with pytest.raises(ValueError):
robot.forward(curve_right=2)
with pytest.raises(ValueError):
robot.forward(curve_left=1, curve_right=1)
robot.backward()
check_pins_and_value(robot, (-1, -1))
robot.reverse()
check_pins_and_value(robot, (1, 1))
robot.backward(0)
check_pins_and_value(robot, (0, 0))
robot.backward(0.5)
check_pins_and_value(robot, (-0.5, -0.5))
robot.backward(1)
check_pins_and_value(robot, (-1, -1))
robot.backward(curve_right=0)
check_pins_and_value(robot, (-1, -1))
robot.backward(curve_left=0)
check_pins_and_value(robot, (-1, -1))
robot.backward(curve_left=0, curve_right=0)
check_pins_and_value(robot, (-1, -1))
robot.backward(curve_right=1)
check_pins_and_value(robot, (-1, 0))
robot.backward(curve_left=1)
check_pins_and_value(robot, (0, -1))
robot.backward(0.5, curve_right=1)
check_pins_and_value(robot, (-0.5, 0))
robot.backward(0.5, curve_left=1)
check_pins_and_value(robot, (0, -0.5))
robot.backward(curve_right=0.5)
check_pins_and_value(robot, (-1, -0.5))
robot.backward(curve_left=0.5)
check_pins_and_value(robot, (-0.5, -1))
robot.backward(0.5, curve_right=0.5)
check_pins_and_value(robot, (-0.5, -0.25))
robot.backward(0.5, curve_left=0.5)
check_pins_and_value(robot, (-0.25, -0.5))
with pytest.raises(ValueError):
robot.backward(-1)
with pytest.raises(ValueError):
robot.backward(2)
with pytest.raises(ValueError):
robot.backward(curve_left=-1)
with pytest.raises(ValueError):
robot.backward(curve_left=2)
with pytest.raises(ValueError):
robot.backward(curve_right=-1)
with pytest.raises(ValueError):
robot.backward(curve_right=2)
with pytest.raises(ValueError):
robot.backward(curve_left=1, curve_right=1)
with pytest.raises(TypeError):
robot.forward(curveleft=1)
with pytest.raises(TypeError):
robot.forward(curveright=1)
robot.left()
assert [pin.state for pin in pins] == [0, 1, 1, 0]
assert robot.value == (-1, 1)
check_pins_and_value(robot, (-1, 1))
robot.left(0)
check_pins_and_value(robot, (0, 0))
robot.left(0.5)
check_pins_and_value(robot, (-0.5, 0.5))
robot.left(1)
check_pins_and_value(robot, (-1, 1))
with pytest.raises(ValueError):
robot.left(-1)
with pytest.raises(ValueError):
robot.left(2)
robot.right()
assert [pin.state for pin in pins] == [1, 0, 0, 1]
assert robot.value == (1, -1)
check_pins_and_value(robot, (1, -1))
robot.right(0)
check_pins_and_value(robot, (0, 0))
robot.right(0.5)
check_pins_and_value(robot, (0.5, -0.5))
robot.right(1)
check_pins_and_value(robot, (1, -1))
with pytest.raises(ValueError):
robot.right(-1)
with pytest.raises(ValueError):
robot.right(2)
robot.reverse()
assert [pin.state for pin in pins] == [0, 1, 1, 0]
assert robot.value == (-1, 1)
check_pins_and_value(robot, (-1, 1))
robot.stop()
check_pins_and_value(robot, (0, 0))
robot.stop()
assert [pin.state for pin in pins] == [0, 0, 0, 0]
assert robot.value == (0, 0)
check_pins_and_value(robot, (0, 0))
robot.value = (-1, -1)
assert robot.value == (-1, -1)
check_pins_and_value(robot, (-1, -1))
robot.value = (0.5, 1)
assert robot.value == (0.5, 1)
check_pins_and_value(robot, (0.5, 1))
robot.value = (0, -0.5)
assert robot.value == (0, -0.5)
check_pins_and_value(robot, (0, -0.5))

def test_ryanteck_robot():
pins = [Device.pin_factory.pin(n) for n in (17, 18, 22, 23)]
Expand Down

0 comments on commit e6a30f0

Please sign in to comment.