Snakebot: An Extensible Slitherer

Constructors Construction
Constructors Construction (click for video)






Garter Snake

Inspiration from Nature:
Garter Snake in Brighton Park


Introduction

Snakebot is an indefinitely extensible robot platform that employs a moving-wave method of locomotion analogous to the serpentine gait of biological snakes. It was designed and constructed by a team of undergrads led by prof Randal Nelson, at the University of Rochester in spring 2017 as the class project for Computer Science 230: Robot Construction.

Why build a robot snake? We can think of at least three reasons: First, for fun. Novelty, entertainment, challenge (and learning). You can't buy a robot snake at your local hobby store. The only ones out there are research projects. If you want to play with one, you need to build it. Second, snakes have an interesting mode of locomotion - neither legged nor wheeled, and can move in ways, and go places neither legged nor wheeled vehicles are able to. The gaits are interesting from a scientific standpoint. Three, a snake is indefinitely extensible. Unlike a four or six-legged walker, or a wheeled rover, length can be added to a snake without substantially modifying the underlying architecture. With some of the gaits, wherever the head goes, the rest of the snake follows, which potentially simplifies route-finding for a large device. If the head gets through, the rest of the snake can usually follow without being blocked.

OK, so if a snake is a non-wheeled vehicle, why does our snake have wheels? The answer is that serpentine motion requires directionally differential friction against the substrate. The wheels provide that. They are not powered, but passive. If replaced by ice-skates or skis, our snake would move on ice or snow. If replaced by fins, it would swim (if it floated).

In nature, snakes push against obstacles and irregularities in the ground. This requires some ability to move out of a plane, and possibly, to sense those irregularities. To simplify the device to something we could build, we limited our snake to move on a flat floor. A floor has no irregularities, and real snakes have no wheels. They have difficulty on smooth surfaces and resort to a sidewinding gait, which involves corkscrewing out of the plane. We could not find a way to pack inexpensive commodity actuators densely enough to provide both horizontal and vertical flexing. So our snake has wheels.




Snake Skeleton

Real snake skeleton
Image source




Wooden Snakebot mockup showing alternating orientation of segments.




Mockup of design providing both vertical and horizontal flexibility,
unfortunately, too large to be practical with our actuators.




Snakebot body segments as implemented




Aluminum brackets used for attaching segment components to each other




Servo gearbox with one attached bracket


Mechanical Design

Real snakes have a large number of vertebrae, 200-400+, which gives them an extreme degree of flexibility. Horizontally, the body can typically bend through at least 3 complete revolutions, and there is considerable vertical flexibility as well. Our budget was not up to hundreds of segments, and current actuator technology does not lend itself to large numbers of closely-spaced units. Instead, we looked at the minimal number of segments that would permit smooth, serpentine locomotion. It turns out that producing at least a full sinusoidal curve is desirable. Breaking the sinusoid into 16 parts gives a reasonably smooth approximation. Total curvature of a sinusoid intersecting the axis at 45 degrees is 180 degrees, but the degree of curvature is not uniform. Allowing a 16-segment unit to form a complete circle provides sufficient flexibility by a slight margin, which implies that each segment needs to be able to bend by at least 360/16 = 22.5 degrees. To provide margin for steering and other endeavors we went for a design with 20 segments, each able to bend 30 degrees.

Real snakes are quite strong mechanically. They can typically extend their body by at least 10 times its thickness, small ones considerably more. This strength is necessary for serpentine propulsion, as local forces must be propagated to slide the entire body forward along a continuously curving trajectory. For economy, and to simplify our design consideration, we planned to use RC standard hobby servos as actuators. Unfortunately, even the strongest available servos did not supply sufficient torque to support a chain of 10 of them extended under their own weight (plus batteries and and peripheral architecture). We ended up adding an additional level of gearing to the strongest available servos. Fortunately we were able to buy pre-made gear-boxes designed for just this purpose.

Body Segments

