Skip to content
Open
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build/
install/
log/
venv/
__pycache__/
27 changes: 27 additions & 0 deletions graph_pwm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal

clock_speed = 84000000
prescaler = 839
period = 1999
pulse = 1000

# okay so pwm_freq = clock_speed / prescaler * period
# duty cycle = pulse / period

timer_tick_freq = clock_speed / (prescaler + 1)
pwm_freq = timer_tick_freq / (period + 1)
duty_cycle = (pulse / (period + 1)) * 100

time = np.linspace(0, 0.06, 1000)
wave = signal.square(2 * np.pi * pwm_freq * time, duty=duty_cycle/100)

plt.figure(figsize=(10, 4))
plt.plot(time * 1000, wave, color='green', linewidth=2)
plt.title(f'PWM Output ({pwm_freq}Hz, {duty_cycle}% Duty Cycle)')
plt.xlabel('Time (ms)')
plt.ylabel('On/Off')
plt.ylim(-1.5, 1.5)
plt.grid(True)
plt.show()
Binary file added pwm_config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile
{
"name": "Existing Dockerfile",
"build": {
// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerfile": "../Dockerfile.dev"
},
"containerEnv": { "DISPLAY": "host.docker.internal:0.0" }

// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Uncomment the next line to run commands after the container is created.
// "postCreateCommand": "cat /etc/os-release",

// Configure tool-specific properties.
// "customizations": {},

// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "devcontainer"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/software_training/launch/__pycache__/
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Start with the desktop ROS Galactic 20.04 image
FROM osrf/ros:galactic-desktop

# This dockerfile assumes you'll share your development folder from your computer over to the container,
# so we don't do `rosdep install` for you, or clone the repository.

# update everything
RUN sudo apt update -y --no-install-recommends && sudo apt dist-upgrade -y
# Ensure rosinstall and rosdep are installed and up to date
RUN sudo apt install -y python3-rosdep

# build via docker build -f .\Dockerfile.dev -t uwrt_dev_image .
# run via docker run --name uwrt_dev_container -e DISPLAY=host.docker.internal:0.0 -it -v uwrt_dev_image


29 changes: 29 additions & 0 deletions software_training_assignment/uwrt_software_trainining/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# uwrt_software_trainining

This is a solution of the software training with some added bugs that discourages one from copying and pasting the code. This code is meant to
serve as a guide to those starting out the training. It makes use of some ROS2 concepts not covered in the training as it is meant to encourage you to
go out and learn different features of ROS2.

This code covers core concepts of ROS2 such as
components, topic statistic, callback groups, extending rclcpp::Node,
the creation of pubs/subs, services/clients, action servers, and multi-threaded callbacks.

The use of the turtlesim package is needed to complete this training. https://docs.ros.org/en/foxy/Tutorials/Turtlesim/Introducing-Turtlesim.html

**The training challenge consists of the following:**

**That training relies heavily on components - as this is the newer and better way to go about ROS2 design**

**Write 6 components that do the following: (Note: Some of the components do not need to be made in the following order)**
1. Clears any existing turtles
2. Create a component that moves 'turtle1' in a circular motion
3. Spawns a turtle named "stationary_turtle" at x = 5, y = 5
Spawns a second turtle named "moving_turtle" at x = 25, y = 10
4. Create a service that resets the "moving_turtle" to its starting position. The service response should be whether or not it was successful.
5. Create a publisher that publishes a custom msg. This custom msgs should have 3 float fields that correspond with the x and y distances of "stationary_turtle" to "moving turtle", as well as the distance between the two turtles.

6. Create an action that moves "moving_turtle" to a waypoint in a straight line by publishing geometry_msgs/Twist msgs to turtleX/cmd_vel.The action's goal command is an absolute position of the waypoint, feedback is distance to the goal, and result is the time it took to reach the goal. You should define a custom action file.

Lastly, create a launch file that will start up all the components and the turtlesim node (configure the parameters of the turtlesim node to however you see fit). Ensure that the turtlesim node is launched first as the other components are dependent upon it.


Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
cmake_minimum_required(VERSION 3.5)
project(software_training)

# default to C99
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()

# default to C++ 14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(turtlesim REQUIRED)
find_package(rclcpp_components REQUIRED)
find_package(std_msgs REQUIRED)
find_package(rcutils REQUIRED)
find_package(rcl REQUIRED)
find_package(rclcpp_action REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(rosidl_default_generators REQUIRED)

include_directories(include)

rosidl_generate_interfaces(${PROJECT_NAME}
"msg/Software.msg"
"srv/Software.srv"
"action/Software.action"
DEPENDENCIES std_msgs geometry_msgs builtin_interfaces
)
ament_export_dependencies(rosidl_default_runtime)

set(node_plugins "")

add_library(turtle_request SHARED src/turtle_neutralize.cpp)
target_compile_definitions(turtle_request PRIVATE "COMPOSITION_BUILDING_DLL")
ament_target_dependencies(turtle_request "rclcpp" "rclcpp_components" "turtlesim" "std_msgs")
rclcpp_components_register_nodes(turtle_request "composition::turtle_service_request_node")
set(node_plugins "${node_plugins}composition::turtle_service_request_node;\\$<TARGET_FILE:turtle_request>\n")

add_library(turtle_spawn SHARED src/spawn_turtle_nodelet.cpp)
target_compile_definitions(turtle_spawn PRIVATE "COMPOSITION_BUILDING_DLL")
ament_target_dependencies(turtle_spawn "rclcpp" "rclcpp_components" "turtlesim" "std_msgs")
rclcpp_components_register_nodes(turtle_spawn "composition::spawn_turtle_nodelet")
set(node_plugins "${node_plugins}composition::spawn_turtle_nodelet;\\$<TARGET_FILE:turtle_spawn>\n")

add_library(turtle_pub SHARED src/turtle_publisher.cpp)
target_compile_definitions(turtle_pub PRIVATE "COMPOSITION_BUILDING_DLL")
ament_target_dependencies(turtle_pub "rclcpp" "rclcpp_components" "turtlesim" "std_msgs")
rosidl_target_interfaces(turtle_pub ${PROJECT_NAME} "rosidl_typesupport_cpp")
rclcpp_components_register_nodes(turtle_pub "composition::turtle_publisher")
set(node_plugins "${node_plugins}composition::turtle_publisher;\\$<TARGET_FILE:turtle_pub>\n")

add_library(turtle_service SHARED src/reset_moving_turtle_service.cpp)
target_compile_definitions(turtle_service PRIVATE "COMPOSITION_BUILDING_DLL")
ament_target_dependencies(turtle_service "rclcpp" "rclcpp_components" "turtlesim" "std_msgs")
rosidl_target_interfaces(turtle_service ${PROJECT_NAME} "rosidl_typesupport_cpp")
rclcpp_components_register_nodes(turtle_service "composition::reset_moving_turtle_service")
set(node_plugins "${node_plugins}composition::reset_moving_turtle_service;\\$<TARGET_FILE:turtle_service>\n")

add_library(cmd_vel_publisher SHARED src/cmd_vel_moving_turt_publisher.cpp)
target_compile_definitions(cmd_vel_publisher PRIVATE "COMPOSITION_BUILDING_DLL")
ament_target_dependencies(cmd_vel_publisher "rclcpp" "rclcpp_components" "turtlesim" "geometry_msgs" "std_msgs")
rclcpp_components_register_nodes(cmd_vel_publisher "composition::cmd_vel_moving_turt_publisher")
set(node_plugins "${node_plugins}composition::cmd_vel_moving_turt_publisher;\\$<TARGET_FILE:cmd_vel_publisher>\n")

add_library(turtle_action_server SHARED src/moving_turtle_action_server.cpp)
target_compile_definitions(turtle_action_server PRIVATE "SOFTWARE_TRAINING_DLL")
ament_target_dependencies(turtle_action_server "rclcpp" "rclcpp_components" "turtlesim" "rclcpp_action" "std_msgs" "geometry_msgs")
rosidl_target_interfaces(turtle_action_server ${PROJECT_NAME} "rosidl_typesupport_cpp")
rclcpp_components_register_node(turtle_action_server PLUGIN "composition::moving_turtle_action_server" EXECUTABLE moving_action_server)

install(TARGETS
turtle_request
turtle_spawn
turtle_pub
turtle_service
turtle_action_server
cmd_vel_publisher
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)

install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})

