I've been given a task to write an API for the AR.Drone 2.0 in R. I know it's probably not the wisest choice of language as there are good validated APIs written in Python and JS, but I took the challenge anyway.
I was doing pretty well until I had to format the AT* command string that is sent for the drone. The commands accepts arguments that can be either a quoted string, an integer, which are sent as is, or binary and float (single precision IEEE754 floating point value between -1 to 1) that must be represented as 32 bit signed integers.
I was able to do the conversion through 2 online converters, converting first from float or binary to hex, and then hex to 32 bit signed integer, so I have the basic conversion for the most common values; however, I would like to use R's built-in functions or added packages to do the conversion. Python's struct function handles this easily:
import struct
print "Float , Signed Integer"
for i in range(-10,10):
z = float(i)/10
Y = struct.unpack('i', struct.pack('f', z))[0]
print "%.1f , %d" % (z,Y)
land = 0b10001010101000000000000000000
take_off = land + 0b1000000000
print "Binary representation is simple as just using the %d format:"
print "Land code: %d, Take off code: %d" % (land, take_off)
This code will produce the following output:
Float , Signed Integer
-1.0 , -1082130432
-0.8 , -1085485875
-0.6 , -1088841318
-0.4 , -1093874483
-0.2 , -1102263091
0 , 0
0.2 , 1045220557
0.4 , 1053609165
0.6 , 1058642330
0.8 , 1061997773
1 , 1065353216
Binary representation is simple as just using the %d format
Land code: 290717696, Take off code: 290718208
Finally to my question, how to I reproduce this functionality/conversion in R?
Thanks heaps, Ido
Edit 1
I found a solution in R for the binary to Int conversion, using the base function strtoi
(land <- strtoi("10001010101000000000000000000", base=2))
[1] 290717696
(takeOff <- land + strtoi("1000000000", base=2))
[1] 290718208
Edit 2
Kept scanning the web for solutions and found a few that combined together get me my desired conversion, probably not in the most elegant way. First, I wrote a function to calculate the mantissa and the exponent:
find_mantissa <- function(f) {
i <- 1 ; rem <- abs(f) ; mantissa <- NULL
man_dec_point <- FALSE
while (length(mantissa)<24) {
temp_rem <- rem-2^-i
if (!isTRUE(man_dec_point)) {
if (temp_rem>=0) {
man_dec_point <- TRUE
mantissa <- "."
}
} else {
mantissa<-c(mantissa,ifelse(temp_rem>=0, "1", "0"))
}
rem <- ifelse(temp_rem>=0, temp_rem, rem)
i<-i+1
next
}
return(c(paste0(mantissa[-1], collapse=""),24-i))
}
find_mantissa(0.68)
[1] "01011100001010001111010" "-1"
Then I use a function that I adapted from r-bloggers (apologies for not including the link, I'm limited to 2 links only):
dec2binstr<-function(p_number) {
bin_str<-NULL
while (p_number > 0) {
digit<-p_number %% 2
p_number<-floor(p_number / 2)
bin_str<-paste0(digit,bin_str)
}
return(bin_str)
}
dec2binstr(127-1)
[1] "1111110"
Finally I wrapped it all in a function to convert the float fraction to binary and then to 32 bit signed integer by pasting together the sign bit (used always "0", but inverted the entire string for the negative binaries and added a - sign to the resulting integer), exponent bits (with left padded 0s) and mantissa. I also added another function instead of strtoi
that can't handle negative signed binaries (thanks to a solution I found here on SO).
str2num <- function(x) {
y <- as.numeric(strsplit(x, "")[[1]])
sum(y * 2^rev((seq_along(y)-1)))
}
float2Int <- function(decfloat){
bit32 <- ifelse(decfloat<0,-1, 1)
mantissa <- find_mantissa(decfloat)
exp <- dec2binstr(127+as.numeric(mantissa[2]))
long_exp <- paste0(rep("0",8-stri_length(exp)),exp)
unsigned <- paste0(long_exp,mantissa[1] )
if (decfloat<0) {
unsigned <- sapply(lapply(strsplit(unsigned, split=NULL),
function(x) ifelse(x=="0","1", "0")), paste0, collapse="")
}
binary <- paste0("0",unsigned)
return(c(binary, bit32*str2num(binary)))
}
float2Int(0.468)
[1] "00111110111011111001110110110010" "1055890866"
> float2Int(-0.468)
[1] "01000001000100000110001001001101" "-1091592781"
It's been quite a journey getting to this solution and I'm sure it's not the most efficient code implementation (and not sure it's correct for floats greater than 1 or smaller than -1), but it works for my purposes.
Any comments how to improve this code would be highly regarded.
Cheers, Ido