Snakebot consists of a head and a series of body segments. The servo and gearbox used to power the segments are a fixed form factor and constrain the design. In order to reduce the torques required, it is desirable to minimize the length of individual segments. The segments also need to be able to rotate 30+ degrees with respect to one another without colliding. To explore the possibilities, we constructed wooden mockups whose shape contained the servo-gearbox units, and tried fitting them together.

It turns out that the closest spacing is obtained by inverting every other unit so that the main bodies of the gearboxes can be staggered. The smallest repeating unit is thus a pair of servos: one up, one down. The mockup can be seen in the figure to the right. We also experimented with configurations allowing both horizontal and vertical flexibility. Unfortunately, we were unable to find a sufficiently compact design using the actuators we had available. Our best effort is illustrated in the figures.

The gearboxes we used are constructed about a strong aluminum frames (CNC milled in fact) with a number of pre-drilled and holes tapped for 6-32 screws. We fabricated custom brackets from 1/16" sheet aluminum for attaching the gearboxes to the gears of the previous stages, and for mounting other pieces of hardware. The semicircular cutouts provide clearance for the gears when the body is flexed. Brackets fabricated from 1/8" x 1/2" aluminum stock support the wheel units. The screws must be firmly installed with lock washers, or they work loose under the alternating forces experienced during locomotion.

Snakebot as built contains 10, 2-segment units, for a total of 20 powered segments, plus the head, which has its own servo, allowing it to be wagged independently if desired. The Arduino Micros we use for control can reasonably manage four servos apiece (other ports are used for a variety of signaling and communication functions). Units thus alternately bear a micro-controller and a battery. With this consideration, the basic repeating unit consists of four servo-gearbox elements, one controller, and one battery.

The architecture and control strategy were designed to permit additional four-servo modules to be added without modifying the programming or connections (except for plugging in the wires that connect the new module to the one ahead of it). The serpentine method of locomotion ensures that wherever the head goes, the rest of the snake follows, moving in the same direction. Thus as long as the head is successfully guided through the environment, an indefinitely long body can follow without modification of navigation or locomotion algorithms.

Differential friction

As mentioned above, serpentine locomotion requires differential friction under the snake body. Specifically, it must be easier to move the snake along its body than across it. The current version uses wheels to achieve this, though ice-skates or skis would work equally well, or even slippery plastic outriggers in grass. One set of wheels per 2-segment unit proved sufficient for support and locomotion, with an additional set to support the head, for a total of 11, 2-wheel units. The snake architecture is quite rigid, so to accommodate minor variations in the terrain, the wheels were mounted with independent suspension

To reduce the collision envelope in sharp turns and for aesthetic considerations, the wheels were kept as small as practical (a staggering strategy could also achieve this). We used rubber tires to provide traction on slippery lab floors. The wheels themselves are LEGO components. Axles, support blocks, and suspension were custom made by us. The axles are 3/16 inch brass rod with a machined groove to accept a retainer ring. They are friction fit in holes in the support blocks. The support blocks are machined from 1/2 inch polycarbonate stock (alternatively, they could be 3-D printed). The suspension consists of leaf springs made from laminated polyester boning, a dressmaking material that substitutes for actual whalebone in corsets and other garments. An assembled wheel unit is shown to the right.




Slithering

Although we tend to think of snakes as always slithering, they, like quadrupeds, can employ several different gaits. The familiar slithering motion is referred to as a serpentine gait. Another mode of locomotion is the sidewinding gait, which is employed on smooth or unstable surfaces like sand. Snakes can also move in a caterpillar-like fashion; and in tight spaces or on trees and branches they sometimes employ an accordion gait where loops of the body are alternately braced against the environment and extended to provide forward motion.

The serpentine gait is probably the simplest to understand, and has the added advantage that it can be implemented in a horizontal plane. Sidewinding and caterpillaring require vertical flexing. The easiest way to visualize the serpentine gait is to imagine a continuously curving path, e.g. a sinusoid drawn on the ground. A snake in serpentine motion slides along this path so that each point along the snake's body passes directly over each point on the path. If a traveling waveform exactly matching the path is passed down the snake's body, then forward motion of the snake along the path will allow the wave to pass while maintaining contact with the path.