ament_package()
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Goal Request /moving_turtle/cmd_vel
geometry_msgs/Vector3 linear_pos
geometry_msgs/Vector3 angular_pos

# Result - time
---
uint64 duration

---
# Feedback /moving_turtle/pose
float32 x_pos
float32 y_pos
float32 theta_pos



Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef CMD_VEL_MOVING_TURT_PUBLISHER_HPP_
#define CMD_VEL_MOVING_TURT_PUBLISHER_HPP_

#include <chrono>
#include <cstdlib>
#include <memory>
#include <string>

#include <rclcpp/rclcpp.hpp>
#include <geometry_msgs/msg/twist.hpp>
#include <software_training/visibility.h>

namespace composition {

class cmd_vel_moving_turt_publisher : public rclcpp::Node {

public:
SOFTWARE_TRAINING_PUBLIC
explicit cmd_vel_moving_turt_publisher(const rclcpp::NodeOptions &options);

private:
rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr publisher;
rclcpp::TimerBase::SharedPtr timer;

static constexpr unsigned int QUEUE{10};

struct coordinates {
struct linear {
static constexpr float x = 2.0;
static constexpr float y = 0.0;
static constexpr float z = 0.0;
};
struct angular {
static constexpr float x = 0.0;
static constexpr float y = 0.0;
static constexpr float z = 2.0;
};
};
};

} // namespace composition

