packages feed

HsWebots-0.1.1.2: test/Webots/CameraSpec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
module Webots.CameraSpec (main, spec) where

import GHC.Generics
import Data.Int
import Data.VRML
import Data.List
import Test.Hspec
import System.Process
import System.Environment

import Webots.Supervisor
import Webots.Robot
import Webots.Driver
import Webots.Camera
import Webots.Types

import qualified Codec.Picture as I

main :: IO ()
main = do
  args <- getArgs
  case args of
    "controller":_ -> do
      wbu_driver_init
      wbu_driver_set_cruising_speed 10
      wbu_driver_set_steering_angle 0
      camera <- wb_robot_get_device "camera"
      wb_camera_enable camera 50
      camera_width <- wb_camera_get_width camera
      camera_height <- wb_camera_get_height camera
      camera_fov <- wb_camera_get_fov camera
      wb_camera_recognition_enable camera 25
      let loop :: Int -> (Int -> IO ()) -> IO ()
          loop t func = do
            i <- wbu_driver_step
            whenM (i /= -1) $ do
              func t
              loop (t+1) func
      loop 0 $ \t -> do
        i <- wb_robot_get_basic_time_step
        whenM (t==10) $ do
          img <- wb_camera_get_image camera
          I.writePng "pic.png" img
          print "Took a picture"
        return ()
      wbu_driver_cleanup
      
    "supervisor":_ -> do
      withWbRobot $ \time_step -> do
        let loop :: Int -> (Int -> IO ()) -> IO ()
            loop t func = do
              i <- wb_robot_step time_step
              whenM (i /= -1) $ do
                func t
                if t > 100
                then wb_supervisor_simulation_quit(1)
                else loop (t+1) func
        loop 0 $ \i -> do
          return ()


data WorldInfo = WorldInfo
  { northDirection      :: (Float,Float,Float)
  , lineScale           :: Float
  } deriving (Generic,Show,Eq,ToNode)

data Viewpoint = Viewpoint
  { orientation :: (Float,Float,Float,Float)
  , position    :: (Float,Float,Float)
  , near        :: Float
  } deriving (Generic,Show,Eq,ToNode)

data Floor = Floor
  { translation :: (Float,Float,Float)
  , size        :: (Float,Float)
  } deriving (Generic,Show,Eq,ToNode)

data Recognition = Recognition
  deriving (Generic,Show,Eq,ToNode)

data Camera = Camera
  { width :: Int32
  , height :: Int32
  , recognition :: Maybe Recognition
  } deriving (Generic,Show,Eq,ToNode)

data BmwX5 = BmwX5
  { translation :: (Float,Float,Float)
  , rotation    :: (Float,Float,Float,Float)
  , name        :: String
  , color       :: Color
  , controller  :: String
  , controllerArgs  :: String
  , sensorsSlotFront :: [Node]
  } deriving (Generic,Show,Eq,ToNode)

data Robot = Robot
  { controller :: String
  , controllerArgs  :: String
  , supervisor :: Bool
  } deriving (Generic,Show,Eq,ToNode)

data TexturedBackground = TexturedBackground
  deriving (Generic,Show,Eq,ToNode)
data TexturedBackgroundLight = TexturedBackgroundLight
  deriving (Generic,Show,Eq,ToNode)

genWbt :: String -> IO String
genWbt file = do
  let wbtfile = "test/worlds/test.wbt"
      world =
        VRML
        { version    = "VRML_SIM R2020b utf8"
        , statements =
          [ toNode $ WorldInfo
                     { northDirection      = (0,0,1.0)
                     , lineScale           = 0
                     }
          , toNode $ Viewpoint
                     { orientation = (-1,0,0,1.57)
                     , position    = (0,171.0768261655035,0.07181023813347440)
                     , near        = 3.0
                     }
          , toNode $ Floor
                     { translation = (0.0, -1.0e-3, 0.0)
                     , size       = (1000.0, 1000.0)
                     }
          , toNode TexturedBackground
          , toNode TexturedBackgroundLight
          , toNode $ Robot
                     { controller = "test"
                     , controllerArgs = "../../" ++ file ++ " supervisor"
                     , supervisor = True
                     }
          , toNode $ BmwX5
                     { translation = (0,0,0)
                     , rotation    = (0,0,0,0)
                     , name        = "car"
                     , color       = Color (1,0,0)
                     , controller  = "test"
                     , controllerArgs  = "../../" ++ file ++ " controller"
                     , sensorsSlotFront = [
                         toNode $ Camera
                         { width = 320
                         , height = 240
                         , recognition = Just Recognition
                         }
                         ]
                     }
          ]
        }
  writeVRML wbtfile world
  return wbtfile

run wbt = do
  readProcessWithExitCode
    "webots"
    [ "--mode=fast"
    , "--batch"
    , "--minimize"
    , "--stdout"
    , "--stderr"
    , wbt
    ]
    ""

spec :: Spec
spec = do
  describe "Camera" $ do
    it "capture something" $ do
      wbt <- genWbt "Webots/CameraSpec.hs"
      (code,out,err) <- run wbt
      let outlines = map read $ map (drop 7) $ filter (isPrefixOf "[test] ") $ lines out
      outlines `shouldBe` ["Took a picture"]