acowley / roshask

Haskell client library for the ROS robotics framework.
BSD 3-Clause "New" or "Revised" License
107 stars 18 forks source link

Arrows on topics; Subscribe, Advertise and Connect type classes. #36

Closed akru closed 8 years ago

akru commented 9 years ago

Arrows

The arrow(https://www.haskell.org/arrows) on topic is an alternative to monadic Ros.Topic interface.

Arrows says in terms of message changing, e.g.

vectorLen :: TopicArrow m Vector3 Float64
vectorLen = arr (\v -> Float64 $ (v ^. x)^2 + (v ^. y)^2 + (v ^. z)^2)

TopicArrow has type:

newtype TopicArrow m a b = TopicArrow
  { runTopicArrow :: Topic m a -> Topic m b }

A lot of standart topic operations can be written in arrow terms, e.g.

import qualified Ros.Topic.Util as U

topicRate :: (Functor m, MonadIO m) => Int -> TopicArrow m a a
topicRate = TopicArrow . U.topicRate

Subscribe, Advertise and Connect type classes

The Subscribe type class is an abstraction of subscribed types, and have definition:

class Subscribe s where
  -- |Subscribe to given topic name
  subscribe :: (RosBinary a, MsgInfo a, Typeable a)
             => TopicName -> Node (s a)

The Advertise type class is an abstraction of advertised types, and have definition:

class Advertise a where
  -- |Advertise topic messages with a per-client
  -- transmit buffer of the specified size.
  advertiseBuffered :: (RosBinary b, MsgInfo b, Typeable b)
              => Int -> TopicName -> a b -> Node ()
  -- |Advertise a 'Topic' publishing a stream of values produced in
  -- the 'IO' monad. Fixed buffer size version of @advertiseBuffered@.
  advertise :: (RosBinary b, MsgInfo b, Typeable b)
              => TopicName -> a b -> Node ()
  advertise = advertiseBuffered 1

The Connect type class is a combination of Subscribe and Advertise actions with given arrow between messages of subscribed and advertised types.

class Arrow a => Connect a where
  connect :: (RosBinary b, MsgInfo b, Typeable b,
        RosBinary c, MsgInfo c, Typeable c)
        => TopicName -> TopicName -> a b c -> Node ()

This PR contains Subscribe/Advertise instances for Topic IO and TopicArrow IO () types, and Connect instances for (->) and TopicArrow IO.

Example:

main = runNode "n" $ connect "a" "b" vectorLen
acowley commented 9 years ago

I really like the way connect looks, but I'm not yet sure about the TopicArrow part. The example looks a lot like the Applicative interface. Do you have in mind some examples where the Arrow interface really wins?

akru commented 8 years ago

It's not the same as Applicative because TopicArrow:

For example

refModel :: TopicArrow IO Double Double                                                             
{- |The DC motor with reductor model                                                 
 - u - control voltage                                                                             
 - y - current position                                                                             
 -                                                                                                  
 - u      +---+   +-------+    +----------+   y                                                                
 - ------>| K |-->| Motor |--->| Reductor |---->                                                                 
 -        +---+   +-------+    +----------+                                                                    
 -}                                                                                                                                        
refModel k = gain k >>> dcmotor >>> reductor

reductor :: Arrow a => a Double Double
reductor = gear 15 >>> gear 5 >>> gear 24

dcmotor :: TopicArrow IO Double Double                                                
dcmotor = stateSpace ss_dcm                                                                         
  where -- State-space dc motor model                                                               
    ss_dcm = c2d dt $ SS tA tB tC tX
    tX = fromLists [[0],[0],[0]]                                                                
    tA = fromLists [[0,1,0],[0,-b/j, k/j],[0,-k/l,-r/l]]                                        
    tB = fromLists [[0],[0],[1/l]]                                                              
    tC = fromLists [[1,0,0]]                                                                    
    -- DC motor physics constants                                                               
    b  = 0.1  -- motor viscous friction constant                                                
    j  = 0.01 -- moment of inertia of the rotor                                                 
    k  = 0.01 -- motor torque constant                                                          
    l  = 0.5  -- electric inductance                                                            
    r  = 1    -- electric resistance 
acowley commented 8 years ago

Alright, I'm sold. Thank you for both the effort on the coding and the patience with the PR!