-
Notifications
You must be signed in to change notification settings - Fork 113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RSDK-7152 Analog Reader API rdk changes #3946
Changes from 10 commits
0405c93
120a4cc
a1d80bf
28cef10
20ac1c5
3a723a4
c07588c
4b3f36a
ec95030
fde443f
ad58c9b
805fb53
036df4a
f825659
3829674
f63d1fe
6b85674
dc02a7d
1aea02c
97c6b63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,8 @@ type numatoBoard struct { | |
sent map[string]bool | ||
sentMu sync.Mutex | ||
workers rdkutils.StoppableWorkers | ||
|
||
productID int | ||
} | ||
|
||
func (b *numatoBoard) addToSent(msg string) { | ||
|
@@ -354,12 +356,44 @@ type analog struct { | |
pin string | ||
} | ||
|
||
func (a *analog) Read(ctx context.Context, extra map[string]interface{}) (int, error) { | ||
// analog Read returns the analog value with the range and step size in mV/bit. | ||
func (a *analog) Read(ctx context.Context, extra map[string]interface{}) (int, board.AnalogRange, error) { | ||
res, err := a.b.doSendReceive(ctx, fmt.Sprintf("adc read %s", a.pin)) | ||
if err != nil { | ||
return 0, err | ||
return 0, board.AnalogRange{}, err | ||
} | ||
reading, err := strconv.Atoi(res) | ||
if err != nil { | ||
return 0, board.AnalogRange{}, err | ||
} | ||
return strconv.Atoi(res) | ||
var max float32 | ||
var stepSize float32 | ||
switch a.b.productID { | ||
case 0x805: | ||
// 128 channel usb numato has 12 bit resolution | ||
max = 3.3 | ||
stepSize = max / 4096 | ||
case 0x802: | ||
// 32 channel usb numato has 10 bit resolution | ||
max = 3.3 | ||
stepSize = max / 1024 | ||
case 0x800: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mild preference to sort the cases in the switch statement, so it's easier to find the one you care about. |
||
// 8 and 16 pin usb versions have the same product ID but different voltage ranges | ||
// both have 10 bit resolution | ||
if a.b.pins == 8 { | ||
max = 5.0 | ||
} else if a.b.pins == 16 { | ||
max = 3.3 | ||
} | ||
stepSize = max / 1024 | ||
case 0xC05: | ||
// 1 channel usb relay module numato - 10 bit resolution | ||
max = 5.0 | ||
stepSize = max / 1024 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussion question: none of these ever change, right? Would it be simpler to calculate them once on initialization, and then just use the stored values within There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah that makes sense to me, ill do this at the start instead. |
||
default: | ||
} | ||
stepSize *= 1000 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we multiplying There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the scope doc converted the example calculation to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense! Put a comment here pointing out the right units. (apologies for the confusion where I remarked on this in the test) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...wait, so Min and Max are in volts, but StepSize is in millivolts? Put a comment in the definition of the struct explaining that. ...or rather, it seems surprising that they have different units, and perhaps the way to make it less surprising, instead of documenting the surprise, is to change the units so they're either all volts or all millivolts. I checked the scope doc, but it doesn't explicitly mention the units on any of these values (two examples mention mV and rejected alternative 3 mentions units, but I don't think this was ever laid out clearly). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah thats fair ill just keep it in volts/bit |
||
return reading, board.AnalogRange{Min: 0, Max: max, StepSize: stepSize}, nil | ||
} | ||
|
||
func (a *analog) Write(ctx context.Context, value int, extra map[string]interface{}) error { | ||
|
@@ -384,6 +418,21 @@ func connect(ctx context.Context, name resource.Name, conf *Config, logger loggi | |
path = devs[0].Path | ||
} | ||
|
||
// Find the numato board's productid | ||
products := getSerialDevices() | ||
|
||
var productID int | ||
for _, product := range products { | ||
if product.ID.Vendor != 0x2a19 { | ||
continue | ||
} | ||
productID = product.ID.Product | ||
oliviamiller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
if productID != 0x805|0x802|0x800|0x0C05 { | ||
oliviamiller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
logger.Warnf("analog range and step size is not supported for numato with product id %d", productID) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change |
||
} | ||
|
||
options := goserial.OpenOptions{ | ||
PortName: path, | ||
BaudRate: 19200, | ||
|
@@ -396,12 +445,12 @@ func connect(ctx context.Context, name resource.Name, conf *Config, logger loggi | |
if err != nil { | ||
return nil, err | ||
} | ||
|
||
b := &numatoBoard{ | ||
Named: name.AsNamed(), | ||
pins: pins, | ||
port: device, | ||
logger: logger, | ||
Named: name.AsNamed(), | ||
pins: pins, | ||
port: device, | ||
logger: logger, | ||
productID: productID, | ||
} | ||
|
||
b.analogs = map[string]*pinwrappers.AnalogSmoother{} | ||
|
@@ -419,6 +468,5 @@ func connect(ctx context.Context, name resource.Name, conf *Config, logger loggi | |
return nil, multierr.Combine(b.Close(ctx), err) | ||
} | ||
b.logger.CDebugw(ctx, "numato startup", "version", ver) | ||
|
||
return b, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
//go:build darwin | ||
|
||
package numato | ||
|
||
import "go.viam.com/utils/usb" | ||
|
||
func getSerialDevices() []usb.Description { | ||
oliviamiller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return usb.Search(usb.NewSearchFilter("AppleUSBACMData", "usbmodem"), func(vendorID, productID int) bool { | ||
return true | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
//go:build linux | ||
|
||
package numato | ||
|
||
import "go.viam.com/utils/usb" | ||
|
||
func getSerialDevices() []usb.Description { | ||
return usb.Search(usb.SearchFilter{}, func(vendorID, productID int) bool { | ||
return true | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussion question: what are the pros and cons of this approach vs. making the new struct
AnalogValue
and having all 4 fields in it (the 3 currently inAnalogRange
and the value itself)? I find the new function signature toRead
surprising, because I'd expect it to return the data we read and an error, and having a third return value is unexpected.AnalogValue
would also more closely match the protobuf structure (though matching the protobuf structure is not a goal in and of itself; it's just an unsurprising and natural thing to do).I'm not opposed to this approach, I just think it's surprising, and am wondering if there's a reason you went with this choice instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can change to returning an
AnalogValue
if you prefer it. I thought that adding a new return would be less breaking since if you still just want the bit value only you can get it and do_
for the analogrange, but still a breaking change either way so probably doesn't matter that muchThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong preference; I just think it's something to consider, in the hopes that on further thought one design is better than the other. Leave as-is if you want. 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay I changed it to one return value, prob better to just have one if theres not a great reason to have 2