Tuesday, 22 October 2024

Setting up Author Attribution for Mastodon on a Blogger Blog

Mastodon, the open source/not owned by corporations social media platform recently added a feature called Author Attribution, which enables you to set up websites you own so that any link to one of your articles posted by anyone on Mastodon will show an author attribution link below it. This links the article to your Mastodon profile. Here is an example for a link posted to an article from this blog, as it appears on Mastodon.

That 'More from' link below it is the automatically generated Author Attribution link.

To set this up for your websites is a two step process. The first step is to add an author attribution meta tag to your website. This takes the following format:

<meta content='@drfootleg@fosstodon.org' name='fediverse:creator'/>

Of course you need to put your own Mastodon profile link in the content field, instead of my profile. 

As I host my blog on Blogger, I was not sure how I could put this custom meta tag into my blog site. Searching for information online took me to many posts all telling me about the support for meta content tags on Blogger. But these all pointed to the 'Search Description' meta tags section of the Blogger site settings page, and this does not allow you to set the name field (it just provides a way to add the text for the contents field of a description meta tag). So we have to get a little more hands on, which I found you can do by editing the HTML of your page theme.

Instead of 'Settings', you need to select 'Theme' in the left pane of the Blogger site editor page:


Then on the Theme page, look for the 'Customize' button at the top of the page, and select the downward pointing arrow on the end of this button:

This reveals a drop down menu where you can select the option to 'Edit HTML'. Choose this and you will be taken into the theme HTML editor. Up near the top of the HTML you can see the <head> tag. You insert <meta> tags below this. Here you can see the author attribution tag I inserted into my blog on line 6.


Insert your meta tag, and don't forget to click 'Save' on the toolbar. If you now view your blog, and press F12 in your browser to inspect the HTML of the site you should see the tag in your blog site HTML.

That's step 1 done. Now for step 2. This is where you allow your website to be used to generate author attribution links in Mastodon. Go into your Mastodon profile edit screen, and select the 'Verification' setting page. Scroll down past the 'Website Verification' settings (which hopefully you already used to tag your website as a way to verify yourself in the Fediverse?). Below this section you should see the 'Author Attribution' settings panel. Here you add the URLs of all the websites which you want to allow to be attributed to you on Mastodon. Without this part of the process, people could falsely attribute other websites to you. By requiring you to edit both your profile on Mastodon and the HTML of your websites, only you can control which websites are attributed to your Mastodon account. You can see my settings here:

As Blogger can use multiple URLs, I added the two most common ones my blog is accessed from here. Notice this page also shows you the syntax to use for your own meta tag, with a convenient 'copy' button.

That's all you need to do. Now when anyone posts a link to one of your blog articles on Mastodon, it should show an author attribution link below it automatically.








Thursday, 15 August 2024

Using a Game Controller with ROS2 in Docker

(NOTE: Since Pi OS moved from X11 to Wayland, the configurations in this post no longer work. I will update this as soon as I have finished testing and documenting a Wayland compatible configuration.)

Continuing our learning of ROS2 running in Docker containers on top of Raspberry Pi OS (see previous posts in this blog). ROS comes with joystick support in the form of the joy package. https://docs.ros.org/en/jazzy/p/joy/ 
To get this working inside Docker, we need to map our joystick input to our container. In the previous post, we created a Docker Compose configuration file which looked like this:

services:

    sim:

      image: ros_docker:latest

      command: ros2 run turtlesim turtlesim_node

      environment:

        DISPLAY:

        QT_X11_NO_MITSHM: 1

      volumes:

        - /tmp/.X11-unix:/tmp/.X11-unix:rw

    dev-build:

      image: ros_docker:latest

      command: rqt

      environment:

        DISPLAY:

        QT_X11_NO_MITSHM: 1

      volumes:

        - /tmp/.X11-unix:/tmp/.X11-unix:rw

        - ~/ros2_ws:/ros2_ws