It turns out, that generating such a traveling wave will actually propel the snake along the path if the body is constrained against moving sideways at a sufficient number of points (5-6 and higher generally works well). To visualize this, imagine the snake to be a piece of springy wire specially shaped to fit in a tube that follows the path (preventing sideway movement). In the original position, the wire rests happily without exerting any forces on the tube (except downward due to gravity) Now imagine the the shape of the springy wire is changed so that it matches the tube a short, distance ahead. Unless the tube has constant curvature the wire will no longer quite fit in its current location, and will be distorted, pushing against the sides, and storing some potential energy. If the wire is moved forward, it will again fit, and the stored spring energy will be zero. This change in potential manifests as a force pushing the snake forward in the tube as the wave propagates.

The fact that no distortion arises from motion along a path of constant curvature (a straight line or a section of a circle) implies that the forces propelling the snake arise primarily from locations where the curvature is changing rapidly. In the case of a sinusoid, those are the inflection points. However, the path does not actually need to be a sinusoid, or any other specific shape: it just needs sufficient changes of curvature throughout its length.

A useful navigation strategy is for the head to select an appropriate path, sensing and avoiding obstacles, while brushing around them in a way that lays a propulsive inflection zone. The rest of the snake follows. This is how real snakes appear to operate, with secondary adjustment of the body contour as needed if pressure-zones fail or move. In our design, we engineer away the need for 3-D environmental structure and the sophisticated sensing required to detect and exploit it by using wheels to constrain sideways movement at every position along the body. The head selects an obstacle-avoiding path consisting of a modifiable sinusoid, but does not need to also identify and exploit useable pressure zones.




Electrical System



Snakebot battery




HiTec HS-7950TH Servo




Arduino processor support board.
Electrical schematic
Arduino port connections for joint board
Arduino port connections for brain board





User control switchboard.
Schematic (Rotate 90 degrees clockwise to align with image above)




Tongue sensor.




Range sensors.




Installed joint processor board with interconnect wiring attached.



The electrical system of Snakebot comprises the RC-standard servo units (which are also part of the mechanical system) the Arduino-based segment control units and their support boards, the Arduino-based central control system (brain) and its support board, an auxiliary control/switch board, the power supply system (segment batteries etc.), and the connecting wiring. It also incorporates the several sensors used by Snakebot for navigational purposes.

Power System

Power is supplied by 7.4V 2000mAh lithium-polymer (LiPo) batteries, each powering 4 servo segments. Multiple batteries are needed because 20 servo-motors (which can pull 6 amps each) all running together pull more power than can be supplied by a single battery of reasonable size. All batteries are connected to a common ground, but the power supplies for each unit are independent (the positive terminals are not linked). Linking the power systems directly would require heavy wires running between units, and could also allow an electrical fault, such as a short, to damage all the power supplies. A more sophisticated interconnect could allow power to be shared, but was judged unnecessary for this project. Both the Arduino boards and the servos can be run on 7.4V, so no auxiliary voltage regulation is not needed.

It is desirable to have some way of switching the power for each segment so that components (especially motors) do not turn on as soon as the battery is plugged in. In fact, because the motors can produce unpredictable behavior if powered up in the absence of a control signal, it is desireable to separately switch power to the controller boards and the motors. Using two manual switches per segment is awkward. Instead, each segment-control board is equipped with two relays: one (5V, 3A) that switches power the micro-controller, and a second (5V, 16A) latching relay that switches power to the motors. The processor relays are connected to a broadcast circuit powered by a simple manual switch and the latching motor relays to a reversible pushbutton switch.