#endif // CMD_VEL_MOVING_TURT_PUBLISHER_HPP_
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#ifndef MOVING_TURTLE_ACTION_SERVER_HPP_
#define MOVING_TURTLE_ACTION_SERVER_HPP_

#include <chrono>
#include <functional>
#include <memory>
#include <thread>

#include <rclcpp/rclcpp.hpp>
#include <rclcpp/time.hpp> // ros2 time header
#include <rclcpp_action/rclcpp_action.hpp> // ros2 action header
#include <software_training/action/software.hpp>
#include <software_training/visibility.h>

#include <geometry_msgs/msg/twist.hpp> // cmd_vel publisher message
#include <turtlesim/msg/pose.hpp> // header for message to get moving turt position

namespace composition{

class moving_turtle_action_server : public rclcpp::Node {
public:
SOFTWARE_TRAINING_PUBLIC
explicit moving_turtle_action_server(const rclcpp::NodeOptions &options);

using GoalHandleActionServer =
rclcpp_action::ServerGoalHandle<software_training::action::Software>;

private:
rclcpp_action::Server<software_training::action::Software>::SharedPtr action_server;
rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr publisher;
rclcpp::Subscription<turtlesim::msg::Pose>::SharedPtr subscriber;

SOFTWARE_TRAINING_LOCAL
rclcpp_action::GoalResponse handle_goal(
const rclcpp_action::GoalUUID &uuid,
std::shared_ptr<const software_training::action::Software::Goal> goal);

SOFTWARE_TRAINING_LOCAL
rclcpp_action::CancelResponse
handle_cancel(const std::shared_ptr<GoalHandleActionServer> goal_handle);

SOFTWARE_TRAINING_LOCAL
void handle_accepted(const std::shared_ptr<GoalHandleActionServer> goal_handle);

void execute(const std::shared_ptr<GoalHandleActionServer> goal_handle);

float x{0.0f};
float y{0.0f};
float theta{0.0f};
float linear_velocity{0.0f};
float angular_velocity{0.0f};

static constexpr unsigned int QUEUE{10};
};

} // namespace composition

#endif // MOVING_TURTLE_ACTION_SERVER_HPP_
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef RESET_MOVING_TURTLE_SERVICE_HPP_
#define RESET_MOVING_TURTLE_SERVICE_HPP_

#include <cstdlib>
#include <functional>
#include <memory>

#include <rclcpp/rclcpp.hpp>

#include <software_training/srv/software.hpp>
#include <software_training/visibility.h>
#include <turtlesim/srv/teleport_absolute.hpp>

namespace composition {

class reset_moving_turtle_service : public rclcpp::Node {

public:
SOFTWARE_TRAINING_PUBLIC
explicit reset_moving_turtle_service(const rclcpp::NodeOptions &options);

private:
// create service that will reset turtle to starting point
rclcpp::Service<software_training::srv::Software>::SharedPtr service;

// create client
rclcpp::Client<turtlesim::srv::TeleportAbsolute>::SharedPtr client;

// server callback
SOFTWARE_TRAINING_LOCAL
void service_callback(
const std::shared_ptr<software_training::srv::Software::Request> request,
std::shared_ptr<software_training::srv::Software::Response> response);

struct reset_coordinates {
static constexpr float x = 25.0;
static constexpr float y = 10.0;
static constexpr float theta = 0.0;
};
};

} // namespace composition

#endif // RESET_MOVING_TURTLE_SERVICE_HPP_
Loading