Before we try mapping our controller, let’s check it is actually connected to the Raspberry Pi. We are using a bluetooth game controller here. This should work with a PS4 Dualshock Controller, an X-Box One S wireless controller, or an 8BitDo Pro2 controller (which can mimic various controllers). Start by pairing your controller through the Raspberry Pi OS bluetooth tray icon. Select ‘Add Device’, put the controller into pairing mode, wait for it to appear in the detected devices list and then select it and press ‘Pair’.

Once you have a controller connected, type the following command in a terminal:


ls /dev/input


You should see among the various event items, there is a 'js' item.

 

$ ls /dev/input  

by-id    event0  event2  event4  event6  event9  mice

by-path  event1  event3  event5  event7  js0     mouse0


In my case I saw js0 which indicates my game controller is available as an input device.


Now we can map our input devices into our docker container. I mapped all of them, so any input device becomes available. Add the following section to dev-build service section in the docker-compose.yml file:


      devices:

        - /dev/input:/dev/input


Now we have changed our docker-compose.yml file, we need to stop and restart our container. Docker Compose will detect the change, and destroy the old container and recreate it. So once it starts up again, we will need to source our ROS2 packages again (just once if we put the command into the bash.rc file again). Open a shell in the container:

docker exec -it jazzy-dev-build-1 bash


Then run following command from the shell:

echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc


Now exit the shell, and use docker exec to start a new one. You should be able to run ROS2 commands from the shell now. You can also confirm that the joystick input is available inside the container by using the command ‘ls /dev/input’ from the container shell prompt. If you can see the 'js' item then we are ready to use it in ROS.


First, we can use the joy package to list all the available joysticks:

ros2 run joy joy_enumerate_devices


This should list the game controller. There are some gotchas to be aware of here. I found that if my game controller was not connected to the host Pi over bluetooth before I started my container then it would not be detected inside the container after it was connected. So if the controller turns off/loses the connection, then it still appears in the input devices list under /dev/input but does not get detected by ROS. You have to restart the container after reconnecting the controller.


Once you have seen your controller in the list output by the joy_enumerate_devices node, you can start the joy node as follows:

ros2 run joy joy_node


Then in a new terminal, open another shell in your container and run the following to see the outputs from the controller:

ros2 topic echo /joy


This confirms the joy node is posting messages to the /joy topic which you can consume in ROS nodes which subscribe to this topic.


You can also monitor the joy topic in the rqt tool. Open the ‘Plugins/Topics’ menu and select the ‘Topic Monitor’. Tick the /joy topic and you should be able to see the values of the various game controller buttons and joysticks (hold them and wait a little as the refresh rate appears to be only once per second or so in the topic monitor).


Now this is all working, we can try and write a node to subscribe to the /joy topic and make use of the game controller input. We will start with the existing ros2-teleop_twist_joy package: https://index.ros.org/p/teleop_twist_joy/github-ros2-teleop_twist_joy/#jazzy 


We can initially run this directly on our ROS desktop container as it is installed there already. Run the command:

ros2 launch teleop_twist_joy teleop-launch.py


This worked without needing more specific configuration and detected my game controller. It launches the joy node, so you do not need to run that separately. The teleop_twist_joy node subscribes to the /joy topic, and converts the data received from the game controller to 'Twist' data which it publishes to the /cmd_vel topic. In a new shell, you can monitor the /cmd_vel topic:

ros2 topic echo /cmd_vel


The teleop twist node only sends messages when ‘button 8’ is pressed on the controller. This was the left trigger (L2) on my controller. I had to hold it down to see messages in the /cmd_vel topic. 


We can remap the topic name which teleop_twist_joy uses, by passing in a different topic via a command line parameter. So let’s set it up to use the /turtle1/cmd_vel topic:

ros2 launch teleop_twist_joy teleop-launch.py joy_vel:='turtle1/cmd_vel'


You should now be able to control the turtle1 in the turtlesim node, using the game controller. Hold down the enable button (L2 in the case of the default mapping) and the left joystick should be able to drive the turtle around.


Open another shell in the container, and run the command:

rqt_graph