Startup procedure is to throw the processor-on switch, wait for the processors to initialize and display ready status (via signal LEDs on the boards), and then throw the motor-on switch. For shutdown, the motors are de-energized first, then the processors are shut off. Turning off the processors first causes potentially damaging, spasmodic movements to occur, since the micro-controllers can be interrupted in the middle of sending a position control pulse, resulting in the servo receiving a random position. We did this accidentally once and broke gears when the bot spasmed into a tangled, heap that put excessive loads on some of the joints. The circuit should be redesigned with a hardware interlock to prevent the boards from being powered down when the motors are powered, but we'd already used all the space on our boards and couldn't fit in the additional components.

It turns out to be necessary to condition the power going to the Arduino boards. Without external filtering, motor operation introduces noise that occasionally causes the supply voltage to dip low enough that the micro-controller resets or jumps to an un-programmed state. Examining the signal on an oscilloscope revealed that the dips, were very short - on the order of 10 us duration. It is unclear what produces the noise - the times seem too short to be due to motor switching. However, inserting a low-pass filter consisting of a 1.8 Ohm resistor and a 47 uF capacitor (characteristic time = 85 us) between the Arduino system and the supply eliminated the problem. Using a higher voltage power supply to the Arduinos might also fix the problem, but that would require separate power supplies, since the servos should not be run at more than 7.4V.

Servo Motors

The joints are powered by RC standard hobby servos, which are used in radio control planes and vehicles. These provide positional control with a simple, well supported interface, that is easy to access from an Arduino or raw microcontroller. Specifically, the servos are HiTec HS-7950TH standard-sized servos which provide 486 oz-in of torque at 7.4 V. These are the strongest RC-standard servos easily available, but even this was not sufficient for the snakebot application. An external gearbox, manufactured be ServoCity provides an additional 7-1 geardown, and also a solid frame to which all parts are connected.

RC-standard servos have a three-wire connection. Two of the wires are power (red) and ground (black). The third (yellow) takes a PWM (pulse-width-modulation) control signal consisting of a 5V square pulse, nominally between 1000us and 2000us, transmitted approximately 50 times per second. These pulse trains are generated by the Arduino, and encode a desired position.

The HS-7950TH servos have a command range of 120 degrees, which amounts to 60 degrees either side of center (they can be moved farther than this manually). The specified pwm control range is 750-2250us. The gearbox has its own potentiometer, which must be substituted for the servo's internal one. This requires significant modification of the servo unit, including removal of an internal mechanical stop, unsoldering of the internal pot, machining a slot for the potentiometer wires, and attachment of the external pot.

A 1500 us pulse train commands the servo to move to the center of its range. Longer or shorter pulses command positions clockwise or counterclockwise of center at a nominal rate of .080 degrees/us. With the gearbox attached, we found the rate experimentally to be .095 degrees/us (1.05 us/degree), and used this value in writing the control programs.

Arduino Support Boards

The micro-controllers used for Snakebot are Arduino Micros which consist of a Amtel ATmega32U4 micro-controller chip mounted on a miniature PCB (printed circuit board) along with support and interconnect electronics. The units are small (3/4" x 2") lightweight, and have pins for mounting in standard header sockets.

In our design, each group of 4 segments has a dedicated support board that contains the Arduino controller with sockets for connecting to its terminals, a power conditioning filter, processor and motor power-on relays, 4 LEDs of different colors for displaying diagnostic information and a motor-power LED, an external motor freewheel diode to prevent voltage spikes when the motor current is switched, and a power/control pin block for connecting the four joint servos. The board also has a power plug for connecting to the battery.

The support boards were constructed by joining (via super-glued strips underneath) two sections of solderable prototype PCB having traces that duplicate the connections on standard breadboard. These traces were used as much as possible to connect the board components, with soldered jumpers added where necessary. The Arduino plugs into tripled standard header sockets (a 3 x 17 block on each side), which allows broadcast communication wiring to be connected to its terminals using in-out jumpers.

Each board contains nearly 200 soldered connections, so making them is a bit of work. A progressive process, with periodic examination and testing by multiple persons, was employed.

Brain Board

