Added ROS services for reading and writing from/to all named sensors

This commit is contained in:
Patrick Goebel 2015-12-18 15:25:13 -08:00
parent 896e60d417
commit 2de2028192
11 changed files with 105 additions and 53 deletions

View File

@ -13,12 +13,20 @@ add_message_files(FILES
add_service_files(FILES add_service_files(FILES
AnalogWrite.srv AnalogWrite.srv
AnalogSensorWrite.srv
AnalogFloatSensorWrite.srv
AnalogRead.srv AnalogRead.srv
AnalogSensorRead.srv
AnalogFloatSensorRead.srv
DigitalRead.srv DigitalRead.srv
DigitalSensorRead.srv
DigitalSetDirection.srv DigitalSetDirection.srv
DigitalSensorSetDirection.srv
DigitalWrite.srv DigitalWrite.srv
DigitalSensorWrite.srv
Enable.srv Enable.srv
Relax.srv Relax.srv
AnalogSensorRead.srv
ServoRead.srv ServoRead.srv
ServoWrite.srv ServoWrite.srv
SetSpeed.srv SetSpeed.srv

View File

@ -1,3 +1,3 @@
# Float message from a single analog IO pin. # Float message from a single analog IO pin.
Header header Header header
float64 value float32 value

View File

@ -0,0 +1,2 @@
---
float32 value

View File

@ -0,0 +1,2 @@
float32 value
---

View File

@ -0,0 +1,2 @@
---
uint16 value

View File

@ -0,0 +1,2 @@
uint16 value
---

View File

@ -0,0 +1,2 @@
---
bool value

View File

@ -0,0 +1,2 @@
bool direction
---

View File

@ -0,0 +1,2 @@
bool value
---

View File

@ -114,32 +114,20 @@ class ArduinoROS():
# Initialize individual sensors appropriately # Initialize individual sensors appropriately
for name, params in sensor_params.iteritems(): for name, params in sensor_params.iteritems():
# Set the direction to input if not specified
try:
params['direction']
except:
params['direction'] = 'input'
# Set the frame_id to the base frame if not set
try:
params['frame_id']
except:
params['frame_id'] = self.base_frame
if params['type'].lower() == 'Ping'.lower(): if params['type'].lower() == 'Ping'.lower():
sensor = Ping(self.device, name, params['pin'], params['rate'], params['frame_id']) sensor = Ping(self.device, name, **params)
elif params['type'].lower() == 'GP2D12'.lower(): elif params['type'].lower() == 'GP2D12'.lower():
sensor = GP2D12(self.device, name, params['pin'], params['rate'], params['frame_id']) sensor = GP2D12(self.device, name, **params)
elif params['type'].lower() == 'Digital'.lower(): elif params['type'].lower() == 'Digital'.lower():
sensor = DigitalSensor(self.device, name, params['pin'], params['rate'], params['frame_id'], direction=params['direction']) sensor = DigitalSensor(self.device, name, **params)
elif params['type'].lower() == 'Analog'.lower(): elif params['type'].lower() == 'Analog'.lower():
sensor = AnalogSensor(self.device, name, params['pin'], params['rate'], params['frame_id'], direction=params['direction']) sensor = AnalogSensor(self.device, name, **params)
elif params['type'].lower() == 'PololuMotorCurrent'.lower(): elif params['type'].lower() == 'PololuMotorCurrent'.lower():
sensor = PololuMotorCurrent(self.device, name, params['pin'], params['rate'], self.base_frame) sensor = PololuMotorCurrent(self.device, name, **params)
elif params['type'].lower() == 'PhidgetsVoltage'.lower(): elif params['type'].lower() == 'PhidgetsVoltage'.lower():
sensor = PhidgetsVoltage(self.device, name, params['pin'], params['rate'], self.base_frame) sensor = PhidgetsVoltage(self.device, name, **params)
elif params['type'].lower() == 'PhidgetsCurrent'.lower(): elif params['type'].lower() == 'PhidgetsCurrent'.lower():
sensor = PhidgetsCurrent(self.device, name, params['pin'], params['rate'], self.base_frame) sensor = PhidgetsCurrent(self.device, name, **params)
# if params['type'].lower() == 'MaxEZ1'.lower(): # if params['type'].lower() == 'MaxEZ1'.lower():
# self.sensors[len(self.sensors)]['trigger_pin'] = params['trigger_pin'] # self.sensors[len(self.sensors)]['trigger_pin'] = params['trigger_pin']
@ -197,9 +185,10 @@ class ArduinoROS():
# Start polling the sensors, base controller, and servo controller # Start polling the sensors, base controller, and servo controller
while not rospy.is_shutdown(): while not rospy.is_shutdown():
for sensor in self.mySensors: for sensor in self.mySensors:
mutex.acquire() if sensor.rate != 0:
sensor.poll() mutex.acquire()
mutex.release() sensor.poll()
mutex.release()
if self.use_base_controller: if self.use_base_controller:
mutex.acquire() mutex.acquire()

View File

@ -22,6 +22,7 @@
import rospy import rospy
from sensor_msgs.msg import Range from sensor_msgs.msg import Range
from ros_arduino_msgs.msg import * from ros_arduino_msgs.msg import *
from ros_arduino_msgs.srv import *
from math import pow from math import pow
LOW = 0 LOW = 0
@ -29,7 +30,7 @@ HIGH = 1
INPUT = 0 INPUT = 0
OUTPUT = 1 OUTPUT = 1
class MessageType: class MessageType:
ANALOG = 0 ANALOG = 0
DIGITAL = 1 DIGITAL = 1
@ -39,19 +40,21 @@ class MessageType:
BOOL = 5 BOOL = 5
class Sensor(object): class Sensor(object):
def __init__(self, controller, name, pin, rate, frame_id, direction="input", **kwargs): def __init__(self, device, name, pin=None, type=None, rate=0, direction="input", frame_id="base_link", **kwargs):
self.controller = controller self.device = device
self.name = name self.name = name
self.pin = pin self.pin = pin
self.type = type
self.rate = rate self.rate = rate
self.direction = direction self.direction = direction
self.frame_id = frame_id self.frame_id = frame_id
self.value = None self.value = None
self.t_delta = rospy.Duration(1.0 / self.rate) if self.rate != 0:
self.t_next = rospy.Time.now() + self.t_delta self.t_delta = rospy.Duration(1.0 / self.rate)
self.t_next = rospy.Time.now() + self.t_delta
def poll(self): def poll(self):
now = rospy.Time.now() now = rospy.Time.now()
if now > self.t_next: if now > self.t_next:
@ -87,20 +90,33 @@ class AnalogSensor(Sensor):
self.msg = Analog() self.msg = Analog()
self.msg.header.frame_id = self.frame_id self.msg.header.frame_id = self.frame_id
# Create the publisher
self.pub = rospy.Publisher("~sensor/" + self.name, Analog, queue_size=5) self.pub = rospy.Publisher("~sensor/" + self.name, Analog, queue_size=5)
if self.direction == "output": if self.direction == "output":
self.controller.pin_mode(self.pin, OUTPUT) self.device.pin_mode(self.pin, OUTPUT)
# Create the write service
rospy.Service('~' + self.name + '/write', AnalogSensorWrite, self.sensor_write_handler)
else: else:
self.controller.pin_mode(self.pin, INPUT) self.device.pin_mode(self.pin, INPUT)
# Create the read service
rospy.Service('~' + self.name + '/read', AnalogSensorRead, self.sensor_read_handler)
self.value = LOW self.value = LOW
def read_value(self): def read_value(self):
return self.controller.analog_read(self.pin) return self.device.analog_read(self.pin)
def write_value(self, value): def write_value(self, value):
return self.controller.analog_write(self.pin, value) return self.device.analog_write(self.pin, value)
def sensor_read_handler(self, req=None):
value = self.read_value()
return AnalogSensorReadResponse(value)
def sensor_write_handler(self, req):
self.write_value(req.value)
return AnalogSensorWriteResponse()
class AnalogFloatSensor(Sensor): class AnalogFloatSensor(Sensor):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -111,20 +127,33 @@ class AnalogFloatSensor(Sensor):
self.msg = AnalogFloat() self.msg = AnalogFloat()
self.msg.header.frame_id = self.frame_id self.msg.header.frame_id = self.frame_id
# Create the publisher
self.pub = rospy.Publisher("~sensor/" + self.name, AnalogFloat, queue_size=5) self.pub = rospy.Publisher("~sensor/" + self.name, AnalogFloat, queue_size=5)
if self.direction == "output": if self.direction == "output":
self.controller.pin_mode(self.pin, OUTPUT) self.device.pin_mode(self.pin, OUTPUT)
# Create the write service
rospy.Service('~' + self.name + '/write', AnalogFloatSensorWrite, self.sensor_write_handler)
else: else:
self.controller.pin_mode(self.pin, INPUT) self.device.pin_mode(self.pin, INPUT)
# Create the read service
rospy.Service('~' + self.name + '/read', AnalogFloatSensorRead, self.sensor_read_handler)
self.value = LOW self.value = LOW
def read_value(self): def read_value(self):
return self.controller.analog_read(self.pin) return self.device.analog_read(self.pin)
def write_value(self, value): def write_value(self, value):
return self.controller.analog_write(self.pin, value) return self.device.analog_write(self.pin, value)
def sensor_read_handler(self, req=None):
value = self.read_value()
return AnalogFloatSensorReadResponse(value)
def sensor_write_handler(self, req):
self.write_value(req.value)
return AnalogFloatSensorWriteResponse()
class DigitalSensor(Sensor): class DigitalSensor(Sensor):
@ -136,33 +165,49 @@ class DigitalSensor(Sensor):
self.msg = Digital() self.msg = Digital()
self.msg.header.frame_id = self.frame_id self.msg.header.frame_id = self.frame_id
# Create the publisher
self.pub = rospy.Publisher("~sensor/" + self.name, Digital, queue_size=5) self.pub = rospy.Publisher("~sensor/" + self.name, Digital, queue_size=5)
if self.direction == "output": if self.direction == "output":
self.controller.pin_mode(self.pin, OUTPUT) self.device.pin_mode(self.pin, OUTPUT)
# Create the write service
rospy.Service('~' + self.name + '/write', DigitalSensorWrite, self.sensor_write_handler)
else: else:
self.controller.pin_mode(self.pin, INPUT) self.device.pin_mode(self.pin, INPUT)
# Create the read service
rospy.Service('~' + self.name + '/read', DigitalSensorRead, self.sensor_read_handler)
self.value = LOW self.value = LOW
def read_value(self): def read_value(self):
return self.controller.digital_read(self.pin) return self.device.digital_read(self.pin)
def write_value(self): def write_value(self):
# Alternate HIGH/LOW when writing at a fixed rate # Alternate HIGH/LOW when writing at a fixed rate
self.value = not self.value self.value = not self.value
return self.controller.digital_write(self.pin, self.value) return self.device.digital_write(self.pin, self.value)
def sensor_read_handler(self, req=None):
value = self.read_value()
return DigitalSensorReadResponse(value)
def sensor_write_handler(self, req):
self.write_value(req.value)
return DigitalSensorWriteResponse()
class RangeSensor(Sensor): class RangeSensor(AnalogFloatSensor):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(RangeSensor, self).__init__(*args, **kwargs) super(RangeSensor, self).__init__(*args, **kwargs)
self.direction = "input"
self.message_type = MessageType.RANGE self.message_type = MessageType.RANGE
self.msg = Range() self.msg = Range()
self.msg.header.frame_id = self.frame_id self.msg.header.frame_id = self.frame_id
# Create the publisher
self.pub = rospy.Publisher("~sensor/" + self.name, Range, queue_size=5) self.pub = rospy.Publisher("~sensor/" + self.name, Range, queue_size=5)
def read_value(self): def read_value(self):
@ -192,7 +237,7 @@ class Ping(SonarSensor):
def read_value(self): def read_value(self):
# The Arduino Ping code returns the distance in centimeters # The Arduino Ping code returns the distance in centimeters
cm = self.controller.ping(self.pin) cm = self.device.ping(self.pin)
# Convert it to meters for ROS # Convert it to meters for ROS
distance = cm / 100.0 distance = cm / 100.0
@ -209,7 +254,7 @@ class GP2D12(IRSensor):
self.msg.max_range = 0.80 self.msg.max_range = 0.80
def read_value(self): def read_value(self):
value = self.controller.analog_read(self.pin) value = self.device.analog_read(self.pin)
# The GP2D12 cannot provide a meaning result closer than 3 cm. # The GP2D12 cannot provide a meaning result closer than 3 cm.
@ -237,7 +282,7 @@ class PololuMotorCurrent(AnalogFloatSensor):
def read_value(self): def read_value(self):
# From the Pololu source code # From the Pololu source code
milliamps = self.controller.analog_read(self.pin) * 34 milliamps = self.device.analog_read(self.pin) * 34
return milliamps / 1000.0 return milliamps / 1000.0
class PhidgetsVoltage(AnalogFloatSensor): class PhidgetsVoltage(AnalogFloatSensor):
@ -246,7 +291,7 @@ class PhidgetsVoltage(AnalogFloatSensor):
def read_value(self): def read_value(self):
# From the Phidgets documentation # From the Phidgets documentation
voltage = 0.06 * (self.controller.analog_read(self.pin) - 500.) voltage = 0.06 * (self.device.analog_read(self.pin) - 500.)
return voltage return voltage
class PhidgetsCurrent(AnalogFloatSensor): class PhidgetsCurrent(AnalogFloatSensor):
@ -255,7 +300,7 @@ class PhidgetsCurrent(AnalogFloatSensor):
def read_value(self): def read_value(self):
# From the Phidgets documentation for the 20 amp DC sensor # From the Phidgets documentation for the 20 amp DC sensor
current = 0.05 * (self.controller.analog_read(self.pin) - 500.) current = 0.05 * (self.device.analog_read(self.pin) - 500.)
return current return current
class MaxEZ1Sensor(SonarSensor): class MaxEZ1Sensor(SonarSensor):
@ -270,10 +315,6 @@ class MaxEZ1Sensor(SonarSensor):
self.msg.max_range = 3.0 self.msg.max_range = 3.0
def read_value(self): def read_value(self):
return self.controller.get_MaxEZ1(self.trigger_pin, self.output_pin) return self.device.get_MaxEZ1(self.trigger_pin, self.output_pin)
if __name__ == '__main__':
myController = Controller()
mySensor = SonarSensor(myController, "My Sonar", type=Type.PING, pin=0, rate=10)