This should open a window showing the node graph. Change the drop down selector to show ‘Nodes/Topics (all)’ and you should see the complete node and topics graph as follows.





Wednesday, 10 April 2024

Final Pi Wars 2024 Blog Entry

It is late in the evening the night before the blogging deadline. So this is my final pre-judging blog entry. I am on holiday in an apartment with no TV. So I had no way to connect my robot to a screen other than to try and get it onto a WiFi connection and VNC onto it from my son's laptop (which I am also using to write this last blog entry). Without a screen to plug into the robot, I decided to try an idea I had but never tested before. I changed the mobile hotspot name on my mobile phone to the same network SID and password as the Makespace network. I then booted up the robot and it connected as it already had the Makespace network set up from working on it there previously. Next I connected the laptop to my hotspot. I just needed to know the IP address the Pi had been allocated. I could not ping it using <robotname>.local so I had to guess the IP. I checked what IP the laptop had on the mobile hotspot, and as the Pi had connected before the laptop I guessed it might have an IP address one bit lower that the laptop. This proved to be the case, and I was able to VNC onto the Pi and work on my code! 

Mostly progress has been in diagnosing why none of my I2C devices were working. After much head scratching I found a note on the Pimoroni website that the silk screen for the 8x8 TOF sensor I was using was incorrect on early boards, and it actually should say x29. The same I2C address as my IMU is using! The IMU can be configured to use x28, but that needs a soldering iron which I don't have with me this week. But at least I could confirm both sensors work when only one is plugged in at a time. I can work with that.

Next I discovered the 8x8 sensor example in MicroPython uses Numpy which is not in the Pimoroni Motor2040 firmware. Ulab Numpy is in the firmware for their Unicorn boards, so I was able to test with that. But in the process of flashing the firmware this wiped the filesystem on the Motor2040 with all my code on it! Thankfully I back things up pretty often. I had all the files on the Pi SD Card, and was able to restore them all apart from one. I managed to download that from my NAS at home over the internet. So everything is back in place. Unfortunately the Unicorn firmware does not contain the motor and encoder classes I need. A cry for help to Pimoroni software expert Gadgetoid resulted in him building a custom MicroPython firmware build which includes the ulab Numpy modules. Now that is customer service! He warned me it will wipe my filesystem, but as I've already been there I am good to try it. Except I had a blog to finish, so I've not done any more coding yet. Plus I am here to relax, after all!



Sunday, 7 April 2024

My Robot is Hardware Complete!

 Finally I have everything assembled and wired up!



I realised my directly soldered wires were prone to snapping off the PCBs, and I needed headers to plug my servo motors into. Just having a pair of signal wires coming of the Motor2040 board was not going to cut it.


My solution was to design some additional brackets to bolt an I2C distribution board onto. A PCB I designed after Pi Wars 2019 but had never actually used on a robot until now.


This board has 4 pin sockets for I2C breakouts, along with some 5 pin sockets intended for the Pimoroni Breakout Garden boards which use a 5th pin for some other signal functions. This 5th pin for each of these sockets is connected to a header on my board. In a flash of inspiration I realised I could cut the power track to these 5 pin sockets, and by sacrificing 2 of these 5 pin outlets I could wire one of the spare 'signal' pins to V+ from the motor supply 6V line and one to GND. Then I could feed the servo supply voltage, GND and the RX and TX signals into this signal header and supply each of the remaining 5 pin sockets with high current power, GND and the signal line needed for the two servos. An extended custom lead crimping session saw the 2 servos converted to custom 5 pin JSH-PH plugs. A custom lead to supply the power and signal inputs to the board, and my servos were connected!

All that remained was to connect up the I2C input to the Motor2040 board and plug in my sensor and IMU and I was done. It was late in the evening the night before my week long family holiday and my robot was read to take away and maybe do some coding on in the evenings. Then the QWIIC socket broke off the Motor2040 board as I plugged in the final connector. I realised I it was too late to take everything apart again, and took the sensible option of going to bed to sleep on the problem.