The same support board and processor used for the joint controllers was used for the central controller/brain unit. The brain Arduino runs a different program, and the ports are connected differently, but the same power conditioning is needed, and the LED indicators are still useful. Only one servo, for moving the head, is attached to the motor output pin block. Other pins are connected to sensor units. The micro is a bit minimal for the brain. With tongue-touch, side-looking IR, and forward-looking ultrasonic range sensors, every pin is utilized. There are potential uses for more inputs.

Control Switchboard

Switches for user control of the snake are mounted on a separate PCB board on the head. Power to the Arduino processors is controlled by a toggle switch. When this switch is closed, current is supplied to the broadcast circuit that activates the (3A) Arduino power relay on each module-support board.

Power to the servos/motors is controlled by a double-pole, double-throw (4-way) switch (implemented with two 3-way switches) with an "on" and an "off" position, and an "activate" pushbutton. When the 4-way switch is in the "on" position, pushing the activate button supplies current to a broadcast circuit that switches the motor power latching relay on each support board into the closed configuration, supplying power to the motors. Similarly, pushing the activate button with the 4-way switch in the "off" position, opens the motor power latching relays. Latching relays were employed because hold-open relays capable of carrying 16A draw enough current to significantly load the battery powering the head, brain, and sensors.

Sensors

The head unit contains a variety of sensors. A flexible forked "tongue" extending about 8" in front of the head contains a pair of resistive flex sensors arranged in a forward-pointing "V". These provide an emergency stop signal if the snake is about to run into an obstacle. They also provide an easy way for the user to stop the snake by touching them.

The head also contains a pair of infrared distance sensors that point approximately 30-40 degrees either side of the direction of travel. The particular devices used are Sharp GP2Y0A21YK0F infrared proximity sensors (data sheet via mouser.com). They have an effective range of approximately 10-80 cm, and output an analog voltage That varies inversely with distance. These are primarily intended to pick up obstacles to the side of the snake (especially walls) so that the bot can adjust its course to avoid running into them. Because of the back-and-forth motion of the head during slithering, the output of these sensors can be integrated over time to produce a rough distance map of the region in front of the snake.

Finally, there is a forward-pointing ultrasonic distance sensor with an effective range of approximately 2cm-4m. This is intended to supply information about the environment in front of the snake so an obstacle-avoiding course can be planned. The specific device is the HC-SR04 ultrasonic range finder, which is essentially a lower-cost clone of the Parallex PING sensor (datasheet via micropic.com). As with the infrared sensors, the scanning movement of the head can be used to build up a rough distance map. The ultrasonic sensor is less reliable than the infrared sensors, especially at longer distances. This is due both to the fact that the strength of the returned signal depends strongly on the orientation of the reflecting obstacle, with inside corners being especially strong reflectors, and to the fact that a return may come from several different objects in the same general direction, which can confuse the sensor's internal computation.

Additional sensors could be useful. However, at this point we have used all the ports on the Arduino micro serving as the brain, so that will have to wait for an upgrade of the brain board.

Interconnect

Each board is connected locally to the battery for the segment it is on. The connection is via a male JST lead soldered to the main power rails on the board. The four servos controlled by each segment board are plugged into the pin block using their native female leads, which fit standard header pins.

All the boards share a common ground, provided by doubled ground jumpers run between boards (black and white wires in the picture). This creates a ladder distribution, which is robust against connection failures. Any single connection can be severed without disconnecting the network.

There are broadcast circuits activating the relays that switch power to the board and servo. These are provided by jumpers that run from board to board. Each board has two socket headers connected to each broadcast circuit, allowing the boards to be connected with pluggable jumpers. In the picture, the white and purple leads are the board and servo relays. They are activated by manual switches mounted on the head segment, and powered from its battery.

There are four other broadcast control circuits (red, orange, yellow and green ribbon). These carry digital signals whose combinations specify basic activities (e.g. rest, slither, reverse, adjust...). All these connections are made via the 3 x 17 socket blocks in which the Arduino Micro is mounted. The Arduino is configured so that these channels use adjacent ports, so the connections between boards can be made using ribbon jumpers.

