From 191174d5881a41406ef7d2cfe6dd885417aaf6d7 Mon Sep 17 00:00:00 2001 From: pockerman Date: Sat, 7 Mar 2026 17:06:40 +0000 Subject: [PATCH 1/4] Refactor example 12 (#176) --- examples/example_6/CMakeLists.txt | 25 ++++++++ examples/example_6/config.json | 9 +++ examples/example_6/example_6.cpp | 97 +++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 examples/example_6/CMakeLists.txt create mode 100644 examples/example_6/config.json create mode 100644 examples/example_6/example_6.cpp diff --git a/examples/example_6/CMakeLists.txt b/examples/example_6/CMakeLists.txt new file mode 100644 index 00000000..2ee045d3 --- /dev/null +++ b/examples/example_6/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.6 FATAL_ERROR) + +SET(EXECUTABLE example_6) +SET(SOURCE ${EXECUTABLE}.cpp) + +ADD_EXECUTABLE(${EXECUTABLE} ${SOURCE}) + +TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE bitrllib pthread boost_log) + +IF(ENABLE_CHRONO) + TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE Chrono::Chrono_core) +ENDIF () + + +IF(BITRL_WEBOTS) + TARGET_LINK_LIBRARIES(${EXECUTABLE} CppController) +ENDIF() + +IF(BITRL_MQTT) + TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE paho-mqttpp3 paho-mqtt3as) +ENDIF () + +IF(BITRL_OPENCV) + TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE ${OpenCV_LIBS}) +ENDIF () diff --git a/examples/example_6/config.json b/examples/example_6/config.json new file mode 100644 index 00000000..1df7eb2e --- /dev/null +++ b/examples/example_6/config.json @@ -0,0 +1,9 @@ +{ +"experiment_dict": "intro_example_2_experiments/", +"experiment_id": "1", +"input_size": 1, +"output_size": 1, +"num_epochs": 60, +"lr":0.001, +"log_path":"/home/alex/qi3/cuberl/examples/intro/intro_example_2/tsb_log" +} diff --git a/examples/example_6/example_6.cpp b/examples/example_6/example_6.cpp new file mode 100644 index 00000000..d46beb48 --- /dev/null +++ b/examples/example_6/example_6.cpp @@ -0,0 +1,97 @@ +/** + * This example utilises the ```TensorboardServer``` class to log values of interest when running + * an experiment. We can monitor the experimet using tensorboard. The ```TensorboardServer``` class + *is a simple wrapper that exposes three functions + * + * - ```add_scalar``` + * - ```add_scalars``` + * - ```add_text``` + * + * We will use ```add_scalar``` and ```add_text```. In order to run this example, fire up the + *server using the ```torchboard_server/start_uvicorn.sh```. The server listens at port 8002. You + *can change this however you want just make sure that the port is not used and also update the + * variable ```TORCH_SERVER_HOST``` in the code below accordingly. Note that the implementation + *uses SummaryWriter + *class. Thus you will need to have PyTorch installed on the machine that you run the server. + */ + +#include "bitrl/bitrl_types.h" +#include "bitrl/utils/io/json_file_reader.h" +#include "bitrl/network/tensorboard_server.h" + +#include +#include +#include +#include + +namespace example_12 +{ +using namespace bitrl; +using utils::io::JSONFileReader; +using network::TensorboardServer; + +namespace fs = std::filesystem; +const std::string CONFIG = "config.json"; + +} // namespace example_12 + +int main() +{ + + using namespace example_12; + + try + { + + // load the json configuration + JSONFileReader json_reader(CONFIG); + json_reader.open(); + + auto experiment_dict = json_reader.template get_value("experiment_dict"); + auto experiment_id = json_reader.template get_value("experiment_id"); + + std::cout << "Experiment directory: " << experiment_dict << std::endl; + std::cout << "Experiment id: " << experiment_id << std::endl << std::endl; + + const fs::path EXPERIMENT_DIR_PATH = experiment_dict + experiment_id; + + // the first thing we want to do when monitoring experiments + // is to create a directory where all data will reside + std::filesystem::create_directories(experiment_dict + experiment_id); + + const auto input_size = json_reader.template get_value("input_size"); + const auto output_size = json_reader.template get_value("output_size"); + const auto num_epochs = json_reader.template get_value("num_epochs"); + const auto learning_rate = json_reader.template get_value("lr"); + auto log_path = json_reader.template get_value("log_path"); + + // log the hyperparameters + std::cout << "Input size: " << input_size << std::endl; + std::cout << "Output size: " << output_size << std::endl; + std::cout << "Max epochs: " << num_epochs << std::endl; + std::cout << "Learning rate: " << learning_rate << std::endl; + + TensorboardServer logger("http://0.0.0.0:8002"); + + std::cout << "Logging results at " << logger.get_log_dir_path() << std::endl; + logger.init(log_path); + + logger.add_scalar("lr", learning_rate); + logger.add_scalar("seed", 42); + logger.add_scalar("num_epochs", num_epochs); + logger.add_text("optimizer", "torch::optim::SGD"); + logger.close(); + } + catch (std::exception &e) + { + std::cout << e.what() << std::endl; + } + catch (...) + { + std::cout << "Unknown exception occured" << std::endl; + } + + return 0; +} From ec9229fea772fd287000f2c1686ff93da6b2f9e3 Mon Sep 17 00:00:00 2001 From: pockerman Date: Sat, 7 Mar 2026 17:13:58 +0000 Subject: [PATCH 2/4] Update examples and documentation (#176) --- config.h.in | 2 +- examples/CMakeLists.txt | 1 + examples/example_11/example_11.md | 17 +- examples/example_13/example_13.cpp | 277 +++++++++++++++++++++-------- 4 files changed, 211 insertions(+), 86 deletions(-) diff --git a/config.h.in b/config.h.in index aaf7db38..140ce9d0 100755 --- a/config.h.in +++ b/config.h.in @@ -16,7 +16,7 @@ /*Use Webots*/ #cmakedefine BITRL_WEBOTS -/*Use Chron*/ +/*Use Chrono*/ #cmakedefine BITRL_CHRONO /*Use OpenCV*/ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 3b2e2b93..79de4181 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -29,6 +29,7 @@ ADD_SUBDIRECTORY(example_2) ADD_SUBDIRECTORY(example_3) ADD_SUBDIRECTORY(example_4) ADD_SUBDIRECTORY(example_5) +ADD_SUBDIRECTORY(example_6) ADD_SUBDIRECTORY(example_7) ADD_SUBDIRECTORY(example_8) ADD_SUBDIRECTORY(example_9) diff --git a/examples/example_11/example_11.md b/examples/example_11/example_11.md index 74d094e2..e5087313 100644 --- a/examples/example_11/example_11.md +++ b/examples/example_11/example_11.md @@ -3,14 +3,14 @@ The Chrono library is the main library that _bitrl_ is using in order to simulate robots and create environments for reinforcement learning agents. As such, knowing your way around Chrono is essential. However, Chrono is a relatively large library with many components and therefore not necessarily easy -to grasp. In a series of examples, we will see main components of the library that _bitrl_ utilizes. +to grasp. In a series of examples, we will see the main components of the library that _bitrl_ utilizes. Note that you should have compiled Chrono with Irrlicht support in order to be able to run this example. The main interface for creating rigid bodies in Chrono is the ChBody class. You can also find this Rigid Bodies helpful. -_ChBody_ is an abstract class, and therefore we cannot instantiate it directly. Chrono provides various classes however we can +_ChBody_ is an abstract class, and therefore we cannot instantiate it directly. Chrono provides various classes however, we can immediately use. The one we will use in this example is the _ChBodyEasyBox_ class. This is defined in the _chrono/physics/ChBodyEasy.h_ header. -Let's first create a box and try to visualize it. Below is the function that constructs a box. +Let's first create a box and try to visualize it. The function below does exactly that. @code{.cpp} std::shared_ptr create_box(real_t xlength, real_t ylength, real_t zlength, @@ -30,12 +30,14 @@ real_t density, bool create_visualization) @endcode -The following is a helper for setting up the visualization +The following is a helper for setting up the visualization. We need to build Chrono with Irrlicht support in order to be able to +use it as a visualization engine. You can find more information about the +visualisation system in Chrono at Visualization System. @code{.cpp} void prepare_visualization(chrono::irrlicht::ChVisualSystemIrrlicht& visual) { -visual.SetWindowSize(WINDOW_WIDTH, WINDOW_WIDTH); //WINDOW_HEIGHT); +visual.SetWindowSize(WINDOW_WIDTH, WINDOW_WIDTH); visual.SetWindowTitle(WINDOW_TITLE); visual.Initialize(); @@ -47,8 +49,9 @@ visual.Initialize(); } @endcode -Below is the main function: - +Below is the main driver for this example. +It creates a box and attaches it to a _ChSystem_ (see Simulation system for more information). +It also sets up a minimal visualization obejct _ChVisualSystemIrrlicht_ for the simulation and finally runs the simulation loop. @code{.cpp} int main() { diff --git a/examples/example_13/example_13.cpp b/examples/example_13/example_13.cpp index c126c5d0..ed455bf0 100644 --- a/examples/example_13/example_13.cpp +++ b/examples/example_13/example_13.cpp @@ -11,101 +11,222 @@ #endif #include "bitrl/bitrl_consts.h" +#include "bitrl/rigid_bodies/chrono_robots/diff_drive_robot.h" + #include "chrono/core/ChRealtimeStep.h" #include "chrono/physics/ChSystemNSC.h" +#include #include +#include "chrono/assets/ChVisualSystem.h" #include -#include "bitrl/rigid_bodies/chrono_robots/diff_drive_robot.h" +// #include "chrono/assets/ChColorAsset.h" +// #include "chrono/assets/ChLineShape.h" + #include #include -namespace example_13 -{ -using namespace bitrl; -using namespace chrono::irrlicht; - -// constants we will be using further below -const uint_t WINDOW_HEIGHT = 800; -const uint_t WINDOW_WIDTH = 1024; -const real_t DT = 0.01; -const real_t SIM_TIME = 5.0; -const std::string WINDOW_TITLE( "Example 13"); - -void prepare_visualization(chrono::irrlicht::ChVisualSystemIrrlicht& visual) -{ - visual.SetWindowSize(WINDOW_WIDTH, WINDOW_WIDTH); //WINDOW_HEIGHT); - visual.SetWindowTitle(WINDOW_TITLE); - visual.Initialize(); - - visual.AddLogo(); - visual.AddSkyBox(); - visual.AddCamera({0, -2, 1}, {0, 0, 0}); - visual.AddTypicalLights(); - visual.BindAll(); -} - - +#include "chrono/physics/ChSystemNSC.h" +#include "chrono/physics/ChBodyEasy.h" +#include "chrono/physics/ChLinkMotorRotationSpeed.h" +#include "chrono/functions/ChFunctionConst.h" +#include "chrono_irrlicht/ChVisualSystemIrrlicht.h" -} // namespace example_13 +using namespace chrono; +using namespace chrono::irrlicht; -int main() +namespace { - using namespace example_13; - chrono::ChSystemNSC sys; - sys.SetGravitationalAcceleration(chrono::ChVector3d(0, 0, -9.81)); - - sys.SetCollisionSystemType(chrono::ChCollisionSystem::Type::BULLET); - chrono::ChCollisionModel::SetDefaultSuggestedEnvelope(0.0025); - chrono::ChCollisionModel::SetDefaultSuggestedMargin(0.0025); - - auto floor_mat = chrono_types::make_shared(); - auto mfloor = chrono_types::make_shared(20, 20, 1, 1000, true, true, floor_mat); - mfloor->SetPos(chrono::ChVector3d(0, 0, -1)); - mfloor->SetFixed(true); - mfloor->GetVisualShape(0)->SetTexture(chrono::GetChronoDataFile("textures/concrete.jpg")); - sys.Add(mfloor); +void draw_world_axes(chrono::irrlicht::ChVisualSystemIrrlicht& vis, + double scale = 1.0) { + auto* driver = vis.GetVideoDriver(); + + // X axis (red) + driver->draw3DLine( + {0, 0, 0}, + {static_cast(scale), 0, 0}, + irr::video::SColor(255, 255, 0, 0)); + + // Y axis (green) + driver->draw3DLine( + {0, 0, 0}, + {0, static_cast(scale), 0}, + irr::video::SColor(255, 0, 255, 0)); + + // Z axis (blue) + driver->draw3DLine( + {0, 0, 0}, + {0, 0, static_cast(scale)}, + irr::video::SColor(255, 0, 0, 255)); +} +} - bitrl::rb::bitrl_chrono::CHRONO_DiffDriveRobot robot(sys, - chrono::ChVector3d(0, 0, -0.45), chrono::QUNIT); +int main() { + + // ----------------------------- + // Create Chrono physical system + // ----------------------------- + ChSystemNSC system; + //ChSystemSMC system; + system.SetGravitationalAcceleration(chrono::ChVector3d(0,0,-9.81)); + system.SetCollisionSystemType(chrono::ChCollisionSystem::Type::BULLET); + + // ----------------------------- + // Create ground + // ----------------------------- + auto material = chrono_types::make_shared(); + + material->SetFriction(0.8f); + material->SetRestitution(0.1f); + auto floor = chrono_types::make_shared( + 5, 5, 0.1, // size + 1000, // density + true, true, material); // visual + collision + + floor->SetPos(chrono::ChVector3d(0,0,-0.05)); + floor->SetFixed(true); + floor->EnableCollision(true); + + system.Add(floor); + + // ----------------------------- + // Robot chassis + // ----------------------------- + double wheel_radius = 0.1; + double chassis_height = 0.1; + auto chassis = chrono_types::make_shared( + 0.5, 0.3, chassis_height, + 1000, + true, true, material); + + // 0,0,wheel_radius + chassis_height/2.0 + //chrono::ChVector3d pos(0,0,0.2); + chrono::ChVector3d pos(0.0, 0.0, wheel_radius + chassis_height/2.0 + 0.01); + chassis->SetPos(pos); + + chrono::ChVector3d vel(0.5, 0.0, 0.0); + chassis->SetPosDt(vel); + system.Add(chassis); + + // ----------------------------- + // Wheels + // ----------------------------- + + double wheel_width = 0.05; + //auto material = chrono_types::make_shared(); + auto left_wheel = chrono_types::make_shared( + chrono::ChAxis::Y, + wheel_radius, + wheel_width, + 1000, + true, true, material); + + auto right_wheel = chrono_types::make_shared( + chrono::ChAxis::Y, + wheel_radius, + wheel_width, + 1000, + true, true, material); + + left_wheel->SetPos(chrono::ChVector3d(0, 0.2, 0.1)); + right_wheel->SetPos(chrono::ChVector3d(0,-0.2, 0.1)); + + system.Add(left_wheel); + system.Add(right_wheel); + + // ----------------------------- + // Motors (differential drive) + // ----------------------------- + auto motor_left = chrono_types::make_shared(); + auto motor_right = chrono_types::make_shared(); + + chrono::ChQuaternion<> rot = chrono::QuatFromAngleX(chrono::CH_PI_2); + motor_left->Initialize( + left_wheel, + chassis, + chrono::ChFrame<>(chrono::ChVector3d(0,0.2,0.1), rot) + ); + + motor_right->Initialize( + right_wheel, + chassis, + chrono::ChFrame<>(chrono::ChVector3d(0,-0.2,0.1), rot) + ); + + system.Add(motor_left); + system.Add(motor_right); + + // ----------------------------- + // Wheel speeds + // ----------------------------- + auto speed_left = chrono_types::make_shared(-4.5); + auto speed_right = chrono_types::make_shared(-4.5); + + motor_left->SetSpeedFunction(speed_left); + motor_right->SetSpeedFunction(speed_right); + + double caster_radius = 0.05; + auto caster = chrono_types::make_shared( + caster_radius, // radius + 1000, // density + true, // visualization + true, // collision + material); + + caster->SetPos(chrono::ChVector3d(0.2, 0, 0.05)); + caster->EnableCollision(true); + + system.Add(caster); + + auto caster_joint = chrono_types::make_shared(); + + caster_joint->Initialize( + caster, + chassis, + ChFrame<>(chrono::ChVector3d(-0.25, 0, caster_radius), QUNIT)); + + system.Add(caster_joint); + + floor->EnableCollision(true); + chassis->EnableCollision(true); + left_wheel->EnableCollision(true); + right_wheel->EnableCollision(true); + + // ----------------------------- + // Irrlicht visualization + // ----------------------------- + chrono::irrlicht::ChVisualSystemIrrlicht vis; + + vis.AttachSystem(&system); + + vis.SetWindowSize(1280,720); + vis.SetWindowTitle("Chrono Differential Drive Robot"); + + vis.Initialize(); + vis.AddSkyBox(); + vis.AddLogo(); + vis.AddSkyBox(); + vis.AddCamera({0, -2, 1}, {0, 0, 0}); + vis.AddTypicalLights(); + vis.BindAll(); + // 1 meter length + // ----------------------------- + // Simulation loop + // ----------------------------- + double step_size = 0.002; - robot.init(); - robot.set_motor_speed(bitrl::consts::maths::PI, 0); - robot.set_motor_speed(bitrl::consts::maths::PI, 1); + while (vis.Run()) { - chrono::irrlicht::ChVisualSystemIrrlicht visual; - prepare_visualization(visual); - visual.AttachSystem(&sys); + vis.BeginScene(); + vis.Render(); + draw_world_axes(vis, 2.0); - // Simulation loop + auto position = chassis -> GetPos(); + std::cout << position <drawAll(); - - // ADVANCE SYSTEM STATE BY ONE STEP - sys.DoStepDynamics(DT); - - // Enforce soft real-time - realtime_timer.Spin(DT); - - // Irrlicht must finish drawing the frame - visual.EndScene(); + system.DoStepDynamics(step_size); + vis.EndScene(); } return 0; From 6d785578a8fb9a80f05d2de9503879ea39d45469 Mon Sep 17 00:00:00 2001 From: pockerman Date: Sat, 7 Mar 2026 17:14:39 +0000 Subject: [PATCH 3/4] Add documentation for example_12 (#176) --- examples/example_12/example_12.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 examples/example_12/example_12.md diff --git a/examples/example_12/example_12.md b/examples/example_12/example_12.md new file mode 100644 index 00000000..06a2eac0 --- /dev/null +++ b/examples/example_12/example_12.md @@ -0,0 +1,13 @@ +\page bitrl_example_12 BitRL Example 12 A rigid body simulation with Chrono + +Example \ref bitrl_example_11 discussed _ChBody_. Specifically, how to create a _ChBodyEasyBox_. +Understanding rigid bodies is fundamental to robotics and further examples in this series will dive deeper into +this subject. In this example we want to create a simple simulation of a differential drive robot. +According to wikipedia: + +_A differential wheeled robot is a mobile robot whose movement is based on two separately +driven wheels placed on either side of the robot body. It can thus change its direction by varying the +relative rate of rotation of its wheels and hence does not require an additional steering motion. +Robots with such a drive typically have one or more caster wheels to prevent the vehicle from tilting._ + +Thus we will build a robot with two motorised wheels and one passive caster wheel useful for balancing the robot. From c82e9e49dca4b8eeb559ac44f2a2c7adcde41811 Mon Sep 17 00:00:00 2001 From: pockerman Date: Sun, 8 Mar 2026 11:18:41 +0000 Subject: [PATCH 4/4] Fix example 12 (#176) --- examples/example_12/CMakeLists.txt | 2 +- examples/example_12/example_12.cpp | 278 +++++++++++++++++++++-------- examples/example_12/example_12.md | 262 ++++++++++++++++++++++++++- src/bitrl/bitrl_consts.h | 2 +- 4 files changed, 471 insertions(+), 73 deletions(-) diff --git a/examples/example_12/CMakeLists.txt b/examples/example_12/CMakeLists.txt index 6e766313..14468338 100644 --- a/examples/example_12/CMakeLists.txt +++ b/examples/example_12/CMakeLists.txt @@ -8,7 +8,7 @@ ADD_EXECUTABLE(${EXECUTABLE} ${SOURCE}) TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE bitrllib pthread boost_log) IF(ENABLE_CHRONO) - TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE Chrono::Chrono_core) + TARGET_LINK_LIBRARIES(${EXECUTABLE} PRIVATE Chrono::Chrono_core Chrono::Chrono_irrlicht) ENDIF () diff --git a/examples/example_12/example_12.cpp b/examples/example_12/example_12.cpp index d46beb48..8c8c20e5 100644 --- a/examples/example_12/example_12.cpp +++ b/examples/example_12/example_12.cpp @@ -1,97 +1,235 @@ -/** - * This example utilises the ```TensorboardServer``` class to log values of interest when running - * an experiment. We can monitor the experimet using tensorboard. The ```TensorboardServer``` class - *is a simple wrapper that exposes three functions - * - * - ```add_scalar``` - * - ```add_scalars``` - * - ```add_text``` - * - * We will use ```add_scalar``` and ```add_text```. In order to run this example, fire up the - *server using the ```torchboard_server/start_uvicorn.sh```. The server listens at port 8002. You - *can change this however you want just make sure that the port is not used and also update the - * variable ```TORCH_SERVER_HOST``` in the code below accordingly. Note that the implementation - *uses SummaryWriter - *class. Thus you will need to have PyTorch installed on the machine that you run the server. - */ +#include "bitrl/bitrl_config.h" + +#ifdef BITRL_CHRONO #include "bitrl/bitrl_types.h" -#include "bitrl/utils/io/json_file_reader.h" -#include "bitrl/network/tensorboard_server.h" +#include "bitrl/bitrl_consts.h" -#include -#include -#include -#include +#ifdef BITRL_LOG +#define BOOST_LOG_DYN_LINK +#include +#endif + +#include +#include +#include "chrono/assets/ChVisualSystem.h" +#include + +#include +#include + +#include namespace example_12 { + +using namespace chrono; +using namespace chrono::irrlicht; using namespace bitrl; -using utils::io::JSONFileReader; -using network::TensorboardServer; -namespace fs = std::filesystem; -const std::string CONFIG = "config.json"; +const real_t WHEEL_RADIUS = 0.1; +const real_t CHASSIS_HEIGHT = 0.1; +const real_t WHEEL_WIDTH = 0.05; +const real_t CASTER_RADIUS = 0.05; + +void draw_world_axes(chrono::irrlicht::ChVisualSystemIrrlicht& vis, + real_t scale = 1.0) { + auto* driver = vis.GetVideoDriver(); + + // X axis (red) + driver->draw3DLine( + {0, 0, 0}, + {static_cast(scale), 0, 0}, + irr::video::SColor(255, 255, 0, 0)); + + // Y axis (green) + driver->draw3DLine( + {0, 0, 0}, + {0, static_cast(scale), 0}, + irr::video::SColor(255, 0, 255, 0)); + + // Z axis (blue) + driver->draw3DLine( + {0, 0, 0}, + {0, 0, static_cast(scale)}, + irr::video::SColor(255, 0, 0, 255)); +} + +auto build_generic_material() +{ + auto material = chrono_types::make_shared(); + material->SetFriction(0.8f); + material->SetRestitution(0.1f); + return material; +} -} // namespace example_12 +auto build_floor(std::shared_ptr material) +{ + auto floor = chrono_types::make_shared( + 5, 5, 0.1, // size + 1000, // density + true, true, material); // visual + collision + + floor->SetPos(chrono::ChVector3d(0,0,-0.05)); + floor->SetFixed(true); + floor->EnableCollision(true); + return floor; +} -int main() +auto build_chassis(std::shared_ptr material) { + auto chassis = chrono_types::make_shared( + 0.5, 0.3, CHASSIS_HEIGHT, + 1000, + true, true, material); + + chrono::ChVector3d pos(0.0, 0.0, WHEEL_RADIUS + CHASSIS_HEIGHT/2.0 + 0.01); + chassis->SetPos(pos); + + chrono::ChVector3d vel(0.5, 0.0, 0.0); + chassis->SetPosDt(vel); + chassis->EnableCollision(true); + return chassis; +} - using namespace example_12; +auto build_wheel(std::shared_ptr material, const chrono::ChVector3d& pos) +{ + auto wheel = chrono_types::make_shared( + chrono::ChAxis::Y, + WHEEL_RADIUS, + WHEEL_WIDTH, + 1000, + true, true, material); + + wheel->SetPos(pos); + wheel->EnableCollision(true); + return wheel; +} - try - { +auto build_motor(std::shared_ptr wheel, + std::shared_ptr chassis, + std::shared_ptr speed_func, + const chrono::ChVector3d& pos) +{ + auto motor = chrono_types::make_shared(); - // load the json configuration - JSONFileReader json_reader(CONFIG); - json_reader.open(); + chrono::ChQuaternion<> rot = chrono::QuatFromAngleX(chrono::CH_PI_2); + motor->Initialize( + wheel, + chassis, + chrono::ChFrame<>(pos, rot) + ); - auto experiment_dict = json_reader.template get_value("experiment_dict"); - auto experiment_id = json_reader.template get_value("experiment_id"); + motor->SetSpeedFunction(speed_func); + return motor; +} - std::cout << "Experiment directory: " << experiment_dict << std::endl; - std::cout << "Experiment id: " << experiment_id << std::endl << std::endl; +auto build_caster_wheel(std::shared_ptr material) +{ - const fs::path EXPERIMENT_DIR_PATH = experiment_dict + experiment_id; + auto caster = chrono_types::make_shared( + CASTER_RADIUS, // radius + 1000, // density + true, // visualization + true, // collision + material); - // the first thing we want to do when monitoring experiments - // is to create a directory where all data will reside - std::filesystem::create_directories(experiment_dict + experiment_id); + caster->SetPos(chrono::ChVector3d(0.2, 0, 0.05)); + caster->EnableCollision(true); + return caster; +} - const auto input_size = json_reader.template get_value("input_size"); - const auto output_size = json_reader.template get_value("output_size"); - const auto num_epochs = json_reader.template get_value("num_epochs"); - const auto learning_rate = json_reader.template get_value("lr"); - auto log_path = json_reader.template get_value("log_path"); +auto build_caster_joint(std::shared_ptr caster, + std::shared_ptr chassis) +{ + auto caster_joint = chrono_types::make_shared(); - // log the hyperparameters - std::cout << "Input size: " << input_size << std::endl; - std::cout << "Output size: " << output_size << std::endl; - std::cout << "Max epochs: " << num_epochs << std::endl; - std::cout << "Learning rate: " << learning_rate << std::endl; + caster_joint->Initialize( + caster, + chassis, + ChFrame<>(chrono::ChVector3d(-0.25, 0, CASTER_RADIUS), QUNIT)); + return caster_joint; - TensorboardServer logger("http://0.0.0.0:8002"); +} +} - std::cout << "Logging results at " << logger.get_log_dir_path() << std::endl; - logger.init(log_path); +int main() { - logger.add_scalar("lr", learning_rate); - logger.add_scalar("seed", 42); - logger.add_scalar("num_epochs", num_epochs); - logger.add_text("optimizer", "torch::optim::SGD"); - logger.close(); - } - catch (std::exception &e) - { - std::cout << e.what() << std::endl; - } - catch (...) - { - std::cout << "Unknown exception occured" << std::endl; + using namespace example_12; + ChSystemNSC system; + system.SetGravitationalAcceleration(chrono::ChVector3d(0,0,-bitrl::consts::maths::G)); + system.SetCollisionSystemType(chrono::ChCollisionSystem::Type::BULLET); + + // create a generic material to use + auto material = example_12::build_generic_material(); + + // build floor + auto floor = example_12::build_floor(material); + system.Add(floor); + + // build chassis + auto chassis = example_12::build_chassis(material); + system.Add(chassis); + + // build wheels + auto left_wheel = example_12::build_wheel(material,chrono::ChVector3d(0, 0.2, 0.1)); + auto right_wheel = example_12::build_wheel(material,chrono::ChVector3d(0,-0.2, 0.1)); + system.Add(left_wheel); + system.Add(right_wheel); + + // build motor + auto motor_left = example_12::build_motor(left_wheel, chassis, + chrono_types::make_shared(-4.5), chrono::ChVector3d(0,0.2,0.1)); + auto motor_right = build_motor(right_wheel, chassis, + chrono_types::make_shared(-4.5), chrono::ChVector3d(0,-0.2,0.1)); + + system.Add(motor_left); + system.Add(motor_right); + + auto caster = example_12::build_caster_wheel(material); + system.Add(caster); + + auto caster_joint = example_12::build_caster_joint(caster, chassis); + system.Add(caster_joint); + + // create the visualization system + chrono::irrlicht::ChVisualSystemIrrlicht vis; + + vis.AttachSystem(&system); + vis.SetWindowSize(1280,720); + vis.SetWindowTitle("Example 12 Differential Drive Robot"); + vis.Initialize(); + vis.AddSkyBox(); + vis.AddLogo(); + vis.AddSkyBox(); + vis.AddCamera({0, -2, 1}, {0, 0, 0}); + vis.AddTypicalLights(); + vis.BindAll(); + + real_t step_size = 0.002; + while (vis.Run()) { + + vis.BeginScene(); + vis.Render(); + draw_world_axes(vis, 2.0); + + auto position = chassis -> GetPos(); + std::cout << position < +int main() +{ + std::cerr<<"You need PROJECTCHRONO configured with " + <<"bitrl in order to run this example " + <<"Reconfigure bitrl and set ENABLE_CHRONO=ON"<Simulation system for more information). +A _ChSystem_ is an abstract class. The Chrono library provides the following subclasses: + +- _ChSystemNSC_ for Non Smooth Contacts (NSC): in case of contacts a complementarity solver will take care of them using non-smooth dynamics; this is very efficient even with large time steps. +- _ChSystemSMC_ for SMooth Contacts (SMC): contacts are handled using penalty methods, i.e. contacts are deformable. + +Note that if there are no contacts or collisions in your system, it is indifferent to use _ChSystemNSC_ or _ChSystemSMC_. + +We will use the _ChSystemNSC_ class in the example below as the wheels of the robot will be in contact with the ground. +The code below evolves around a number of helper functions that create the various components we will be adding to +the _ChSystemSMC_. A lot of things are hardcoded i.e. not necessarily the best way we want to do things. +However, in this tutorial we want to keep things simple and concentrate more on the essential elements of a Chrono simulation. + +The include files + +@code{.cpp} +#include "bitrl/bitrl_config.h" + +#ifdef BITRL_CHRONO + +#include "bitrl/bitrl_types.h" +#include "bitrl/bitrl_consts.h" + +#ifdef BITRL_LOG +#define BOOST_LOG_DYN_LINK +#include +#endif + +#include +#include +#include "chrono/assets/ChVisualSystem.h" +#include + +#include +#include + +#include +@endcode + +Next are the helper functions that set up the various components. Note that we need to enable collisions. +We also need to set explicitly the velocity of the chassis explicitly. The linear velocity of a differential drive system is given by + +$$ +v = \frac{r}{2}(\omega_R + \omega_L) +$$ + +where \f$r\f$ is the radius of the wheel and \f$\omega_i\f$ if the angular velocity of motor \f$\i\f$ in rad/s. +We can use this relationship in a control simulation in order to control either the linear velocity or the motor speed. + +@code{.cpp} +namespace example_12 +{ + +using namespace chrono; +using namespace chrono::irrlicht; +using namespace bitrl; + +const real_t WHEEL_RADIUS = 0.1; +const real_t CHASSIS_HEIGHT = 0.1; +const real_t WHEEL_WIDTH = 0.05; +const real_t CASTER_RADIUS = 0.05; + +void draw_world_axes(chrono::irrlicht::ChVisualSystemIrrlicht& vis, +real_t scale = 1.0) { +auto* driver = vis.GetVideoDriver(); + + // X axis (red) + driver->draw3DLine( + {0, 0, 0}, + {static_cast(scale), 0, 0}, + irr::video::SColor(255, 255, 0, 0)); + + // Y axis (green) + driver->draw3DLine( + {0, 0, 0}, + {0, static_cast(scale), 0}, + irr::video::SColor(255, 0, 255, 0)); + + // Z axis (blue) + driver->draw3DLine( + {0, 0, 0}, + {0, 0, static_cast(scale)}, + irr::video::SColor(255, 0, 0, 255)); +} + +auto build_generic_material() +{ +auto material = chrono_types::make_shared(); +material->SetFriction(0.8f); +material->SetRestitution(0.1f); +return material; +} + +auto build_floor(std::shared_ptr material) +{ +auto floor = chrono_types::make_shared( +5, 5, 0.1, // size +1000, // density +true, true, material); // visual + collision + + floor->SetPos(chrono::ChVector3d(0,0,-0.05)); + floor->SetFixed(true); + floor->EnableCollision(true); + return floor; +} + +auto build_chassis(std::shared_ptr material) +{ +auto chassis = chrono_types::make_shared( +0.5, 0.3, CHASSIS_HEIGHT, +1000, +true, true, material); + + chrono::ChVector3d pos(0.0, 0.0, WHEEL_RADIUS + CHASSIS_HEIGHT/2.0 + 0.01); + chassis->SetPos(pos); + + chrono::ChVector3d vel(0.5, 0.0, 0.0); + chassis->SetPosDt(vel); + chassis->EnableCollision(true); + return chassis; +} + +auto build_wheel(std::shared_ptr material, const chrono::ChVector3d& pos) +{ +auto wheel = chrono_types::make_shared( +chrono::ChAxis::Y, +WHEEL_RADIUS, +WHEEL_WIDTH, +1000, +true, true, material); + + wheel->SetPos(pos); + wheel->EnableCollision(true); + return wheel; +} + +auto build_motor(std::shared_ptr wheel, +std::shared_ptr chassis, +std::shared_ptr speed_func, +const chrono::ChVector3d& pos) +{ +auto motor = chrono_types::make_shared(); + + chrono::ChQuaternion<> rot = chrono::QuatFromAngleX(chrono::CH_PI_2); + motor->Initialize( + wheel, + chassis, + chrono::ChFrame<>(pos, rot) + ); + + motor->SetSpeedFunction(speed_func); + return motor; +} + +auto build_caster_wheel(std::shared_ptr material) +{ + + auto caster = chrono_types::make_shared( + CASTER_RADIUS, // radius + 1000, // density + true, // visualization + true, // collision + material); + + caster->SetPos(chrono::ChVector3d(0.2, 0, 0.05)); + caster->EnableCollision(true); + return caster; +} + +auto build_caster_joint(std::shared_ptr caster, +std::shared_ptr chassis) +{ +auto caster_joint = chrono_types::make_shared(); + + caster_joint->Initialize( + caster, + chassis, + ChFrame<>(chrono::ChVector3d(-0.25, 0, CASTER_RADIUS), QUNIT)); + return caster_joint; + +} +} +@endcode + +Below is the main driver + + +@code{.cpp} +int main() { + + using namespace example_12; + ChSystemNSC system; + system.SetGravitationalAcceleration(chrono::ChVector3d(0,0,-bitrl::consts::maths::G)); + system.SetCollisionSystemType(chrono::ChCollisionSystem::Type::BULLET); + + // create a generic material to use + auto material = example_12::build_generic_material(); + + // build floor + auto floor = example_12::build_floor(material); + system.Add(floor); + + // build chassis + auto chassis = example_12::build_chassis(material); + system.Add(chassis); + + // build wheels + auto left_wheel = example_12::build_wheel(material,chrono::ChVector3d(0, 0.2, 0.1)); + auto right_wheel = example_12::build_wheel(material,chrono::ChVector3d(0,-0.2, 0.1)); + system.Add(left_wheel); + system.Add(right_wheel); + + // build motor + auto motor_left = example_12::build_motor(left_wheel, chassis, + chrono_types::make_shared(-4.5), chrono::ChVector3d(0,0.2,0.1)); + auto motor_right = build_motor(right_wheel, chassis, + chrono_types::make_shared(-4.5), chrono::ChVector3d(0,-0.2,0.1)); + + system.Add(motor_left); + system.Add(motor_right); + + auto caster = example_12::build_caster_wheel(material); + system.Add(caster); + + auto caster_joint = example_12::build_caster_joint(caster, chassis); + system.Add(caster_joint); + + // create the visualization system + chrono::irrlicht::ChVisualSystemIrrlicht vis; + + vis.AttachSystem(&system); + vis.SetWindowSize(1280,720); + vis.SetWindowTitle("Example 12 Differential Drive Robot"); + vis.Initialize(); + vis.AddSkyBox(); + vis.AddLogo(); + vis.AddSkyBox(); + vis.AddCamera({0, -2, 1}, {0, 0, 0}); + vis.AddTypicalLights(); + vis.BindAll(); + + real_t step_size = 0.002; + while (vis.Run()) { + + vis.BeginScene(); + vis.Render(); + draw_world_axes(vis, 2.0); + + auto position = chassis -> GetPos(); + std::cout << position <