Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ MESSAGE(STATUS "Using CMake ${CMAKE_VERSION}")

SET(BITRL_VERSION_MAJOR 2)
SET(BITRL_VERSION_MINOR 2)
SET(BITRL_VERSION_PATCH 0)
SET(BITRL_VERSION_PATCH 2)

SET(BITRL_VERSION "${BITRL_VERSION_MAJOR}.${BITRL_VERSION_MINOR}.${BITRL_VERSION_PATCH}")
MESSAGE(STATUS "bitrllib Version ${BITRL_VERSION}")
Expand All @@ -29,14 +29,13 @@ ENDIF(COMMAND cmake_policy)
OPTION(ENABLE_TESTS OFF)
#OPTION(ENABLE_EXAMPLES OFF)
OPTION(ENABLE_WEBOTS OFF)
#OPTION(ENABLE_CHRONO OFF)

# configure packages
SET(ENABLE_EXAMPLES ON)
SET(ENABLE_CHRONO OFF)
SET(ENABLE_OPENCV ON)
SET(ENABLE_MQTT ON)
SET(ENABLE_DOCS OFF)
SET(ENABLE_DOCS ON)

# build options
SET(CMAKE_BUILD_TYPE "Release")
Expand Down Expand Up @@ -141,6 +140,7 @@ INCLUDE_DIRECTORIES(src/)
FILE(GLOB SRCS src/bitrl/*.cpp
src/bitrl/network/*.cpp
src/bitrl/sensors/*cpp
src/bitrl/sensors/messages/*cpp
src/bitrl/envs/*.cpp
src/bitrl/envs/gymnasium/*.cpp
src/bitrl/envs/gymnasium/toy_text/*.cpp
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ The following is an example how to use the
``FrozenLake`` environment from <a href="https://github.com/Farama-Foundation/Gymnasium/tree/main">Gymnasium</a>.

```

#include "bitrl/bitrl_types.h"
#include "bitrl/envs/gymnasium/toy_text/frozen_lake_env.h"
#include "bitrl/network/rest_rl_env_client.h"
Expand Down
135 changes: 118 additions & 17 deletions doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,125 @@ The following is an example how to use the
_FrozenLake_ environment from <a href="https://github.com/Farama-Foundation/Gymnasium/tree/main">Gymnasium</a>.

@code

#include "bitrl/bitrl_types.h"
#include "bitrl/envs/gymnasium/toy_text/frozen_lake_env.h"
#include "bitrl/network/rest_rl_env_client.h"

#include <any>
#include <iostream>
#include <string>
#include <unordered_map>
#include <any>

namespace example_1 {
namespace example_1
{
using namespace bitrl;

const std::string SERVER_URL = "http://0.0.0.0:8001/api";

using bitrl::envs::gymnasium::FrozenLake;
using bitrl::envs::RESTApiServerWrapper;
using bitrl::network::RESTRLEnvClient;

void test_frozen_lake(RESTRLEnvClient &server)
{

// the environment is not registered with the server
std::cout << "Is environment registered: " << server.is_env_registered(FrozenLake<4>::name)
<< std::endl;

// when the environment is created we register it with the REST client
FrozenLake<4> env(server);

// environment name can also be accessed via env.env_name()
std::cout << "Is environment registered: " << server.is_env_registered(env.env_name())
<< std::endl;
std::cout << "Environment URL: " << env.get_url() << std::endl;

// make the environment we pass both make options
// and reset options
std::unordered_map<std::string, std::any> make_ops;
make_ops.insert({"is_slippery", false});

std::unordered_map<std::string, std::any> reset_ops;
reset_ops.insert({"seed", static_cast<uint_t>(42)});
env.make("v1", make_ops, reset_ops);

// query the environemnt version
std::cout << "Environment version: " << env.version() << std::endl;

// once the env is created we can get it's id
std::cout << "Environment idx is: " << env.idx() << std::endl;

// the create flag should be true
std::cout << "Is environment created? " << env.is_created() << std::endl;

// environment should be alive on the server
std::cout << "Is environment alive? " << env.is_alive() << std::endl;

// FrozenLake is a discrete state-action env so we can
// query number of actions and states
std::cout << "Number of valid actions? " << env.n_actions() << std::endl;
std::cout << "Number of states? " << env.n_states() << std::endl;

// how many copies of this environment
auto n_copies = env.n_copies();
std::cout << "n_copies: " << n_copies << std::endl;

// reset the environment
auto time_step = env.reset();

std::cout << "Reward on reset: " << time_step.reward() << std::endl;
std::cout << "Observation on reset: " << time_step.observation() << std::endl;
std::cout << "Is terminal state: " << time_step.done() << std::endl;

void test_frozen_lake(const RESTApiServerWrapper& server) {
//...print the time_step
std::cout << time_step << std::endl;

FrozenLake<4> env(server);
std::cout << "Environment URL: " << env.get_url() << std::endl;

std::unordered_map<std::string, std::any> make_ops;
make_ops.insert({"is_slippery", false});

std::unordered_map<std::string, std::any> reset_ops;
reset_ops.insert({"seed", static_cast<uint_t>(42)});
// take an action in the environment
// 2 = RIGHT
auto new_time_step = env.step(2);
std::cout << new_time_step << std::endl;

env.make("v1", make_ops, reset_ops);
// get the dynamics of the environment for the given state and action
auto state = 0;
auto action = 1;
auto dynamics = env.p(state, action);

std::cout << "Dynamics for state=" << state << " and action=" << action << std::endl;
for (auto item : dynamics)
{
std::cout << std::get<0>(item) << std::endl;
std::cout << std::get<1>(item) << std::endl;
std::cout << std::get<2>(item) << std::endl;
std::cout << std::get<3>(item) << std::endl;
}

// discrete action environments can sample
// actions
action = env.sample_action();
std::cout << "Action sampled: " << action << std::endl;

new_time_step = env.step(action);
std::cout << new_time_step << std::endl;

// close the environment
env.close();
}

} // namespace example_1

int main() {
RESTApiServerWrapper server(SERVER_URL, true);
example_1::test_frozen_lake(server);
return 0;
int main()
{
using namespace example_1;
RESTRLEnvClient server(SERVER_URL, false);

std::cout << "Testing FrozenLake..." << std::endl;
example_1::test_frozen_lake(server);
std::cout << "====================" << std::endl;

return 0;
}

@endcode


Expand All @@ -55,6 +140,7 @@ _bitrl_ has a number of dependencies assumed to be installed under usual destina
- Blas
- OpenCV
- PahoMqttCpp
- Doxygen

## Installation

Expand All @@ -66,5 +152,20 @@ cmake -DCMAKE_INSTALL_PREFIX=/path/where/bitrl/should/be/installed/to ..
make install -j4
@endcode

## Build the documentation

You can build the documentation locally. In this case, Doxygen should be installed on your machine.

@code
cd build
cmake -DCMAKE_INSTALL_PREFIX=/path/where/bitrl/should/be/installed/to ..
make install -j4
make doc
@endcode


The documentation will be installed under _docs_ under the project's source directory


## Examples

1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ADD_SUBDIRECTORY(arduino_wifi)

IF(BITRL_MQTT)
ADD_SUBDIRECTORY(mqtt_exe_1)
ADD_SUBDIRECTORY(mqtt_exe_3)

IF(BITRL_OPENCV)
ADD_SUBDIRECTORY(mqtt_exe_2)
Expand Down
2 changes: 1 addition & 1 deletion examples/mqtt_exe_1/mqtt_example_1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "bitrl/network/mqtt_subscriber.h"
#include "bitrl/sensors/ekf_sensor_fusion.h"
#include "bitrl/sensors/sensor_type_enum.h"
#include "bitrl/sensors/vector_message.h"
#include "../../src/bitrl/sensors/messages/vector_message.h"
#include "bitrl/utils/unit_converter.h"

#include <chrono>
Expand Down
4 changes: 2 additions & 2 deletions examples/mqtt_exe_2/mqtt_example_2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#ifdef BITRL_MQTT

#include "bitrl/network/mqtt_subscriber.h"
#include "bitrl/sensors/camera.h"
#include "../../src/bitrl/sensors/messages/camera.h"

#include <chrono>
#include <iostream>
Expand All @@ -27,7 +27,7 @@ int main()

if (message.has_value())
{
auto reading = sensors::CameraReading::parse(message.value());
auto reading = sensors::CameraMessage::parse(message.value());

if (reading.has_value())
{
Expand Down
23 changes: 23 additions & 0 deletions examples/mqtt_exe_3/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)

SET(EXECUTABLE mqtt_example_3)
SET(SOURCE ${EXECUTABLE}.cpp)

ADD_EXECUTABLE(${EXECUTABLE} ${SOURCE})
TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE bitrllib)

IF(BITRL_CHRONO)
TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE ${BITRL_CHRONO_TARGETS})
ENDIF ()

IF(BITRL_WEBOTS)
TARGET_LINK_LIBRARIES(${EXECUTABLE} CppController)
ENDIF()

IF(BITRL_MQTT)
TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE bitrllib paho-mqttpp3 paho-mqtt3as)
ENDIF ()

IF(BITRL_OPENCV)
TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE ${OpenCV_LIBS})
ENDIF ()
30 changes: 30 additions & 0 deletions examples/mqtt_exe_3/feed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import time
import datetime
import json
import paho.mqtt.client as mqtt

BROKER = "localhost"
PORT = 1883
ULTRASOUND_TOPIC = "ultrasound"

def main():
# Initialize MQTT
client = mqtt.Client()
client.connect(BROKER, PORT, 60)

distance = 0.0
try:
while True:
z_str = json.dumps({"distance": distance, "unit":"cm",
"timestamp": str(datetime.datetime.now(datetime.UTC))}
)
distance += 0.01
client.publish(topic=ULTRASOUND_TOPIC, payload=z_str)
time.sleep(2.0)

except Exception:
print("Stopping...")


if __name__ == "__main__":
main()
56 changes: 56 additions & 0 deletions examples/mqtt_exe_3/mqtt_example_3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "bitrl/bitrl_config.h"
#ifdef BITRL_MQTT

#include "bitrl/network/mqtt_subscriber.h"
#include "bitrl/sensors/messages/ultrasound.h"

#include <chrono>
#include <iostream>
#include <thread>
#include <iomanip>

int main()
{

using namespace bitrl;

network::MqttSubscriber ultrasound_subscriber("tcp://localhost:1883", "ultrasound");
ultrasound_subscriber.connect();

while (true)
{
auto message = ultrasound_subscriber.poll(std::chrono::milliseconds(3000));

if (message.has_value())
{
auto reading = sensors::UltrasoundMessage::parse(message.value());
if (reading.has_value())
{

auto read_message = reading.value();

std::time_t t = std::chrono::system_clock::to_time_t(read_message.source_timestamp);
std::tm tm = *std::localtime(&t);
std::cout<<"Distance received: "<<read_message.distance<<std::endl;
std::cout<<"Units received: "<<read_message.unit_str<<std::endl;
std::cout<<"Generated at: "<< std::put_time(&tm, "%Y-%m-%d %H:%M:%S")<<std::endl;
}

}

std::this_thread::sleep_for(std::chrono::microseconds(200));
}

return 0;
}

#else
#include <iostream>
int main()
{
std::cerr << "This example requires MQTT and OpenCV to be enable. "
"Reconfigure bitrl with ENABLE_MQTT=ON and ENABLE_OPENCV=ON"
<< std::endl;
return 1;
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
//

#include "camera.h"
#include "bitrl/sensors/camera.h"
#include "camera.h"
#include <boost/beast/core/detail/base64.hpp>
#include <vector>
namespace bitrl
{
namespace sensors
{
std::optional<CameraReading> CameraReading::parse(const std::string &base64jpeg)
std::optional<CameraMessage> CameraMessage::parse(const std::string &base64jpeg)
{
// Decode base64
auto tmp = std::string(base64jpeg);
Expand All @@ -32,7 +32,7 @@ std::optional<CameraReading> CameraReading::parse(const std::string &base64jpeg)
return std::nullopt;
}

CameraReading reading;
CameraMessage reading;
reading.image = image;
return reading;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ namespace bitrl
{
namespace sensors
{
struct CameraReading
struct CameraMessage
{
cv::Mat image;
static std::optional<CameraReading> parse(const std::string &base64jpeg);
static std::optional<CameraMessage> parse(const std::string &base64jpeg);
};
} // namespace sensors
} // namespace bitrl
Expand Down
Loading