Finally, the RX and TX ports are used to carry serial communications that implement the propagated wave motion. These connections are doubled because serial protocols are particularly sensitive to interference (yellow and green pair).

The central controller/brain board provides the broadcast signals. For convenience, the same Arduino ports are used for the ribbon cable connections, though the function is different. There are also ports for tongue/feeler, IR range, and ultrasonic range sensor input.




Control/Programming/Software

There are two levels of program control in Snake-bot. A program on the brain board handles sensing and navigation, and sends configuration and movement commands to the joint controller boards, each of which runs an instantiation of a joint controller program. Each joint processor manages control of 4 sequential snake joint servos. It is connected via serial ports to the processors controlling the joints directly in front and behind. It is also connected directly to the brain processor via digital broadcast lines.

Much potential Snake-bot behavior remains to be implemented in software. The code described below implements a basic demonstration of forward sinusoidal slithering and turning sufficient to navigate down a hallway while avoiding collision with the walls. In addition behaviors are provided that allow the snake to be started up from a "stretched-straight" storage state, and returned to that state at the close of a demonstration.

Heartbeat

At the lowest level, all processors run a heartbeat cycle. This is the basic control loop, and represents the fastest rate at which the system can update outputs or respond to any input. Currently the heartbeat for the joint controllers is 100 Hz, and that for the brain is 50 Hz. The heartbeat loops ARE NOT synchronized between processors. All communication protocols are written to be asynchronous. This produces an architecture that is more robust against local faults and transient communication failures.

The conceptual control architecture is a state machine. While in the heartbeat loop, the controller is in one of several states. At every heartbeat, the controller performs servicing actions associated with the current state, (e.g. setting servo positions, reading sensors, blinking LED...) and then decides whether to remain in the state, or transition to a new one. Certain global information is available including how many heartbeats the system has been in the current state, and a number of program counters that cycle at different rates. The latter allow services that do not have to be performed every heartbeat to be executed on a regular schedule, and for operations that occur more slowly than the heartbeat to be sequenced.

Communication

In propagating-wave slithering, the joint processors sequentially read joint angles, originating from the brain, from the incoming serial port. These are buffered appropriately, used to set the angles of the controlled servos, and then passed to the next controller via the serial out port. To permit fine-grain at a high update rate, the size of the joint angle buffer is several times the number of controlled servos, which are set from fixed offset from the buffer head. There is also a long buffer tail past the point at which the output is obtained. This permits a motion history to be "reversed" and used for backing the snake up if it gets into a tight situation (up to the limit of the stored data).

All communication is asynchronous. The brain can send joint positions at whatever rate it likes. If carelessly programmed, it could swamp the serial input buffer. We try to make this hard to do accidentally by running the joint controller heartbeat at twice the rate of the brain (100 Hz vs. 50 Hz) and generally having the brain send only one new position per heartbeat.

It takes two bytes to send a servo position, which makes a variety of transmission errors possible. Some error checking is performed on the received values to make sure they represent legal and reasonable servo positions, and that pairing of the bytes is not out of synch. Anything that looks like an error is simply dropped, and if an odd number of bytes > 2 are waiting, the first one is flushed. Because byte pairs that go together are sent in rapid succession, this protocol statistically recovers quickly from occasional transmission errors. It might be reasonable to implement a flag byte protocol for additional robustness. In any case, dropping a value generally produces just a small glitch in snake motion, since the slithering functions are typically continuous and smooth

The broadcast lines convey codes that tell the joint processors which of several modes they should be operating in. These modes include stopped/frozen, adjustment to a configuration, and active slithering. Serial data transmission can occur without movement in the stopped state to load a global configuration.

Joint Controller State Machine

Three states are currently fully implemented for the joint controller: STOP, ADJUST, and MOVE_FWD. The program contains boilerplate for several others not yet implemented.