In the morning, alongside final packing I managed to take apart the robot to remove the Motor2040 board. It has headers which can take a Breakout Garden socket (too large for the space I had) but also due to an extra GND pin on the header, could take a 4 pin JST-XH socket. Genius on the part of Pimoroni, or just good luck? Either way I was able to solder on a socket and crimp up one more custom lead and pack it all in my bag to take on holiday.


Monday, 1 April 2024

Pulling it all together!

 A few more late nights working to assemble my robot. Thankfully the CAD model went together pretty well, with just some minor filing of parts to make them fit together well. I used hot melt threaded inserts in several places which makes it very quick to assemble (and more importantly take apart) when things go wrong.


Here you can see the lower chassis with the Motor2040 board mounted at the front with the battery tray in the middle between the wheels (the battery slides into this). The UBEC sits on top of the middle battery and the USB-C battery pack is on the back, held in place with velcro straps.


The 3D printed Raspberry Pi 5 case sits on top, screwed onto a pair of bars. The screws come up from below and hold the case together, so need to be fitted before the bars are screwed down onto the robot. You can just see the Motor2040 board below the Pi here with an IMU plugged into the QWIIC socket. It was at this point that things started to go wrong. See the yellow wire which has snapped off the IMU board where I had soldered it straight to the PCB. Then I realised my Motor2040 board has no servo headers. I have nowhere to plug in the servos on my grabber!


Some frantic study of the Motor2040 board documentation and schematic revealed no broken out pins from the GPIO. There were some analogue inputs, but it turns out these are for a seperate ADC chip and not the RP2040. Then I spotted the UART pins labelled RX and TX on the board. Looking at the schematic these are directly connected to a pair of GPIOs on the RP2040, and I was not using them for serial communications as I am using the USB socket for that! I clipped my PicoScope probe ground to the USB plug (the only accessible GND point with my board mounted) and found a simple servo driving example for MicroPython. Setting the RX and TX pins as the 'servo outputs' in the example I was able to confirm the PWM output on these pins on the PicoScope. The day was saved!

Friday, 29 March 2024

3D Printing and Assembling my Robot

 Finally I have enough parts printed to start to assemble my final robot.


Some parts require supporting during the 3D printing process. I have an IDEX printer (Independent Dual EXtruder). This means it has 2 independent tool heads/hot-ends. They can each print a different material. So here I have printed my main part in PLA+, but used PETG for the support material. These different plastics do not stick together very strongly, so I can completely eliminate the vertical separation normally required to make supports removable. Above you can see the indented rectangles and the arch (this part was printed the other way up to how it is shown in the photo. The PLA+ is totally supported in these areas, and the PETG just snaps cleanly off (you can see the small PETG supporting parts behind on the desk).

Around 3 weeks to the competition and I have so much to do! I am away for a week around Easter too, so I have to turn this pile of parts into a working robot this week.


It isn't all advanced digital design and manufacturing. I cut these 'washers' out of plastic milk cartons as the polythene these are made of is really low friction. I put one of these between every pivot joint in the grabber so that the rougher surfaces of the 3D prints move smoothly over each other.

Monday, 25 March 2024

CAD Model Completed

After several late nights working on my CAD model I think I have everything done.


Learning from past mistakes, I included a sketch of the maximum allowed robot size. I also used this to label which motor sockets on the Motor2040 board each of my wheels is connected to, so that I reassemble it correctly when I disassemble my test chassis and rebuild it with the 3D printed parts from this new design. I reused the Pi 5 case design, but reprinted it in better quality in ABS. I added mounting space for a USB-C battery pack which after testing I was happy to confirm is capable of powering the Raspberry Pi 5 with no issue. The twin cell Li-Ion battery pack between the wheels powers the motors (via a 6V UBEC) so they get a constant voltage supply whatever the level of charge of the battery. Using separate batteries also ensures the motors don't cause brown outs for the Pi power supply when the going gets tough.

The whole CAD design is highly modular. This enables each part to be printed separately, reducing the time lost if a print fails or a part needs modifying and reprinting. It also allowed me to get parts printing while I was still working on the rest of the model, saving valuable time.