6

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

Community
  • 1
  • 1
IsoBar
  • 405
  • 3
  • 10
  • Welcome to SO! You can always leave a link as plain text, and someone will edit it to a hyperlink. – tonytonov Sep 21 '15 at 12:59
  • I'm wondering if careful use of `writeBin` and `readBin` will do this task. See, for some help but not a solution, https://stackoverflow.com/questions/39461349/converting-hex-format-to-float-numbers-in-r – Carl Witthoft Oct 27 '20 at 11:16

0 Answers0