In the STOP state, joint movement is frozen, but position information can flow through the joint-angle buffers. This allows a pre-form position to be set. Information flow is regulated by the brain. It sends a sequence of positions on the serial line. When a new position shows up at the input, a joint controller shifts its buffer and sends the pushed out value to the next joint controller in line.

The ADJUST state moves the snake gradually towards whatever position is currently in the buffer locations associated with each servo. This is needed because the servos are strong and fast, and if a move to a preset position was commanded all at once, the resulting violent motion could damage the bot and possibly humans in its vicinity. New position information can flow through the buffer at the same time, but this is not the intended mode of operation.

In the MOVE_FWD state, the brain supplies new joint positions at a regular rate, which as they flow down the servo chain, produce a moving wave that propels the snake forward. In the current implementation, the joint angles supplied produce a moving sinusoid. Specifically, the joint angles sent represent the local curvature of the generated sinusoid. Turning is accomplished by biasing the sent angles up or down, which generates an overall net curvature of the path.

Transition between states is controlled by the brain through setting of the broadcast digital control lines. This allows the snake to be stopped or started all at once without waiting for a command to ripple down the serial "bucket brigade". Before switching states, the joint controllers ensure that the command is stable and represents a legal transition from the current state. Illegal or unrecognized commands invoke a "safe" transition, usually staying the current state, but possibly by going into STOP state and freezing all movement. Arduino Micro C code for the joint controllers can be examined HERE. Note this is still developmental and is certainly not optimal. There could even be bugs.

Brain Controller State Machine

In the brain, four states are currently fully implemented: WAIT, LOAD_STRAIGHT, ADJUST, and SLITHER_FWD. Boilerplate exists for several others.

In WAIT, Snake-bot is quiescent. The servos are energized, but just hold whatever position was last commanded. No data is sent down the serial chain. Snake-bot boots up in the WAIT state. Leaving it currently requires the operator to push a button on the control panel. It can transition to LOAD_STRAIGHT, ADJUST, or SLITHER_FWD depending on which button is pushed and whether a pose has been pre-loaded to the joint servo buffers.

LOAD_STRAIGHT sends the neutral servo position down the serial chain long enough to fill all buffers. This corresponds to a straight, stretched-out, Snake-bot pose. The servos are not active while this is occurring, and no movement take place. Once the preload is complete, the brain transitions back to the WAIT state. Other poses could be preloaded. The current code base contains boilerplate for loading a sinusoidal pose, but the state is not currently reachable.

ADJUST instructs the node controllers to gradually move the servos from their current position to the position currently specified in the serial chain buffers. It is employed in conjunction with the LOAD states to move Snake-bot gracefully (non-violently) between set poses. Adjustment takes several seconds. When completed, the brain transitions back to WAIT.

SLITHER_FWD implements a somewhat non-trivial behavior. At the base level, the brain sends a sequence of servo positions down the serial chain that when buffered and executed by the servo units, produce a moving sinusoid that propels Snake-bot forward. The servo positions are derived from a table precomputed during initialization containing settings that produce a sinusoidal shape. By scanning through the table, the waveform can be made to move. A turning motion is generated by adding or subtracting an offset to the table values before they are sent down the serial chain.

While in SLITHER_FWD, the brain monitors the various sensors. If the tongue bend sensor registers a collision, Snake-bot transitions to WAIT, which produces an immediate halt. The same occurs if the range sensors indicate an unavoidable obstacle ahead. Sophisticated navigation could potentially avoid many such obstacles, but is not yet implemented. If the range sensors indicate a wall-like obstacle to the left or right, the steering bias is adjusted until the obstacle is far enough away not to be a collision threat. In the current implementation, Snake-bot can (usually) make its way down a corridor without touching the walls.

Arduino Micro C code for the brain can be examined HERE. As with the node controller code, this is developmental, sub-optimal, and probably buggy. For example, the ultrasonic range sensor does not perform as originally hoped. Multi-bounce echos produce false readings in most environments we have explored when the nearest obstacles are beyond a few feet and we are sampling faster than about twice a second. The ultrasonic sensing is consequently disabled.