Rotating Sensor Mast
The latest project in the cave is this 360 degree rotating sensor mast for our robot, AAIMIv2. Today I'll share the details of the build, as well as the code to run the mast.
Many of my robot's functions involve taking measurements at numerous accurate angles to learn about its environment. AAIMIv2 can turn on her wheels accurately enough for this task, but there are several good reasons to have a dedicated sensor mast.
Firstly there should be significant increase in battery-life using one small 5V motor to turn the mast rather than the two 24V motors that drive the wheels.
More importantly, I need AAIMI to know exactly where it is within its environment. Each turn the robot makes adds a minute element of error to these calculations, so the less physical 360 degree turns it needs to perform, the more accurate the calculations will be.
I have used mostly recycled parts, as usuall. I salvage the stainless steel shaft from an inkjet printer, along with matching bearings.
I made the base of the unit from a piece cut from a CD ROM drive. Underneath the steel plate, the main bearing is drilled into a small square of 3mm MDF timber, which can adjust several mm within the plate.
The entire unit is only fixed on one side and can swivell sligthly to adjust the verticle angle of the shaft.
The gears came from one of my printer teardowns. One fitted the motor well enough to require just a drop of glue to hold it in place. The other was too large for the shaft, but the sleeve of a masonry dyna-bolt bridged that perfectly.
The lower bearing is underneath the robot held in place by a large, slightly cupped washer. This allows a few milimetres of adjustment. In the image above I have adjusted it fully to the left to demonstrate.
The motor is a 5V stepper motor of the same type I used for driving the wheels of my previous robot, AAIMIv1. These motors cost about three bucks on Ebay including the controller. It is geared with a 40 to 28 ratio and turns the mast a full rotation in a few seconds.
The head of the unit is simple. I found a plastic bracket in my kit and screwed it to a piece of MDF in a way that allows sideways adjustment if required. Rubber bands hold the sensor in place and the whole assembly is tacked onto the steel shaft with a dob of glue.
The mast needs the freedom to turn 180 degrees in either direction so I have used cables of adequate length to allow that.
Overall I am happy with this project. It is really not heavy-duty, but neither is it fragile. There are four separate adjustment points to remedy any future damage. Best of all, because I already had the motor and sensor, I didn't have to spend a penny.
I have written the code below specifically for a Raspberry Pi running Raspian Linux.
One of the main requirements for the movement functions was the intelligence to stay within a 360 degree arc to avoid tearing the sensor wires apart. It also needed the ability to move the sensor directly to a given position regardless of the starting point. It achieves this with two variables, current_pos, and target_pos. The default starting value for current_pos is 0, which means the sensor is pointing directly ahead.
By default the code below provides accurate turning with the motor I have used and and the 40-to-28 gear ratio. By sheer luck this configuration requries 359 step sequences to move 360 degrees, making calculations easy. For different ratios you will need to change the adjuster variable at the top of the code. For example, if the mast is only turning to 120 degrees when you command it to 180 dgrees, you could change the adjustment variable from 1, to 1.3 and try again.
Copy and paste this code into a file and save it as mast.py. In the Raspberry Pi terminal type sudo python and type your password if prompted.
Type import mast then press Enter. Next, type mast.calc_move(position), placing the target position in degrees within the brackets. For example, to turn the sensor directly left, type mast.calc_move(270). To turn the sensor directly right, type mast.calc_move(90). Press Enter and watch the mast turn to your chosen position.
#!/bin/bash # Run a 360-degree rotating stepper-motor-powered sensor mast import time import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) # Convert full steps to degrees adjuster = 1 # Current position in degrees current_pos = 0 # Define pins for motor motor_gpio_pins = [22, 23, 24, 25] # Set all pins as output and set LOW for pin in motor_gpio_pins: print("Setup pins") GPIO.setup(pin,GPIO.OUT) GPIO.output(pin, False) #Define waitTime between steps pause = 0.006 # Create stepping sequences orders = [[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]] # Move the mast one full step sequence def mast_motor(mdirection): global orders current_order = 0 # Define order of GPIO signals to use if mdirection == "anti_clockwise": motor_gpio_pins = [22, 23, 24, 25] elif mdirection == "clockwise": motor_gpio_pins = [25, 24, 23, 22] # Work through all combinations in orders array while current_order < len(orders): # Switch each pin to suit the current combination for pin in range(0, 4): targetpin = motor_gpio_pins[pin] if orders[current_order][pin]!=0: GPIO.output(targetpin, True) #print(targetpin) else: GPIO.output(targetpin, False) current_order += 1 time.sleep(pause) # Calculate the distance and direction and move the motor to a location in degrees def calc_move(target_pos): global current_pos if target_pos < 360: if target_pos < 181: if current_pos < 181: if current_pos < target_pos: distance = target_pos - current_pos direction = "clockwise" elif current_pos > target_pos: distance = current_pos - target_pos direction = "anti_clockwise" elif current_pos > 180: distance = (360 - current_pos) + target_pos direction = "clockwise" elif target_pos > 180: if current_pos < 181: distance = (360 - target_pos) + current_pos direction = "anti_clockwise" elif current_pos > 180: if current_pos < target_pos: distance = target_pos - current_pos direction = "clockwise" elif current_pos > target_pos: distance = current_pos - target_pos direction = "anti_clockwise" moves = 0 while moves < int(distance * adjuster): mast_motor(direction) moves += 1 current_pos = target_pos print(direction) else: print("You must choose a target position between 0 and 359.") def clean_up(): GPIO.cleanup() print("Pins reset")
I will have the full version of this code, including the module to work the measurement functions, available for download from the AAIMI source code page shortly.
Comments are now live on this page.