ws281x_node.cpp
Go to the documentation of this file.
1 /*
2  * ws281x LED strip ROS driver
3  * Copyright (C) 2019 Copter Express Technologies
4  *
5  * Authors: Alexey Rogachevskiy <sfalexrog@gmail.com>, Oleg Kalachev <okalachev@gmail.com>
6  *
7  * Distributed under MIT License (available at https://opensource.org/licenses/MIT).
8  * The above copyright notice and this permission notice shall be included in all
9  * copies or substantial portions of the Software.
10  */
11 
12 #include <ros/ros.h>
13 
14 #include <led_msgs/SetLEDs.h>
15 #include <led_msgs/LEDStateArray.h>
16 #include <ws281x/SetGamma.h>
17 
18 #include <ws2811.h>
19 #include <ros/console.h>
20 #include <unordered_map>
21 #include <signal.h>
22 
23 constexpr uint32_t LED_RED_SHIFT = 16;
24 constexpr uint32_t LED_GREEN_SHIFT = 8;
25 constexpr uint32_t LED_BLUE_SHIFT = 0;
26 constexpr uint32_t LED_WHITE_SHIFT = 24;
27 
28 constexpr uint32_t LED_RED_MASK = (0xFF << LED_RED_SHIFT);
29 constexpr uint32_t LED_GREEN_MASK = (0xFF << LED_GREEN_SHIFT);
30 constexpr uint32_t LED_BLUE_MASK = (0xFF << LED_BLUE_SHIFT);
31 constexpr uint32_t LED_WHITE_MASK = (0xFF << LED_WHITE_SHIFT);
32 
33 constexpr uint32_t LED_RED = (0x01 << LED_RED_SHIFT);
34 constexpr uint32_t LED_GREEN = (0x01 << LED_GREEN_SHIFT);
35 constexpr uint32_t LED_BLUE = (0x01 << LED_BLUE_SHIFT);
36 constexpr uint32_t LED_WHITE = (0x01 << LED_WHITE_SHIFT);
37 
38 
39 
40 std::unordered_map<std::string, uint64_t> ws2811_types = {
41  {"SK6812_STRIP_RGBW", SK6812_STRIP_RGBW},
42  {"SK6812_STRIP_RBGW", SK6812_STRIP_RBGW},
43  {"SK6812_STRIP_GRBW", SK6812_STRIP_GRBW},
44  {"SK6812_STRIP_GBRW", SK6812_STRIP_GBRW},
45  {"SK6812_STRIP_BRGW", SK6812_STRIP_BRGW},
46  {"SK6812_STRIP_BGRW", SK6812_STRIP_BGRW},
47  {"WS2811_STRIP_RGB", WS2811_STRIP_RGB},
48  {"WS2811_STRIP_RBG", WS2811_STRIP_RBG},
49  {"WS2811_STRIP_GRB", WS2811_STRIP_GRB},
50  {"WS2811_STRIP_GBR", WS2811_STRIP_GBR},
51  {"WS2811_STRIP_BRG", WS2811_STRIP_BRG},
52  {"WS2811_STRIP_BGR", WS2811_STRIP_BGR},
53  {"WS2812_STRIP", WS2812_STRIP},
54  {"SK6812_STRIP", SK6812_STRIP},
55  {"SK6812W_STRIP", SK6812W_STRIP}
56 };
57 
58 
60 
62 led_msgs::LEDStateArray strip_state;
63 
65 {
66  for(size_t i = 0; i < strip_state.leds.size(); ++i) {
67  strip_state.leds[i].index = i;
68  strip_state.leds[i].r = (led_string.channel[0].leds[i] & LED_RED_MASK) >> LED_RED_SHIFT;
69  strip_state.leds[i].g = (led_string.channel[0].leds[i] & LED_GREEN_MASK) >> LED_GREEN_SHIFT;
70  strip_state.leds[i].b = (led_string.channel[0].leds[i] & LED_BLUE_MASK) >> LED_BLUE_SHIFT;
71  // led_state.w = (led_string.channel[0].leds[i] & LED_WHITE_MASK) >> LED_WHITE_SHIFT;
72  }
73 
74  led_state_pub.publish(strip_state);
75 }
76 
77 bool setGamma(ws281x::SetGamma::Request& req, ws281x::SetGamma::Response& resp)
78 {
79  for(int i = 0; i < 255; ++i) {
80  led_string.channel[0].gamma[i] = req.gamma[i];
81  }
82  resp.success = 1;
83  return true;
84 }
85 
86 bool setLeds(led_msgs::SetLEDs::Request& req, led_msgs::SetLEDs::Response& resp)
87 {
88  // check validness
89  for(auto const& led : req.leds) {
90  if (led.index < 0 || led.index >= strip_state.leds.size()) {
91  ROS_ERROR("[ws281x] LED index out of bounds: %d", led.index);
92  resp.message = "LED index out of bounds: " + std::to_string(led.index);
93  return true;
94  }
95  }
96 
97  for(auto const& led : req.leds) {
98  auto color = uint32_t(
99  LED_RED * int(led.r) + // Red channel mask
100  LED_GREEN * int(led.g) + // Green channel mask
101  LED_BLUE * int(led.b)); // Blue channel mask
102  led_string.channel[0].leds[led.index] = color;
103  }
104  ws2811_return_t ret;
105  if ((ret = ws2811_render(&led_string)) != WS2811_SUCCESS) {
106  resp.message = ws2811_get_return_t_str(ret);
107  ROS_ERROR_THROTTLE(1, "[ws281x] Could not set LED colors: %s", resp.message.c_str());
108  resp.success = false;
109  } else {
110  resp.success = true;
111  resp.message = "";
112  }
113  publishLedState();
114  return true;
115 }
116 
117 void cleanup(int signal)
118 {
119  (void) signal;
120  for(int i = 0; i < led_string.channel[0].count; ++i) {
121  led_string.channel[0].leds[i] = 0;
122  ws2811_render(&led_string);
123  }
124  ws2811_fini(&led_string);
125  ros::shutdown();
126 }
127 
128 int main(int argc, char** argv)
129 {
130  ros::init(argc, argv, "ws281x");
131  ros::NodeHandle nh, nh_priv("~");
132 
133  int param_freq;
134  int param_pin;
135  int param_dma;
136  uint64_t param_strip_type;
137  int param_led_count;
138  bool param_invert;
139  int param_brightness;
140 
141  nh_priv.param("target_frequency", param_freq, WS2811_TARGET_FREQ);
142  nh_priv.param("gpio_pin", param_pin, 21);
143  nh_priv.param("dma", param_dma, 10);
144 
145  std::string strip_type_str;
146  nh_priv.param("strip_type", strip_type_str, std::string("WS2811_STRIP_GBR"));
147  nh_priv.param("led_count", param_led_count, 30);
148  nh_priv.param("invert", param_invert, false);
149  nh_priv.param("brightness", param_brightness, 255);
150 
151  auto strip_type_it = ws2811_types.find(strip_type_str);
152  if (strip_type_it != ws2811_types.end()) {
153  param_strip_type = strip_type_it->second;
154  } else {
155  ROS_WARN("[ws281x] Unknown strip type: %s", strip_type_str.c_str());
156  param_strip_type = WS2811_STRIP_GBR;
157  }
158 
159  if (param_freq < 0) {
160  ROS_WARN("[ws281x] Target_frequency out of range, resetting to default");
161  led_string.freq = (uint32_t)WS2811_TARGET_FREQ;
162  } else {
163  led_string.freq = (uint32_t)param_freq;
164  }
165 
166  led_string.dmanum = param_dma;
167  led_string.channel[0].gpionum = param_pin;
168  led_string.channel[0].count = param_led_count;
169  led_string.channel[0].invert = param_invert ? (1) : (0);
170  led_string.channel[0].brightness = (uint8_t)param_brightness;
171  led_string.channel[0].strip_type = (int)param_strip_type;
172 
173  // Disable second channel for now
174  led_string.channel[1].gpionum = 0;
175  led_string.channel[1].count = 0;
176  led_string.channel[1].invert = 0;
177  led_string.channel[1].brightness = 0;
178 
179  ws2811_return_t ret;
180  if ((ret = ws2811_init(&led_string)) != WS2811_SUCCESS) {
181  ROS_FATAL("[ws281x] native library init failed: %s", ws2811_get_return_t_str(ret));
182  exit(1);
183  }
184  signal(SIGINT, cleanup);
185  signal(SIGTERM, cleanup);
186 
187  strip_state.leds.resize(param_led_count);
188 
189  auto srv_gamma = nh_priv.advertiseService("set_gamma", setGamma);
190  auto srv_leds = nh_priv.advertiseService("set_leds", setLeds);
191 
192  led_state_pub = nh_priv.advertise<led_msgs::LEDStateArray>("state", 1, true);
193  publishLedState();
194 
195  ros::spin();
196 
197  return 0;
198 }
#define WS2811_STRIP_BRG
Definition: ws2811.h:60
constexpr uint32_t LED_RED_MASK
Definition: ws281x_node.cpp:28
#define SK6812W_STRIP
Definition: ws2811.h:66
#define WS2811_STRIP_BGR
Definition: ws2811.h:61
ws2811_t led_string
Definition: ws281x_node.cpp:59
#define ROS_FATAL(...)
constexpr uint32_t LED_BLUE
Definition: ws281x_node.cpp:35
constexpr uint32_t LED_WHITE
Definition: ws281x_node.cpp:36
#define WS2811_STRIP_RBG
Definition: ws2811.h:57
constexpr uint32_t LED_BLUE_MASK
Definition: ws281x_node.cpp:30
constexpr uint32_t LED_GREEN
Definition: ws281x_node.cpp:34
constexpr uint32_t LED_BLUE_SHIFT
Definition: ws281x_node.cpp:25
constexpr uint32_t LED_WHITE_MASK
Definition: ws281x_node.cpp:31
#define WS2811_STRIP_GRB
Definition: ws2811.h:58
ws2811_channel_t channel[RPI_PWM_CHANNELS]
Definition: ws2811.h:93
#define SK6812_STRIP_GBRW
Definition: ws2811.h:50
constexpr uint32_t LED_GREEN_MASK
Definition: ws281x_node.cpp:29
#define SK6812_STRIP_RBGW
Definition: ws2811.h:48
ws2811_return_t
Definition: ws2811.h:116
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
#define SK6812_STRIP_BRGW
Definition: ws2811.h:51
constexpr uint32_t LED_RED_SHIFT
Definition: ws281x_node.cpp:23
#define SK6812_STRIP_GRBW
Definition: ws2811.h:49
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
#define WS2811_TARGET_FREQ
Definition: ws2811.h:44
#define ROS_WARN(...)
led_msgs::LEDStateArray strip_state
Definition: ws281x_node.cpp:62
int main(int argc, char **argv)
constexpr uint32_t LED_GREEN_SHIFT
Definition: ws281x_node.cpp:24
#define SK6812_STRIP_BGRW
Definition: ws2811.h:52
#define SK6812_STRIP
Definition: ws2811.h:65
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void publish(const boost::shared_ptr< M > &message) const
#define WS2812_STRIP
Definition: ws2811.h:64
ws2811_led_t * leds
Definition: ws2811.h:77
ws2811_return_t ws2811_init(ws2811_t *ws2811)
Definition: ws2811.c:894
#define ROS_ERROR_THROTTLE(period,...)
std::unordered_map< std::string, uint64_t > ws2811_types
Definition: ws281x_node.cpp:40
void publishLedState()
Definition: ws281x_node.cpp:64
ws2811_return_t ws2811_render(ws2811_t *ws2811)
Definition: ws2811.c:1138
uint32_t freq
Definition: ws2811.h:91
void cleanup(int signal)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ROSCPP_DECL void spin()
bool setLeds(led_msgs::SetLEDs::Request &req, led_msgs::SetLEDs::Response &resp)
Definition: ws281x_node.cpp:86
const char * ws2811_get_return_t_str(const ws2811_return_t state)
Definition: ws2811.c:1273
void ws2811_fini(ws2811_t *ws2811)
Definition: ws2811.c:1079
int strip_type
Definition: ws2811.h:76
uint8_t * gamma
Definition: ws2811.h:83
#define WS2811_STRIP_GBR
Definition: ws2811.h:59
constexpr uint32_t LED_WHITE_SHIFT
Definition: ws281x_node.cpp:26
#define SK6812_STRIP_RGBW
Definition: ws2811.h:47
constexpr uint32_t LED_RED
Definition: ws281x_node.cpp:33
ros::Publisher led_state_pub
Definition: ws281x_node.cpp:61
ROSCPP_DECL void shutdown()
int dmanum
Definition: ws2811.h:92
uint8_t brightness
Definition: ws2811.h:78
#define WS2811_STRIP_RGB
Definition: ws2811.h:56
#define ROS_ERROR(...)
bool setGamma(ws281x::SetGamma::Request &req, ws281x::SetGamma::Response &resp)
Definition: ws281x_node.cpp:77


ws281x
Author(s): Alexey Rogachevskiy , Oleg Kalachev
autogenerated on Wed Jun 15 2022 02:46:00