Permalink
Browse files

Added motor controls.

It turns out that controlling the motor via USB/Bluetooth sucks.

You don't have the really cool fine-control that you can get via
a program running on the brick itself.

So I simplified the interface for the moment to just run and stop.

I'm looking at possible solutions (such an running a program on the
brick we can talk to).
  • Loading branch information...
1 parent ba00036 commit ea69379c1a2e5b3824d3eb956e7f6947c5ac6c42 @docwhat committed Apr 23, 2012
Showing with 78 additions and 3 deletions.
  1. +7 −0 lib/lego_nxt.rb
  2. +35 −3 lib/lego_nxt/brick.rb
  3. +36 −0 spec/lib/lego_nxt/brick_spec.rb
View
7 lib/lego_nxt.rb
@@ -14,3 +14,10 @@ def LegoNXT::connect
@found_connection ||= LegoNXT::UsbConnection.new
LegoNXT::Brick.new @found_connection
end
+
+def LegoNXT::disconnect
+ unless @found_connection.nil?
+ @found_connection.close
+ @found_connection = nil
+ end
+end
View
38 lib/lego_nxt/brick.rb
@@ -54,6 +54,34 @@ def reset_motor_position port, set_relative
)
end
+ # Runs the motor
+ #
+ # @param [Symbol] port The port the motor is attached to. Should be `:a`, `:b`, `:c`, `:all`
+ # @param [Integer] power A number between -100 through 100 inclusive. Defaults to 100.
+ # @return [nil]
+ def run_motor port, power=100
+ raise ArgumentError.new("Power must be -100 through 100") if power < -100 || power > 100
+ transmit(
+ LegoNXT::DirectOps::NO_RESPONSE,
+ LegoNXT::DirectOps::SETOUTPUTSTATE,
+ normalize_motor_port(port, accept_all=true),
+ sbyte(power), # power set point
+ byte(1), # mode
+ byte(0), # regulation mode
+ sbyte(0), # turn ratio
+ byte(0x20), # run state
+ long(0), # tacho limit
+ )
+ end
+
+ # Stops the motor
+ #
+ # @param [Symbol] port The port the motor is attached to. Should be `:a`, `:b`, `:c`, `:all`
+ # @return [nil]
+ def stop_motor port
+ run_motor port, 0
+ end
+
# A wrapper around the transmit function for the connection.
#
# @param [LegoNXT::Type] bits A list of bytes.
@@ -82,12 +110,16 @@ def transceive *bits
# Converts a port symbol into the appropriate byte().
#
- # @param [Symbol] port It should be `:a`, `:b`, or `:c` (which correspond to the markings on the brick)
+ # @param [Symbol] port It should be `:a`, `:b`, `:c`, or `:all` (which correspond to the markings on the brick)
+ # @param [Boolean] accept_all If true, then `:all` will be allowed, otherwise it's an error.
# @return [UnsignedByte] The corresponding byte for the port.
- def normalize_motor_port port
+ def normalize_motor_port port, accept_all=false
@portmap ||= { a: byte(0),
b: byte(1),
- c: byte(2) }
+ c: byte(2),
+ all: byte(0xff),
+ }
+ raise ArgumentError.new("You cannot specify :all for this port") if port == :all and !accept_all
raise ArgumentError.new("Motor ports must be #{@portmap.keys.inspect}: got #{port.inspect}") unless @portmap.include? port
@portmap[port]
end
View
36 spec/lib/lego_nxt/brick_spec.rb
@@ -130,4 +130,40 @@
end
end
+ describe ".run_motor" do
+ it "should default to power 100" do
+ subject.should_receive(:transmit).with(
+ anything, anything,
+ anything, sbyte(100),
+ anything, anything, anything, anything,
+ anything,
+ )
+ subject.run_motor :a
+ end
+
+ it "should accept power" do
+ subject.should_receive(:transmit).with(
+ anything, anything,
+ anything, sbyte(42),
+ anything, anything, anything, anything,
+ anything,
+ )
+ subject.run_motor :a, 42
+ end
+
+ it "calls normalize_motor_port" do
+ port = double(name: 'port')
+ subject.should_receive(:run_motor).with(port) { byte(0) }
+ subject.run_motor port
+ end
+ end
+
+ describe ".stop_motor" do
+ it "should call run_motor" do
+ port = double
+ subject.should_receive(:run_motor).with(port, 0) { true }
+ subject.stop_motor port
+ end
+ end
+
end

0 comments on commit ea69379

Please sign in to comment.