Program Listing for File wiimote_controller.hpp
↰ Return to documentation for file (include/wiimote/wiimote_controller.hpp
)
// Copyright 2020 Intel Corporation
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/*
* ROS Node for interfacing with a wiimote control unit.
*/
/*
* This code is based on the original Python implementation
* created by Andreas Paepcke and Melonee Wise
* Andreas Paepcke <paepcke@anw.willowgarage.com>
* with contributions by
* David Lu <davidlu@wustl.edu>
* Miguel Angel Julian Aguilar <miguel.angel@thecorpora.com>
* See https://github.com/ros-drivers/joystick_drivers/tree/indigo-devel/wiimote
* for details and history.
*
* This C++ implementation used the functionality of the existing
* Python code as the feature requirements.
*/
/*
* Initial C++ implementation by
* Mark Horn <mark.d.horn@intel.com>
*
* Revisions:
*
*/
#pragma once
#ifndef WIIMOTE__WIIMOTE_CONTROLLER_HPP_
#define WIIMOTE__WIIMOTE_CONTROLLER_HPP_
#include <rclcpp/rclcpp.hpp>
#include <rclcpp_lifecycle/lifecycle_node.hpp>
#include <sensor_msgs/msg/imu.hpp>
#include <sensor_msgs/msg/joy.hpp>
#include <sensor_msgs/msg/joy_feedback_array.hpp>
#include <std_msgs/msg/bool.hpp>
#include <std_srvs/srv/empty.hpp>
#include <wiimote_msgs/msg/state.hpp>
#include "bluetooth/bluetooth.h"
namespace wiimote_c
{
#include "cwiid.h" // NOLINT, cpplint wants us to have a directory
}
#include "wiimote/stat_vector_3d.hpp"
#define zeroedByCal(raw, zero, one) (((raw - zero) * 1.0) / ((one - zero) * 1.0))
class WiimoteNode : public rclcpp_lifecycle::LifecycleNode
{
public:
explicit WiimoteNode(const rclcpp::NodeOptions & options);
CallbackReturn on_configure(const rclcpp_lifecycle::State & previous_state) override;
CallbackReturn on_activate(const rclcpp_lifecycle::State & previous_state) override;
CallbackReturn on_deactivate(const rclcpp_lifecycle::State & previous_state) override;
CallbackReturn on_cleanup(const rclcpp_lifecycle::State & previous_state) override;
CallbackReturn on_shutdown(const rclcpp_lifecycle::State & previous_state) override;
CallbackReturn on_error(const rclcpp_lifecycle::State & previous_state) override;
char * get_bluetooth_addr();
void set_bluetooth_addr(const char * bt_str);
bool pair_wiimote(int flags, int timeout);
int unpair_wiimote();
void publish();
bool wiimote_is_connected();
void check_connection();
void set_led_state(uint8_t led_state);
void set_rumble_state(uint8_t rumble);
private:
void set_report_mode(uint8_t rpt_mode);
void check_factory_calibration_data();
void reset_motion_plus_state();
void reset_nunchuck_state();
void reset_classic_state();
static wiimote_c::cwiid_err_t cwiid_error_callback;
void joy_set_feedback_callback(sensor_msgs::msg::JoyFeedbackArray::ConstSharedPtr feedback);
bool service_imu_calibrate_callback(
std_srvs::srv::Empty::Request::SharedPtr, std_srvs::srv::Empty::Response::SharedPtr);
bool is_collecting_wiimote();
bool is_collecting_nunchuk();
bool is_collecting_classic();
bool is_collecting_motionplus();
bool is_present_nunchuk();
bool is_present_classic();
bool is_present_motionplus();
bool calibrate_joystick(uint8_t * stick, uint8_t(¢er)[2], const char * name);
void update_joystick_min_max(
uint8_t * stick, uint8_t(&stick_min)[2], uint8_t(&stick_max)[2], const char * name);
void calculate_joystick_axis_xy(
uint8_t * stick_current, uint8_t * stick_min, uint8_t * stick_max, uint8_t * stick_center,
double (& stick)[2]);
void publish_joy();
void publish_imu_data();
void publish_wiimote_state();
bool publish_wiimote_nunchuk_common();
void publish_wiimote_nunchuk();
void publish_wiimote_classic();
void initialize_wiimote_state();
bool get_state_sample();
void set_led_bit(uint8_t led, bool on);
void set_rumble_bit(bool on);
rclcpp::Logger logger_;
rclcpp_lifecycle::LifecyclePublisher<sensor_msgs::msg::Joy>::SharedPtr joy_pub_;
rclcpp_lifecycle::LifecyclePublisher<sensor_msgs::msg::Imu>::SharedPtr imu_data_pub_;
rclcpp_lifecycle::LifecyclePublisher<wiimote_msgs::msg::State>::SharedPtr wiimote_state_pub_;
rclcpp_lifecycle::LifecyclePublisher<sensor_msgs::msg::Joy>::SharedPtr wiimote_nunchuk_pub_;
rclcpp_lifecycle::LifecyclePublisher<sensor_msgs::msg::Joy>::SharedPtr wiimote_classic_pub_;
rclcpp_lifecycle::LifecyclePublisher<std_msgs::msg::Bool>::SharedPtr imu_is_calibrated_pub_;
rclcpp::Subscription<sensor_msgs::msg::JoyFeedbackArray>::SharedPtr joy_set_feedback_sub_;
rclcpp::Service<std_srvs::srv::Empty>::SharedPtr imu_calibrate_srv_;
rclcpp::TimerBase::SharedPtr check_connection_timer_;
rclcpp::TimerBase::SharedPtr publish_timer_;
// bluetooth device address
bdaddr_t bt_device_addr_;
// wiimote handle
wiimote_c::cwiid_wiimote_t * wiimote_;
// Last state of the Wiimote
struct wiimote_c::cwiid_state wiimote_state_;
// Time last state sample was taken
uint32_t state_secs_;
uint32_t state_nsecs_;
// Which data items should be reported in state
uint8_t report_mode_;
// Calibration status Wiimote
struct wiimote_c::acc_cal wiimote_cal_; // wiimote acceleration factory calibration
bool wiimote_calibrated_;
rclcpp::Time calibration_time_;
// Joystick related constants
const uint8_t JOYSTICK_NUNCHUK_DEFAULT_CENTER_ = 127; // Theoretical center
const uint8_t JOYSTICK_NUNCHUK_20PERCENT_MAX_ = 205;
const uint8_t JOYSTICK_NUNCHUK_20PERCENT_MIN_ = 50;
const uint8_t JOYSTICK_CLASSIC_LEFT_DEFAULT_CENTER_ = 31; // Theoretical center
const uint8_t JOYSTICK_CLASSIC_LEFT_20PERCENT_MAX_ = 50;
const uint8_t JOYSTICK_CLASSIC_LEFT_20PERCENT_MIN_ = 13;
const uint8_t JOYSTICK_CLASSIC_RIGHT_DEFAULT_CENTER_ = 15; // Theoretical center
const uint8_t JOYSTICK_CLASSIC_RIGHT_20PERCENT_MAX_ = 25;
const uint8_t JOYSTICK_CLASSIC_RIGHT_20PERCENT_MIN_ = 6;
// Calibration status Nunchuk
struct wiimote_c::acc_cal nunchuk_cal_; // nunchuk acceleration factory calibration
bool nunchuk_calibrated_;
bool nunchuk_failed_calibration_;
uint8_t nunchuk_stick_center_[2]; // nunchuk stick center position
bool nunchuk_stick_calibrated_;
uint8_t nunchuk_stick_max_[2]; // Maximums x,y
uint8_t nunchuk_stick_min_[2]; // Minimums x,y
// Calibration status Classic Controller
uint8_t classic_stick_left_center_[2]; // nunchuk stick center position
bool classic_stick_left_calibrated_;
uint8_t classic_stick_left_max_[2];
uint8_t classic_stick_left_min_[2];
uint8_t classic_stick_right_center_[2]; // nunchuk stick center position
bool classic_stick_right_calibrated_;
uint8_t classic_stick_right_max_[2];
uint8_t classic_stick_right_min_[2];
const int IGNORE_DATA_POINTS_ = 100; // throw away the first few data points
const int COVARIANCE_DATA_POINTS_ = 100;
StatVector3d linear_acceleration_stat_;
StatVector3d angular_velocity_stat_;
std::array<double, 9> linear_acceleration_covariance_;
std::array<double, 9> angular_velocity_covariance_;
uint8_t led_state_ = 0;
uint8_t rumble_ = 0;
uint64_t wiimote_errors = 0;
// Convert wiimote accelerator readings from g's to m/sec^2:
const double EARTH_GRAVITY_ = 9.80665; // m/sec^2 @sea_level
// Method used in Wiimote Python version
// TODO(mdhorn): Repeat experiment or create a new one
// and collect data from multiple wiimotes and use mean.
//
// Turning wiimote gyro readings to radians/sec.
// This scale factor is highly approximate. Procedure:
// - Tape Wiimote to center of an office chair seat
// - Rotate the chair at approximately constant speed
// for 10 seconds. This resulted in 6 chair revolutions
// - On average, the Wiimote gyro read 3570 during this
// experiment.
// - Speed of chair revolving:
// * One full circle is: 2#pi radians
// * Six revolutions = 12pi radians. ==> 12pi rad in 10 sec ==> 1.2pi rad/sec
// * => 3570 == 1.2pi
// * => x*3570 = 1.2pi
// * => x = 1.2pi/3570 (1.2pi = 3.769908)
// * => scale factor = 0.001055997
// So multiplying the gyro readings by this factor
// calibrates the readings to show angular velocity
// in radians/sec.
const double GYRO_SCALE_FACTOR_ = 0.001055997;
};
#endif // WIIMOTE__WIIMOTE_CONTROLLER_HPP_